[一般更新] Flask8检查代码,套利模板,股票下载更新,天勤更新

This commit is contained in:
msincenselee 2020-10-10 14:14:53 +08:00
parent 74d156b3ae
commit b32ca3b9d5
30 changed files with 382 additions and 323 deletions

View File

@ -20,7 +20,7 @@ import baostock as bs
from vnpy.trader.constant import Exchange from vnpy.trader.constant import Exchange
from vnpy.data.tdx.tdx_common import get_tdx_market_code from vnpy.data.tdx.tdx_common import get_tdx_market_code
from vnpy.trader.utility import load_json, get_csv_last_dt, extract_vt_symbol from vnpy.trader.utility import load_json, get_csv_last_dt, extract_vt_symbol
from vnpy.data.stock.stock_base import get_stock_base from vnpy.data.stock.stock_base import update_stock_base, get_stock_base
# 保存的1分钟指数 bar目录 # 保存的1分钟指数 bar目录
bar_data_folder = os.path.abspath(os.path.join(vnpy_root, 'bar_data')) bar_data_folder = os.path.abspath(os.path.join(vnpy_root, 'bar_data'))
@ -34,6 +34,9 @@ if __name__ == "__main__":
if login_msg.error_code != '0': if login_msg.error_code != '0':
print(f'证券宝登录错误代码:{login_msg.error_code}, 错误信息:{login_msg.error_msg}') print(f'证券宝登录错误代码:{login_msg.error_code}, 错误信息:{login_msg.error_msg}')
print('更新股票基本信息')
update_stock_base()
symbol_dict = get_stock_base() symbol_dict = get_stock_base()
if len(sys.argv) >= 2 and sys.argv[1].lower() == 'all': if len(sys.argv) >= 2 and sys.argv[1].lower() == 'all':
stock_list = list(symbol_dict.keys()) stock_list = list(symbol_dict.keys())
@ -43,7 +46,6 @@ if __name__ == "__main__":
stock_list = load_json('stock_list.json') stock_list = load_json('stock_list.json')
print('读取本地stock_list.json文件{}'.format(len(stock_list))) print('读取本地stock_list.json文件{}'.format(len(stock_list)))
day_fields = "date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,isST" day_fields = "date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,isST"
min_fields = "date,time,code,open,high,low,close,volume,amount,adjustflag" min_fields = "date,time,code,open,high,low,close,volume,amount,adjustflag"
@ -74,7 +76,10 @@ if __name__ == "__main__":
exchange_name = '深交所' exchange_name = '深交所'
exchange_code = 'sz' exchange_code = 'sz'
symbol_info = symbol_dict.get(vt_symbol) symbol_info = symbol_dict.get(vt_symbol,None)
if symbol_info is None:
print(f'找不到{vt_symbol}得配置信息', file=sys.stderr)
continue
if symbol_info['类型'] == '指数': if symbol_info['类型'] == '指数':
continue continue
stock_name = symbol_info.get('name') stock_name = symbol_info.get('name')

View File

@ -1,4 +1,4 @@
six==1.13.0 six
PyQt5 PyQt5
pyqtgraph pyqtgraph
dataclasses; python_version<="3.6" dataclasses; python_version<="3.6"
@ -8,7 +8,7 @@ websocket-client
peewee peewee
mongoengine mongoengine
numpy numpy
pandas==0.25.2 pandas
matplotlib matplotlib
seaborn seaborn
futu-api futu-api

View File

@ -1945,7 +1945,7 @@ class BackTestingEngine(object):
self.daily_max_drawdown_rate = drawdown_rate self.daily_max_drawdown_rate = drawdown_rate
self.max_drawdown_rate_time = data['date'] self.max_drawdown_rate_time = data['date']
msg = u'{}: net={}, capital={} max={} margin={} commission={} pos: {}' \ msg = u'{}: net={}, capital={} max={} holding_profit={} commission={} pos: {}' \
.format(data['date'], .format(data['date'],
data['net'], c, m, data['net'], c, m,
today_holding_profit, today_holding_profit,

View File

@ -11,6 +11,7 @@ import sys
import os import os
import gc import gc
import pandas as pd import pandas as pd
import numpy as np
import traceback import traceback
import random import random
import bz2 import bz2
@ -425,7 +426,10 @@ class PortfolioTestingEngine(BackTestingEngine):
last_price=tick_data['price'], last_price=tick_data['price'],
volume=tick_data['volume'] volume=tick_data['volume']
) )
if not isinstance(tick.last_price,float):
continue
if np.isnan(tick.last_price):
continue
self.new_tick(tick) self.new_tick(tick)
# 结束一个交易日后,更新每日净值 # 结束一个交易日后,更新每日净值

View File

@ -11,6 +11,7 @@ import sys
import os import os
import gc import gc
import pandas as pd import pandas as pd
import numpy as np
import traceback import traceback
import bz2 import bz2
@ -426,6 +427,9 @@ class SpreadTestingEngine(BackTestingEngine):
bid_volume_1=int(tick_data['bid_volume_1']) bid_volume_1=int(tick_data['bid_volume_1'])
) )
if np.isnan(tick.ask_price_1) or np.isnan(tick.bid_price_1):
continue
self.new_tick(tick) self.new_tick(tick)
# 结束一个交易日后,更新每日净值 # 结束一个交易日后,更新每日净值

View File

@ -63,6 +63,12 @@ class CtaSpreadTemplate(CtaTemplate):
self.klines = {} # K线组件字典: kline_name: kline self.klines = {} # K线组件字典: kline_name: kline
self.cur_datetime = None # 当前Tick时间 self.cur_datetime = None # 当前Tick时间
self.cur_mi_tick = None # 最新的主力合约tick( vt_symbol)
self.cur_99_tick = None # 最新得指数合约tick( idx_symbol)
self.cur_mi_price = None # 当前价(主力合约 vt_symbol)
self.cur_99_price = None # 当前价tick时根据tick更新onBar回测时根据bar.close更新)
self.cur_act_tick = None # 最新的主动腿合约tick( act_vt_symbol) self.cur_act_tick = None # 最新的主动腿合约tick( act_vt_symbol)
self.cur_pas_tick = None # 最新得被动腿合约tick( pas_vt_symbol) self.cur_pas_tick = None # 最新得被动腿合约tick( pas_vt_symbol)
self.cur_spd_tick = None # 价差tick self.cur_spd_tick = None # 价差tick
@ -124,7 +130,6 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(u'保存k线缓存数据') self.write_log(u'保存k线缓存数据')
self.save_klines_to_cache() self.save_klines_to_cache()
def save_klines_to_cache(self, kline_names: list = []): def save_klines_to_cache(self, kline_names: list = []):
""" """
保存K线数据到缓存 保存K线数据到缓存
@ -748,8 +753,8 @@ class CtaSpreadTemplate(CtaTemplate):
grid.order_ids.remove(order.vt_orderid) grid.order_ids.remove(order.vt_orderid)
# 网格的所有委托单已经执行完毕 # 网格的所有委托单已经执行完毕
if len(grid.order_ids) == 0: #if len(grid.order_ids) == 0:
grid.order_status = False # grid.order_status = False
self.gt.save() self.gt.save()
self.write_log(u'网格信息更新:{}'.format(grid.__dict__)) self.write_log(u'网格信息更新:{}'.format(grid.__dict__))
@ -776,7 +781,7 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(f'{order_vt_symbol}涨停不做buy') self.write_log(f'{order_vt_symbol}涨停不做buy')
return return
# 发送委托 # FAK发送委托追单
vt_orderids = self.buy(price=buy_price, vt_orderids = self.buy(price=buy_price,
volume=order_volume, volume=order_volume,
vt_symbol=order_vt_symbol, vt_symbol=order_vt_symbol,
@ -855,8 +860,8 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(f'移除grid中order_ids:{order.vt_orderid}') self.write_log(f'移除grid中order_ids:{order.vt_orderid}')
grid.order_ids.remove(order.vt_orderid) grid.order_ids.remove(order.vt_orderid)
if not grid.order_ids: #if not grid.order_ids:
grid.order_status = False # grid.order_status = False
self.gt.save() self.gt.save()
self.active_orders.update({order.vt_orderid: old_order}) self.active_orders.update({order.vt_orderid: old_order})
@ -872,7 +877,7 @@ class CtaSpreadTemplate(CtaTemplate):
return return
if not self.trading: if not self.trading:
self.write_error(u'当前不允许交易') self.write_error(f'{self.cur_datetime} 当前不允许交易')
return return
# 直接更新“未完成委托单”更新volume,Retry次数 # 直接更新“未完成委托单”更新volume,Retry次数
@ -906,8 +911,8 @@ class CtaSpreadTemplate(CtaTemplate):
if order.vt_orderid in grid.order_ids: if order.vt_orderid in grid.order_ids:
self.write_log(f'移除grid中order_ids:{order.vt_orderid}') self.write_log(f'移除grid中order_ids:{order.vt_orderid}')
grid.order_ids.remove(order.vt_orderid) grid.order_ids.remove(order.vt_orderid)
if not grid.order_ids: #if not grid.order_ids:
grid.order_status = False # grid.order_status = False
self.gt.save() self.gt.save()
self.write_log(u'更新网格=>{}'.format(grid.__dict__)) self.write_log(u'更新网格=>{}'.format(grid.__dict__))
@ -1001,8 +1006,8 @@ class CtaSpreadTemplate(CtaTemplate):
if order.vt_orderid in grid.order_ids: if order.vt_orderid in grid.order_ids:
self.write_log(f'移除grid中order_ids:{order.vt_orderid}') self.write_log(f'移除grid中order_ids:{order.vt_orderid}')
grid.order_ids.remove(order.vt_orderid) grid.order_ids.remove(order.vt_orderid)
if len(grid.order_ids) == 0: #if len(grid.order_ids) == 0:
grid.order_status = False # grid.order_status = False
self.gt.save() self.gt.save()
self.active_orders.update({order.vt_orderid: old_order}) self.active_orders.update({order.vt_orderid: old_order})
@ -1047,15 +1052,17 @@ class CtaSpreadTemplate(CtaTemplate):
self.active_orders.update({vt_orderid: order_info}) self.active_orders.update({vt_orderid: order_info})
ret = self.cancel_order(str(vt_orderid)) ret = self.cancel_order(str(vt_orderid))
if not ret: if not ret:
self.write_log(u'撤单失败,更新状态为撤单成功') self.write_log(f'{vt_orderid}撤单失败,更新状态为撤单成功')
order_info.update({'status': Status.CANCELLED}) order_info.update({'status': Status.CANCELLED})
self.active_orders.update({vt_orderid: order_info}) self.active_orders.update({vt_orderid: order_info})
else: else:
self.write_log(f'{vt_orderid}撤单成功')
if order_grid: if order_grid:
if vt_orderid in order_grid.order_ids: if vt_orderid in order_grid.order_ids:
self.write_log(f'{vt_orderid}存在网格委托队列{order_grid.order_ids}中,移除')
order_grid.order_ids.remove(vt_orderid) order_grid.order_ids.remove(vt_orderid)
if len(order_grid.order_ids) == 0: #if len(order_grid.order_ids) == 0:
order_grid.order_status = False # order_grid.order_status = False
continue continue
# 处理状态为‘撤销’的委托单 # 处理状态为‘撤销’的委托单
@ -1234,10 +1241,10 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(u'停止状态,不开仓') self.write_log(u'停止状态,不开仓')
return [] return []
if not self.allow_trading_open: if not self.allow_trading_open:
self.write_log(u'不允许开仓') self.write_log(f'{self.cur_datetime}不允许开仓')
return [] return []
if self.force_trading_close: if self.force_trading_close:
self.write_log(u'强制平仓日,不开仓') self.write_log(f'{self.cur_datetime}强制平仓日,不开仓')
return [] return []
# 检查流动性缺失 # 检查流动性缺失
if not self.check_liquidity( direction=Direction.SHORT, if not self.check_liquidity( direction=Direction.SHORT,
@ -1266,7 +1273,7 @@ class CtaSpreadTemplate(CtaTemplate):
f'委托价:{self.cur_act_tick.bid_price_1}') f'委托价:{self.cur_act_tick.bid_price_1}')
return [] return []
# 开多被动腿 # 开多被动腿FAK或者限价单
pas_vt_orderids = self.buy(vt_symbol=self.pas_vt_symbol, pas_vt_orderids = self.buy(vt_symbol=self.pas_vt_symbol,
lock=self.pas_exchange==Exchange.CFFEX, lock=self.pas_exchange==Exchange.CFFEX,
price=self.cur_pas_tick.ask_price_1, price=self.cur_pas_tick.ask_price_1,
@ -1303,10 +1310,10 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(u'停止状态,不开仓') self.write_log(u'停止状态,不开仓')
return [] return []
if not self.allow_trading_open: if not self.allow_trading_open:
self.write_log(u'不允许开仓') self.write_log(f'{self.cur_datetime}不允许开仓')
return [] return []
if self.force_trading_close: if self.force_trading_close:
self.write_log(u'强制平仓日,不开仓') self.write_log(f'{self.cur_datetime}强制平仓日,不开仓')
return [] return []
# 检查流动性缺失 # 检查流动性缺失
if not self.check_liquidity( if not self.check_liquidity(
@ -1324,7 +1331,7 @@ class CtaSpreadTemplate(CtaTemplate):
self.write_log(u'价差{}不满足:{}'.format(self.cur_spd_tick.bid_price_1, grid.open_price)) self.write_log(u'价差{}不满足:{}'.format(self.cur_spd_tick.bid_price_1, grid.open_price))
return [] return []
# 开多主动腿 # 开多主动腿FAK 或者限价单)
act_vt_orderids = self.buy(vt_symbol=self.act_vt_symbol, act_vt_orderids = self.buy(vt_symbol=self.act_vt_symbol,
lock=self.act_exchange==Exchange.CFFEX, lock=self.act_exchange==Exchange.CFFEX,
price=self.cur_act_tick.ask_price_1, price=self.cur_act_tick.ask_price_1,

View File

@ -300,6 +300,7 @@ class StrategyManager(QtWidgets.QFrame):
tns_csv = os.path.abspath(os.path.join(self.cta_engine.get_data_path(), f'{self.strategy_name}_tns.csv')) tns_csv = os.path.abspath(os.path.join(self.cta_engine.get_data_path(), f'{self.strategy_name}_tns.csv'))
ui_snapshot.show(snapshot_file="", d=snapshot, trade_file=trade_csv, tns_file=tns_csv) ui_snapshot.show(snapshot_file="", d=snapshot, trade_file=trade_csv, tns_file=tns_csv)
class DataMonitor(QtWidgets.QTableWidget): class DataMonitor(QtWidgets.QTableWidget):
""" """
Table monitor for parameters and variables. Table monitor for parameters and variables.
@ -477,7 +478,7 @@ class SettingEditor(QtWidgets.QDialog):
try: try:
value = type_(value_text) value = type_(value_text)
except Exception as ex: except Exception as ex:
print(f'{name}数据类型转换未指定') print(f'{name}数据类型转换未指定:{str(ex)}')
if isnumber(value_text): if isnumber(value_text):
value = float(value_text) value = float(value_text)
elif value_text == 'None': elif value_text == 'None':
@ -489,6 +490,7 @@ class SettingEditor(QtWidgets.QDialog):
return setting return setting
def isnumber(aString): def isnumber(aString):
try: try:
float(aString) float(aString)

View File

@ -40,7 +40,6 @@ class RiskManager(QtWidgets.QDialog):
self.trade_hold_active_limit_spin = RiskManagerSpinBox() self.trade_hold_active_limit_spin = RiskManagerSpinBox()
self.trade_hold_percent_limit_spin = RiskManagerSpinBox() self.trade_hold_percent_limit_spin = RiskManagerSpinBox()
save_button = QtWidgets.QPushButton("保存") save_button = QtWidgets.QPushButton("保存")
save_button.clicked.connect(self.save_setting) save_button.clicked.connect(self.save_setting)
@ -57,7 +56,7 @@ class RiskManager(QtWidgets.QDialog):
form.addRow("激活废单/撤单(笔)", self.ratio_active_limit_spin) form.addRow("激活废单/撤单(笔)", self.ratio_active_limit_spin)
form.addRow("废单比上限(%)", self.reject_limit_percent_spin) form.addRow("废单比上限(%)", self.reject_limit_percent_spin)
form.addRow("撤单比上限(%)", self.cancel_limit_percent_spin) form.addRow("撤单比上限(%)", self.cancel_limit_percent_spin)
form.addRow("激活成交/持仓比阈值(笔)" ,self.trade_hold_active_limit_spin) form.addRow("激活成交/持仓比阈值(笔)", self.trade_hold_active_limit_spin)
form.addRow("成交/持仓比上限(%)", self.trade_hold_percent_limit_spin) form.addRow("成交/持仓比上限(%)", self.trade_hold_percent_limit_spin)
form.addRow(save_button) form.addRow(save_button)

View File

@ -5,3 +5,5 @@ HEIGHT_LIST = [3, 5, 10, 'K3', 'K5', 'K10']
FUTURE_RENKO_DB_NAME = 'FutureRenko' FUTURE_RENKO_DB_NAME = 'FutureRenko'
STOCK_RENKO_DB_NAME = 'StockRenko' STOCK_RENKO_DB_NAME = 'StockRenko'
CRYPTO_RENKO_DB_NAME= 'CryptoRenko'

View File

@ -26,6 +26,17 @@ stock_type_map = {
} }
STOCK_BASE_FILE = 'stock_base.pkb2' STOCK_BASE_FILE = 'stock_base.pkb2'
# get_stock_base 返回数据格式
# vt_symbol: {
# 'exchange': 交易所代码
# 'code': 股票代码
# 'name': 中文名
# 'ipo_date': 上市日期
# 'out_date': 退市日期
# '类型': 股票,指数,其他
# 'type': stock_cn, index_cn,etf_cn,bond_cn,cb_cn
# 'status': '上市' '退市'
# }
def get_stock_base(): def get_stock_base():
""" 获取股票基础信息""" """ 获取股票基础信息"""

View File

@ -46,7 +46,6 @@ NUM_MINUTE_MAPPING['1day'] = 60 * 5.5 # 股票收盘时间是1500
# 常量 # 常量
QSIZE = 800 QSIZE = 800
# 通达信 <=> 交易所代码 映射 # 通达信 <=> 交易所代码 映射
TDX_VN_STOCK_MARKET_MAP = { TDX_VN_STOCK_MARKET_MAP = {
TDXParams.MARKET_SH: Exchange.SSE, # 1: 上交所 TDXParams.MARKET_SH: Exchange.SSE, # 1: 上交所
@ -76,7 +75,7 @@ class TdxStockData(object):
self.proxy_ip = proxy_ip self.proxy_ip = proxy_ip
self.proxy_port = proxy_port self.proxy_port = proxy_port
if self.proxy_port == 0 and len(self.proxy_ip)==0: if self.proxy_port == 0 and len(self.proxy_ip) == 0:
proxy_config = get_cache_json(TDX_PROXY_CONFIG) proxy_config = get_cache_json(TDX_PROXY_CONFIG)
proxy_ip = proxy_config.get('proxy_ip', '') proxy_ip = proxy_config.get('proxy_ip', '')
proxy_port = proxy_config.get('proxy_port', 0) proxy_port = proxy_config.get('proxy_port', 0)
@ -388,16 +387,16 @@ class TdxStockData(object):
cache_date: str): cache_date: str):
"""加载缓存数据""" """加载缓存数据"""
if not os.path.exists(cache_folder): if not os.path.exists(cache_folder):
#self.write_error('缓存目录:{}不存在,不能读取'.format(cache_folder)) # self.write_error('缓存目录:{}不存在,不能读取'.format(cache_folder))
return None return None
cache_folder_year_month = os.path.join(cache_folder, cache_date[:6]) cache_folder_year_month = os.path.join(cache_folder, cache_date[:6])
if not os.path.exists(cache_folder_year_month): if not os.path.exists(cache_folder_year_month):
#self.write_error('缓存目录:{}不存在,不能读取'.format(cache_folder_year_month)) # self.write_error('缓存目录:{}不存在,不能读取'.format(cache_folder_year_month))
return None return None
cache_file = os.path.join(cache_folder_year_month, '{}_{}.pkb2'.format(cache_symbol, cache_date)) cache_file = os.path.join(cache_folder_year_month, '{}_{}.pkb2'.format(cache_symbol, cache_date))
if not os.path.isfile(cache_file): if not os.path.isfile(cache_file):
#self.write_error('缓存文件:{}不存在,不能读取'.format(cache_file)) # self.write_error('缓存文件:{}不存在,不能读取'.format(cache_file))
return None return None
with bz2.BZ2File(cache_file, 'rb') as f: with bz2.BZ2File(cache_file, 'rb') as f:
data = pickle.load(f) data = pickle.load(f)
@ -531,8 +530,10 @@ class TdxStockData(object):
self.connect() self.connect()
data = pd.concat( data = pd.concat(
[pd.concat([self.api.to_df(self.api.get_security_list(j, i * 1000)).assign(sse='sz' if j == 0 else 'sh').set_index( [pd.concat(
['code', 'sse'], drop=False) for i in range(int(self.api.get_security_count(j) / 1000) + 1)], axis=0) for j [self.api.to_df(self.api.get_security_list(j, i * 1000)).assign(sse='sz' if j == 0 else 'sh').set_index(
['code', 'sse'], drop=False) for i in range(int(self.api.get_security_count(j) / 1000) + 1)],
axis=0) for j
in range(2)], axis=0) in range(2)], axis=0)
sz = data.query('sse=="sz"') sz = data.query('sse=="sz"')
sh = data.query('sse=="sh"') sh = data.query('sse=="sh"')
@ -575,12 +576,13 @@ class TdxStockData(object):
def get_stock_quotes_by_type(self, stock_type): def get_stock_quotes_by_type(self, stock_type):
"""根据股票代码类型,获取其最新行情""" """根据股票代码类型,获取其最新行情"""
stock_list = [(stock.get('market_id'), stock.get('code')) for stock in self.symbol_dict.values() if stock.get('stock_type') == stock_type] stock_list = [(stock.get('market_id'), stock.get('code')) for stock in self.symbol_dict.values() if
stock.get('stock_type') == stock_type]
num_per_count = 60 num_per_count = 60
results = [] results = []
for i in range(0, len(stock_list)+1, num_per_count): for i in range(0, len(stock_list) + 1, num_per_count):
cur_results = self.get_security_quotes(stock_list[i:i+num_per_count]) cur_results = self.get_security_quotes(stock_list[i:i + num_per_count])
results.extend(cur_results) results.extend(cur_results)
return results return results

View File

@ -18,12 +18,12 @@ t2 = FakeStrategy()
api_01 = TdxFutureData(strategy=t1) api_01 = TdxFutureData(strategy=t1)
# 获取所有市场信息 # 获取所有市场信息
markets = api_01.get_markets() #markets = api_01.get_markets()
str_markets = json.dumps(markets, indent=1, ensure_ascii=False) #str_markets = json.dumps(markets, indent=1, ensure_ascii=False)
print(u'{}'.format(str_markets)) #print(u'{}'.format(str_markets))
# 获取所有的期货合约明细 # 获取所有的期货合约明细
api_01.qry_instrument() #api_01.qry_instrument()
# 获取某个合约得最新价 # 获取某个合约得最新价
#price = api_01.get_price('rb2010') #price = api_01.get_price('rb2010')
@ -64,8 +64,8 @@ corr_rate = round(abs(corr.iloc[0, 1]) * 100, 2)
# api_01.get_bars('IF99', period='1min', callback=t1.display_bar, bar_freq=1) # api_01.get_bars('IF99', period='1min', callback=t1.display_bar, bar_freq=1)
# 获取bar只返回 list[dict] # 获取bar只返回 list[dict]
"""
result, bars = api_01.get_bars('IF99', period='1min', return_bar=False) result, bars = api_01.get_bars('SA2101', period='1min', return_bar=False)
if result: if result:
print('前十根bar') print('前十根bar')
for bar in bars[0:10]: for bar in bars[0:10]:
@ -73,15 +73,15 @@ if result:
print('后十根bar') print('后十根bar')
for bar in bars[-10:]: for bar in bars[-10:]:
print(bar) print(bar)
"""
# result,datas = api_01.get_transaction_data(symbol='ni1905') # result,datas = api_01.get_transaction_data(symbol='ni1905')
# api_02 = TdxFutureData(t2) # api_02 = TdxFutureData(t2)
# api_02.get_bars('IF99', period='1min', callback=t1.display_bar) # api_02.get_bars('IF99', period='1min', callback=t1.display_bar)
# 获取当前交易日分时数据 # 获取当前交易日分时数据
ret,result = api_01.get_transaction_data('NI99') #ret,result = api_01.get_transaction_data('NI99')
for r in result[0:10] + result[-10:]: #for r in result[0:10] + result[-10:]:
print(r) # print(r)
# 获取历史分时数据 # 获取历史分时数据
# ret, result = api_01.get_history_transaction_data('RB99', '20190109') # ret, result = api_01.get_history_transaction_data('RB99', '20190109')

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
#__author__ = 'yangyang' # __author__ = 'yangyang'
# 修改: # 修改:
# 1 输入单个合约时,标题不再扩展为 合约.标题 # 1 输入单个合约时,标题不再扩展为 合约.标题
# 2. 下载tick时5档行情都下载 # 2. 下载tick时5档行情都下载
@ -74,11 +74,13 @@ class DataDownloader:
if isinstance(start_dt, datetime): if isinstance(start_dt, datetime):
self._start_dt_nano = int(start_dt.timestamp() * 1e9) self._start_dt_nano = int(start_dt.timestamp() * 1e9)
else: else:
self._start_dt_nano = _get_trading_day_start_time(int(datetime(start_dt.year, start_dt.month, start_dt.day).timestamp()) * 1000000000) self._start_dt_nano = _get_trading_day_start_time(
int(datetime(start_dt.year, start_dt.month, start_dt.day).timestamp()) * 1000000000)
if isinstance(end_dt, datetime): if isinstance(end_dt, datetime):
self._end_dt_nano = int(end_dt.timestamp() * 1e9) self._end_dt_nano = int(end_dt.timestamp() * 1e9)
else: else:
self._end_dt_nano = _get_trading_day_end_time(int(datetime(end_dt.year, end_dt.month, end_dt.day).timestamp()) * 1000000000) self._end_dt_nano = _get_trading_day_end_time(
int(datetime(end_dt.year, end_dt.month, end_dt.day).timestamp()) * 1000000000)
self._current_dt_nano = self._start_dt_nano self._current_dt_nano = self._start_dt_nano
self._symbol_list = symbol_list if isinstance(symbol_list, list) else [symbol_list] self._symbol_list = symbol_list if isinstance(symbol_list, list) else [symbol_list]
# 检查合约代码是否存在 # 检查合约代码是否存在
@ -121,7 +123,7 @@ class DataDownloader:
"focus_datetime": self._start_dt_nano, "focus_datetime": self._start_dt_nano,
"focus_position": 0, "focus_position": 0,
} }
if len(self._symbol_list) ==1: if len(self._symbol_list) == 1:
single_exchange, single_symbol = self._symbol_list[0].split('.') single_exchange, single_symbol = self._symbol_list[0].split('.')
else: else:
single_exchange, single_symbol = None, None single_exchange, single_symbol = None, None
@ -132,7 +134,7 @@ class DataDownloader:
csv_header = [] csv_header = []
data_cols = ["open", "high", "low", "close", "volume", "open_oi", "close_oi"] if self._dur_nano != 0 else \ data_cols = ["open", "high", "low", "close", "volume", "open_oi", "close_oi"] if self._dur_nano != 0 else \
["last_price", "highest", "lowest", "volume", ["last_price", "highest", "lowest", "volume",
"amount", "open_interest","upper_limit","lower_limit", "amount", "open_interest", "upper_limit", "lower_limit",
"bid_price1", "bid_volume1", "ask_price1", "ask_volume1", "bid_price1", "bid_volume1", "ask_price1", "ask_volume1",
"bid_price2", "bid_volume2", "ask_price2", "ask_volume2", "bid_price2", "bid_volume2", "ask_price2", "ask_volume2",
"bid_price3", "bid_volume3", "ask_price3", "ask_volume3", "bid_price3", "bid_volume3", "ask_price3", "ask_volume3",

View File

@ -28,15 +28,16 @@ import csv
# pd.pandas.reset_option(‘参数名’, 参数值) # 恢复默认相关选项 # pd.pandas.reset_option(‘参数名’, 参数值) # 恢复默认相关选项
tick_csv_header = [ tick_csv_header = [
"datetime","symbol", "exchange", "last_price","highest","lowest","volume","amount","open_interest", "datetime", "symbol", "exchange", "last_price", "highest", "lowest", "volume", "amount", "open_interest",
"upper_limit","lower_limit","bid_price1","bid_volume1","ask_price1", "upper_limit", "lower_limit", "bid_price1", "bid_volume1", "ask_price1",
"ask_volume1","bid_price2","bid_volume2","ask_price2","ask_volume2", "ask_volume1", "bid_price2", "bid_volume2", "ask_price2", "ask_volume2",
"bid_price3","bid_volume3","ask_price3","ask_volume3","bid_price4", "bid_price3", "bid_volume3", "ask_price3", "ask_volume3", "bid_price4",
"bid_volume4", "bid_volume4",
"ask_price4","ask_volume4", "ask_price4", "ask_volume4",
"bid_price5","bid_volume5","ask_price5","ask_volume5" "bid_price5", "bid_volume5", "ask_price5", "ask_volume5"
] ]
@lru_cache(maxsize=9999) @lru_cache(maxsize=9999)
def to_vt_symbol(tq_symbol: str) -> str: def to_vt_symbol(tq_symbol: str) -> str:
"""""" """"""
@ -95,8 +96,8 @@ def generate_tick_from_dict(vt_symbol: str, data: dict) -> TickData:
volume=int(data["volume"]), volume=int(data["volume"]),
open_interest=data["open_interest"], open_interest=data["open_interest"],
last_price=float(data["last_price"]), last_price=float(data["last_price"]),
#limit_up=float(data["upper_limit"]) if data["upper_limit"] !='#N/A' else None, # limit_up=float(data["upper_limit"]) if data["upper_limit"] !='#N/A' else None,
#limit_down=float(data["lower_limit"]), # limit_down=float(data["lower_limit"]),
high_price=float(data["highest"]), high_price=float(data["highest"]),
low_price=float(data["lowest"]), low_price=float(data["lowest"]),
bid_price_1=float(data["bid_price1"]), bid_price_1=float(data["bid_price1"]),
@ -182,7 +183,7 @@ class TqFutureData():
with open(file=ticks_file, mode='r', encoding='utf-8', ) as f: with open(file=ticks_file, mode='r', encoding='utf-8', ) as f:
reader = csv.DictReader(f=f, fieldnames=tick_csv_header, delimiter=",") reader = csv.DictReader(f=f, fieldnames=tick_csv_header, delimiter=",")
for row in reader: for row in reader:
if str(row.get('last_price','nan')) not in['nan','last_price']: if str(row.get('last_price', 'nan')) not in ['nan', 'last_price']:
tick_dict_list.append(row) tick_dict_list.append(row)
return tick_dict_list return tick_dict_list
@ -191,7 +192,7 @@ class TqFutureData():
return [] return []
def get_bars(self, vt_symbol: str, start_date: datetime=None, end_date: datetime = None): def get_bars(self, vt_symbol: str, start_date: datetime = None, end_date: datetime = None):
""" """
获取历史bar受限于最大长度8964根bar 获取历史bar受限于最大长度8964根bar
:param vt_symbol: :param vt_symbol:
@ -235,7 +236,6 @@ class TqFutureData():
return bars return bars
def get_ticks(self, vt_symbol: str, start_date: datetime, end_date: datetime = None): def get_ticks(self, vt_symbol: str, start_date: datetime, end_date: datetime = None):
"""获取历史tick""" """获取历史tick"""
@ -253,7 +253,7 @@ class TqFutureData():
all_ticks = [] all_ticks = []
# 轮询每一天,读取缓存数据 # 轮询每一天,读取缓存数据
for n in range(n_days+1): for n in range(n_days + 1):
trading_date = start_date + timedelta(days=n) trading_date = start_date + timedelta(days=n)
if trading_date.isoweekday() in [6, 7]: if trading_date.isoweekday() in [6, 7]:
continue continue
@ -272,7 +272,7 @@ class TqFutureData():
all_ticks.extend(rt_ticks) all_ticks.extend(rt_ticks)
return all_ticks return all_ticks
def get_runtime_ticks(self, vt_symbol: str, begin_dt: datetime= None): def get_runtime_ticks(self, vt_symbol: str, begin_dt: datetime = None):
"""获取实时历史tick""" """获取实时历史tick"""
self.write_log(f"从天勤请求合约:{vt_symbol}的实时的8964条tick数据") self.write_log(f"从天勤请求合约:{vt_symbol}的实时的8964条tick数据")
symbol, exchange = extract_vt_symbol(vt_symbol) symbol, exchange = extract_vt_symbol(vt_symbol)
@ -290,7 +290,7 @@ class TqFutureData():
'bid_volume13', 'ask_price4', 'ask_volume14', 'bid_price4', 'bid_volume14', 'bid_volume13', 'ask_price4', 'ask_volume14', 'bid_price4', 'bid_volume14',
'ask_price5', 'ask_volume15', 'bid_price5', 'bid_volume15', 'volume', 'amount', 'ask_price5', 'ask_volume15', 'bid_price5', 'bid_volume15', 'volume', 'amount',
'open_interest', 'symbol', 'duration'] 'open_interest', 'symbol', 'duration']
df.drop(['id','average','duration'], axis=1) df.drop(['id', 'average', 'duration'], axis=1)
for index, row in df.iterrows(): for index, row in df.iterrows():
# 日期时间, 成交价, 成交量, 总量, 属性(持仓增减), B1价, B1量, B2价, B2量, B3价, B3量, S1价, S1量, S2价, S2量, S3价, S3量, BS # 日期时间, 成交价, 成交量, 总量, 属性(持仓增减), B1价, B1量, B2价, B2量, B3价, B3量, S1价, S1量, S2价, S2量, S3价, S3量, BS
@ -341,18 +341,14 @@ if __name__ == '__main__':
# tqsdk = Query_tqsdk_data(strategy=self) # 在策略中使用 # tqsdk = Query_tqsdk_data(strategy=self) # 在策略中使用
tqsdk = TqFutureData() tqsdk = TqFutureData()
# ticks = tqsdk.query_tick_current("pp2009.DCE") # ticks = tqsdk.query_tick_current("pp2009.DCE")
#tick_df = tqsdk.query_tick_history_data(vt_symbol="ni2009.SHFE", start_date=pd.to_datetime("2020-07-22")) # tick_df = tqsdk.query_tick_history_data(vt_symbol="ni2009.SHFE", start_date=pd.to_datetime("2020-07-22"))
#print(tick_df) # print(tick_df)
#ticks = tqsdk.get_runtime_ticks("ni2009.SHFE") # ticks = tqsdk.get_runtime_ticks("ni2009.SHFE")
#print(ticks[0]) # print(ticks[0])
#print(ticks[-1]) # print(ticks[-1])
bars = tqsdk.get_bars(vt_symbol='ni2011.SHFE') bars = tqsdk.get_bars(vt_symbol='ni2011.SHFE')
print(bars[0]) print(bars[0])
print(bars[-1]) print(bars[-1])

View File

@ -573,7 +573,7 @@ class BinancefRestApi(RestClient):
self.cache_position_symbols.update({position.symbol: position.volume}) self.cache_position_symbols.update({position.symbol: position.volume})
self.gateway.on_position(position) self.gateway.on_position(position)
#if position.symbol == 'BTCUSDT': # if position.symbol == 'BTCUSDT':
# self.gateway.write_log(f'{position.__dict__}\n {d}') # self.gateway.write_log(f'{position.__dict__}\n {d}')
# self.gateway.write_log("持仓信息查询成功") # self.gateway.write_log("持仓信息查询成功")

View File

@ -180,6 +180,7 @@ TQ2VT_TYPE = {
"OPTION": Product.OPTION, "OPTION": Product.OPTION,
} }
@lru_cache(maxsize=9999) @lru_cache(maxsize=9999)
def vt_to_tq_symbol(symbol: str, exchange: Exchange) -> str: def vt_to_tq_symbol(symbol: str, exchange: Exchange) -> str:
""" """
@ -432,12 +433,12 @@ class CtpGateway(BaseGateway):
self.write_log(f'使用RabbitMQ接口订阅{req.symbol}') self.write_log(f'使用RabbitMQ接口订阅{req.symbol}')
self.rabbit_api.subscribe(req) self.rabbit_api.subscribe(req)
elif self.tq_api: elif self.tq_api:
self.write_log(f'使用天勤接口订阅{ req.symbol}') self.write_log(f'使用天勤接口订阅{req.symbol}')
self.tq_api.subscribe(req) self.tq_api.subscribe(req)
else: else:
# 上期所、上能源支持五档行情,使用天勤接口 # 上期所、上能源支持五档行情,使用天勤接口
if self.tq_api and req.exchange in [Exchange.SHFE, Exchange.INE]: if self.tq_api and req.exchange in [Exchange.SHFE, Exchange.INE]:
self.write_log(f'使用天勤接口订阅{ req.symbol}') self.write_log(f'使用天勤接口订阅{req.symbol}')
self.tq_api.subscribe(req) self.tq_api.subscribe(req)
else: else:
self.write_log(f'使用CTP接口订阅{req.symbol}') self.write_log(f'使用CTP接口订阅{req.symbol}')
@ -544,6 +545,7 @@ class CtpGateway(BaseGateway):
tick = copy(tick) tick = copy(tick)
combiner.on_tick(tick) combiner.on_tick(tick)
class CtpMdApi(MdApi): class CtpMdApi(MdApi):
"""""" """"""
@ -652,7 +654,7 @@ class CtpMdApi(MdApi):
# 处理一下标准套利合约的last_price # 处理一下标准套利合约的last_price
if '&' in symbol: if '&' in symbol:
tick.last_price = (tick.ask_price_1 + tick.bid_price_1)/2 tick.last_price = (tick.ask_price_1 + tick.bid_price_1) / 2
if data["BidVolume2"] or data["AskVolume2"]: if data["BidVolume2"] or data["AskVolume2"]:
tick.bid_price_2 = adjust_price(data["BidPrice2"]) tick.bid_price_2 = adjust_price(data["BidPrice2"])
@ -846,7 +848,7 @@ class CtpTdApi(TdApi):
) )
self.gateway.on_order(order) self.gateway.on_order(order)
#self.gateway.write_error("交易委托失败", error) # self.gateway.write_error("交易委托失败", error)
def onRspOrderAction(self, data: dict, error: dict, reqid: int, last: bool): def onRspOrderAction(self, data: dict, error: dict, reqid: int, last: bool):
"""""" """"""
@ -965,7 +967,7 @@ class CtpTdApi(TdApi):
"""""" """"""
if "AccountID" not in data: if "AccountID" not in data:
return return
if len(self.accountid)== 0: if len(self.accountid) == 0:
self.accountid = data['AccountID'] self.accountid = data['AccountID']
balance = float(data["Balance"]) balance = float(data["Balance"])
@ -984,8 +986,11 @@ class CtpTdApi(TdApi):
account.available = round(float(data["Available"]), 7) account.available = round(float(data["Available"]), 7)
account.commission = round(float(data['Commission']), 7) account.commission = round(float(data['Commission']), 7)
account.margin = round(float(data['CurrMargin']), 7) account.margin = round(float(data['CurrMargin']), 7)
account.close_profit = round(float(data['CloseProfit']), 7) account.close_profit = round(float(data['CloseProfit']), 7) + round(
account.holding_profit = round(float(data['PositionProfit']), 7) float(data.get("SpecProductCloseProfit", 0)), 7)
account.holding_profit = round(float(data['PositionProfit']), 7) + round(
float(data.get("SpecProductPositionProfit", 0)), 7) + round(
float(data.get("SpecProductPositionProfitByAlg", 0)), 7)
account.trading_day = str(data['TradingDay']) account.trading_day = str(data['TradingDay'])
if '-' not in account.trading_day and len(account.trading_day) == 8: if '-' not in account.trading_day and len(account.trading_day) == 8:
account.trading_day = '-'.join( account.trading_day = '-'.join(
@ -1014,7 +1019,7 @@ class CtpTdApi(TdApi):
gateway_name=self.gateway_name gateway_name=self.gateway_name
) )
# 保证金费率(期权合约的保证金比例数值可能不对所以设置个0.2的最大值) # 保证金费率(期权合约的保证金比例数值可能不对所以设置个0.2的最大值)
contract.margin_rate = min(0.2,max(data.get('LongMarginRatio', 0), data.get('ShortMarginRatio', 0))) contract.margin_rate = min(0.2, max(data.get('LongMarginRatio', 0), data.get('ShortMarginRatio', 0)))
if contract.margin_rate == 0: if contract.margin_rate == 0:
contract.margin_rate = 0.1 contract.margin_rate = 0.1
@ -1153,7 +1158,7 @@ class CtpTdApi(TdApi):
exchange=exchange, exchange=exchange,
orderid=orderid, orderid=orderid,
sys_orderid=data.get("OrderSysID", orderid), sys_orderid=data.get("OrderSysID", orderid),
tradeid=tradeid.replace(' ',''), tradeid=tradeid.replace(' ', ''),
direction=DIRECTION_CTP2VT[data["Direction"]], direction=DIRECTION_CTP2VT[data["Direction"]],
offset=OFFSET_CTP2VT[data["OffsetFlag"]], offset=OFFSET_CTP2VT[data["OffsetFlag"]],
price=data["Price"], price=data["Price"],
@ -1789,7 +1794,7 @@ class SubMdApi():
"""转换dict vnpy1 tick dict => vnpy2 tick dict""" """转换dict vnpy1 tick dict => vnpy2 tick dict"""
if 'vtSymbol' not in d: if 'vtSymbol' not in d:
return d return d
symbol= d.get('symbol') symbol = d.get('symbol')
exchange = d.get('exchange') exchange = d.get('exchange')
vtSymbol = d.pop('vtSymbol', symbol) vtSymbol = d.pop('vtSymbol', symbol)
if '.' not in symbol: if '.' not in symbol:
@ -1798,14 +1803,13 @@ class SubMdApi():
d.update({'vt_symbol': f'{symbol}.{Exchange.LOCAL.value}'}) d.update({'vt_symbol': f'{symbol}.{Exchange.LOCAL.value}'})
# 成交数据 # 成交数据
d.update({'last_price': d.pop('lastPrice',0.0)}) # 最新成交价 d.update({'last_price': d.pop('lastPrice', 0.0)}) # 最新成交价
d.update({'last_volume': d.pop('lastVolume', 0)}) # 最新成交量 d.update({'last_volume': d.pop('lastVolume', 0)}) # 最新成交量
d.update({'open_interest': d.pop('openInterest', 0)}) # 昨持仓量 d.update({'open_interest': d.pop('openInterest', 0)}) # 昨持仓量
d.update({'open_interest': d.pop('tradingDay', get_trading_date())}) d.update({'open_interest': d.pop('tradingDay', get_trading_date())})
# 常规行情 # 常规行情
d.update({'open_price': d.pop('openPrice', 0)}) # 今日开盘价 d.update({'open_price': d.pop('openPrice', 0)}) # 今日开盘价
d.update({'high_price': d.pop('highPrice', 0)}) # 今日最高价 d.update({'high_price': d.pop('highPrice', 0)}) # 今日最高价
@ -1951,7 +1955,7 @@ class TqMdApi():
) )
if symbol.endswith('99') and tick.ask_price_1 == 0.0 and tick.bid_price_1 == 0.0: if symbol.endswith('99') and tick.ask_price_1 == 0.0 and tick.bid_price_1 == 0.0:
price_tick = quote['price_tick'] price_tick = quote['price_tick']
if isinstance(price_tick, float) or isinstance(price_tick,int): if isinstance(price_tick, float) or isinstance(price_tick, int):
tick.ask_price_1 = tick.last_price + price_tick tick.ask_price_1 = tick.last_price + price_tick
tick.ask_volume_1 = 1 tick.ask_volume_1 = 1
tick.bid_price_1 = tick.last_price - price_tick tick.bid_price_1 = tick.last_price - price_tick

View File

@ -485,7 +485,7 @@ class FutuGateway(BaseGateway):
sys_orderid = "" sys_orderid = ""
for ix, row in data.iterrows(): for ix, row in data.iterrows():
sys_orderid = str(row.get("order_id","")) sys_orderid = str(row.get("order_id", ""))
if len(sys_orderid) > 0: if len(sys_orderid) > 0:
self.write_log(f'系统委托号:{sys_orderid}') self.write_log(f'系统委托号:{sys_orderid}')
break break

View File

@ -1167,7 +1167,7 @@ class TqMdApi():
return return
try: try:
from tqsdk import TqApi from tqsdk import TqApi
self.api = TqApi(_stock=True,url="wss://u.shinnytech.com/t/nfmd/front/mobile") self.api = TqApi(_stock=True, url="wss://u.shinnytech.com/t/nfmd/front/mobile")
except Exception as e: except Exception as e:
self.gateway.write_log(f'天勤股票行情API接入异常:'.format(str(e))) self.gateway.write_log(f'天勤股票行情API接入异常:'.format(str(e)))
self.gateway.write_log(traceback.format_exc()) self.gateway.write_log(traceback.format_exc())

View File

@ -17,6 +17,11 @@ from functools import lru_cache
from collections import OrderedDict from collections import OrderedDict
from multiprocessing.dummy import Pool from multiprocessing.dummy import Pool
from threading import Thread from threading import Thread
from pytdx.hq import TdxHq_API
from pytdx.config.hosts import hq_hosts
from pytdx.params import TDXParams
from vnpy.event import EventEngine from vnpy.event import EventEngine
from vnpy.trader.event import EVENT_TIMER from vnpy.trader.event import EVENT_TIMER
from vnpy.trader.constant import ( from vnpy.trader.constant import (
@ -45,6 +50,9 @@ from vnpy.trader.object import (
from vnpy.trader.utility import get_folder_path, print_dict, extract_vt_symbol, get_stock_exchange, append_data from vnpy.trader.utility import get_folder_path, print_dict, extract_vt_symbol, get_stock_exchange, append_data
from vnpy.data.tdx.tdx_common import get_stock_type_sz, get_stock_type_sh from vnpy.data.tdx.tdx_common import get_stock_type_sz, get_stock_type_sh
# 通达信股票行情
from vnpy.data.tdx.tdx_common import get_cache_config, get_tdx_market_code
# 代码 <=> 中文名称 # 代码 <=> 中文名称
symbol_name_map: Dict[str, str] = {} symbol_name_map: Dict[str, str] = {}
# 代码 <=> 交易所 # 代码 <=> 交易所
@ -303,11 +311,6 @@ STATUS_PB2VT: Dict[str, Status] = {
} }
STOCK_CONFIG_FILE = 'tdx_stock_config.pkb2' STOCK_CONFIG_FILE = 'tdx_stock_config.pkb2'
from pytdx.hq import TdxHq_API
# 通达信股票行情
from vnpy.data.tdx.tdx_common import get_cache_config, get_tdx_market_code
from pytdx.config.hosts import hq_hosts
from pytdx.params import TDXParams
class PbGateway(BaseGateway): class PbGateway(BaseGateway):
@ -474,12 +477,12 @@ class PbMdApi(object):
{'ip': "124.160.88.183", 'port': 7709}, {'ip': "124.160.88.183", 'port': 7709},
{'ip': "60.12.136.250", 'port': 7709}, {'ip': "60.12.136.250", 'port': 7709},
{'ip': "218.108.98.244", 'port': 7709}, {'ip': "218.108.98.244", 'port': 7709},
#{'ip': "218.108.47.69", 'port': 7709}, # {'ip': "218.108.47.69", 'port': 7709},
{'ip': "114.80.63.12", 'port': 7709}, {'ip': "114.80.63.12", 'port': 7709},
{'ip': "114.80.63.35", 'port': 7709}, {'ip': "114.80.63.35", 'port': 7709},
{'ip': "180.153.39.51", 'port': 7709}, {'ip': "180.153.39.51", 'port': 7709},
#{'ip': '14.215.128.18', 'port': 7709}, # {'ip': '14.215.128.18', 'port': 7709},
#{'ip': '59.173.18.140', 'port': 7709} # {'ip': '59.173.18.140', 'port': 7709}
] ]
self.best_ip = {'ip': None, 'port': None} self.best_ip = {'ip': None, 'port': None}
@ -722,7 +725,7 @@ class PbMdApi(object):
margin_rate=1 margin_rate=1
) )
if product!= Product.INDEX: if product != Product.INDEX:
# 缓存 合约 =》 中文名 # 缓存 合约 =》 中文名
symbol_name_map.update({contract.symbol: contract.name}) symbol_name_map.update({contract.symbol: contract.name})
@ -1654,7 +1657,8 @@ class PbTdApi(object):
order.status = Status.REJECTED order.status = Status.REJECTED
self.gateway.write_log(f'dbf批量下单委托被拒:{order.__dict__}') self.gateway.write_log(f'dbf批量下单委托被拒:{order.__dict__}')
self.gateway.order_manager.on_order(order) self.gateway.order_manager.on_order(order)
self.gateway.write_error(msg=f'{order.direction.value},{order.vt_symbol},{err_msg}', error={"ErrorID": err_id, "ErrorMsg": "委托失败"}) self.gateway.write_error(msg=f'{order.direction.value},{order.vt_symbol},{err_msg}',
error={"ErrorID": err_id, "ErrorMsg": "委托失败"})
if sys_orderid != '0': if sys_orderid != '0':
self.gateway.order_manager.update_orderid_map(local_orderid=local_orderid, self.gateway.order_manager.update_orderid_map(local_orderid=local_orderid,
@ -1933,7 +1937,6 @@ class PbTdApi(object):
'{}{}.dbf'.format(PB_FILE_NAMES.get('cancel_order'), '{}{}.dbf'.format(PB_FILE_NAMES.get('cancel_order'),
self.trading_date))) self.trading_date)))
# 打开dbf文件=》table # 打开dbf文件=》table
table = dbf.Table(dbf_file) table = dbf.Table(dbf_file)
# 读取、写入模式 # 读取、写入模式
@ -2062,14 +2065,14 @@ class TqMdApi():
self.ticks = {} self.ticks = {}
def connect(self, setting = {}): def connect(self, setting={}):
"""""" """"""
if self.api and self.is_connected: if self.api and self.is_connected:
self.gateway.write_log(f'天勤行情已经接入,无需重新连接') self.gateway.write_log(f'天勤行情已经接入,无需重新连接')
return return
try: try:
from tqsdk import TqApi from tqsdk import TqApi
self.api = TqApi(_stock=True) self.api = TqApi(_stock=True, url="wss://u.shinnytech.com/t/nfmd/front/mobile")
except Exception as e: except Exception as e:
self.gateway.write_log(f'天勤股票行情API接入异常:'.format(str(e))) self.gateway.write_log(f'天勤股票行情API接入异常:'.format(str(e)))
self.gateway.write_log(traceback.format_exc()) self.gateway.write_log(traceback.format_exc())
@ -2203,4 +2206,3 @@ class TqMdApi():
self.update_thread.join() self.update_thread.join()
except Exception as e: except Exception as e:
self.gateway.write_log('退出天勤行情api异常:{}'.format(str(e))) self.gateway.write_log('退出天勤行情api异常:{}'.format(str(e)))

View File

@ -4,7 +4,7 @@ import sys
import json import json
import traceback import traceback
from datetime import datetime, timedelta from datetime import datetime, timedelta
from copy import copy,deepcopy from copy import copy, deepcopy
from functools import lru_cache from functools import lru_cache
from typing import List from typing import List
import pandas as pd import pandas as pd
@ -175,6 +175,7 @@ TQ2VT_TYPE = {
"OPTION": Product.OPTION, "OPTION": Product.OPTION,
} }
@lru_cache(maxsize=9999) @lru_cache(maxsize=9999)
def vt_to_tq_symbol(symbol: str, exchange: Exchange) -> str: def vt_to_tq_symbol(symbol: str, exchange: Exchange) -> str:
""" """
@ -270,7 +271,7 @@ class RohonGateway(BaseGateway):
product_info = setting["产品信息"] product_info = setting["产品信息"]
rabbit_dict = setting.get('rabbit', None) rabbit_dict = setting.get('rabbit', None)
tq_dict = setting.get('tq', None) tq_dict = setting.get('tq', None)
self.debug = setting.get('debug',False) self.debug = setting.get('debug', False)
if not td_address.startswith("tcp://"): if not td_address.startswith("tcp://"):
td_address = "tcp://" + td_address td_address = "tcp://" + td_address
@ -425,12 +426,12 @@ class RohonGateway(BaseGateway):
self.write_log(f'使用RabbitMQ接口订阅{req.symbol}') self.write_log(f'使用RabbitMQ接口订阅{req.symbol}')
self.rabbit_api.subscribe(req) self.rabbit_api.subscribe(req)
elif self.tq_api: elif self.tq_api:
self.write_log(f'使用天勤接口订阅{ req.symbol}') self.write_log(f'使用天勤接口订阅{req.symbol}')
self.tq_api.subscribe(req) self.tq_api.subscribe(req)
else: else:
# 上期所、上能源支持五档行情,使用天勤接口 # 上期所、上能源支持五档行情,使用天勤接口
if self.tq_api and req.exchange in [Exchange.SHFE, Exchange.INE]: if self.tq_api and req.exchange in [Exchange.SHFE, Exchange.INE]:
self.write_log(f'使用天勤接口订阅{ req.symbol}') self.write_log(f'使用天勤接口订阅{req.symbol}')
self.tq_api.subscribe(req) self.tq_api.subscribe(req)
else: else:
self.write_log(f'使用CTP接口订阅{req.symbol}') self.write_log(f'使用CTP接口订阅{req.symbol}')
@ -537,6 +538,7 @@ class RohonGateway(BaseGateway):
tick = copy(tick) tick = copy(tick)
combiner.on_tick(tick) combiner.on_tick(tick)
class RohonMdApi(MdApi): class RohonMdApi(MdApi):
"""""" """"""
@ -645,7 +647,7 @@ class RohonMdApi(MdApi):
# 处理一下标准套利合约的last_price # 处理一下标准套利合约的last_price
if '&' in symbol: if '&' in symbol:
tick.last_price = (tick.ask_price_1 + tick.bid_price_1)/2 tick.last_price = (tick.ask_price_1 + tick.bid_price_1) / 2
if data["BidVolume2"] or data["AskVolume2"]: if data["BidVolume2"] or data["AskVolume2"]:
tick.bid_price_2 = adjust_price(data["BidPrice2"]) tick.bid_price_2 = adjust_price(data["BidPrice2"])
@ -924,7 +926,7 @@ class RohonTdApi(TdApi):
if "AccountID" not in data: if "AccountID" not in data:
return return
if len(self.accountid)== 0: if len(self.accountid) == 0:
self.accountid = data['AccountID'] self.accountid = data['AccountID']
account = AccountData( account = AccountData(
@ -955,7 +957,7 @@ class RohonTdApi(TdApi):
""" """
Callback of instrument query. Callback of instrument query.
""" """
#if self.gateway.debug: # if self.gateway.debug:
# print(f'onRspQryInstrument') # print(f'onRspQryInstrument')
product = PRODUCT_ROHON2VT.get(data["ProductClass"], None) product = PRODUCT_ROHON2VT.get(data["ProductClass"], None)
@ -1113,7 +1115,7 @@ class RohonTdApi(TdApi):
exchange=exchange, exchange=exchange,
orderid=orderid, orderid=orderid,
sys_orderid=data.get("OrderSysID", orderid), sys_orderid=data.get("OrderSysID", orderid),
tradeid=tradeid.replace(' ',''), tradeid=tradeid.replace(' ', ''),
direction=DIRECTION_ROHON2VT[data["Direction"]], direction=DIRECTION_ROHON2VT[data["Direction"]],
offset=OFFSET_ROHON2VT[data["OffsetFlag"]], offset=OFFSET_ROHON2VT[data["OffsetFlag"]],
price=data["Price"], price=data["Price"],
@ -1760,23 +1762,22 @@ class SubMdApi():
"""转换dict vnpy1 tick dict => vnpy2 tick dict""" """转换dict vnpy1 tick dict => vnpy2 tick dict"""
if 'vtSymbol' not in d: if 'vtSymbol' not in d:
return d return d
symbol= d.get('symbol') symbol = d.get('symbol')
exchange = d.get('exchange') exchange = d.get('exchange')
vtSymbol = d.pop('vtSymbol', symbol) d.pop('vtSymbol', None)
if '.' not in symbol: if '.' not in symbol:
d.update({'vt_symbol': f'{symbol}.{exchange}'}) d.update({'vt_symbol': f'{symbol}.{exchange}'})
else: else:
d.update({'vt_symbol': f'{symbol}.{Exchange.LOCAL.value}'}) d.update({'vt_symbol': f'{symbol}.{Exchange.LOCAL.value}'})
# 成交数据 # 成交数据
d.update({'last_price': d.pop('lastPrice',0.0)}) # 最新成交价 d.update({'last_price': d.pop('lastPrice', 0.0)}) # 最新成交价
d.update({'last_volume': d.pop('lastVolume', 0)}) # 最新成交量 d.update({'last_volume': d.pop('lastVolume', 0)}) # 最新成交量
d.update({'open_interest': d.pop('openInterest', 0)}) # 昨持仓量 d.update({'open_interest': d.pop('openInterest', 0)}) # 昨持仓量
d.update({'open_interest': d.pop('tradingDay', get_trading_date())}) d.update({'open_interest': d.pop('tradingDay', get_trading_date())})
# 常规行情 # 常规行情
d.update({'open_price': d.pop('openPrice', 0)}) # 今日开盘价 d.update({'open_price': d.pop('openPrice', 0)}) # 今日开盘价
d.update({'high_price': d.pop('highPrice', 0)}) # 今日最高价 d.update({'high_price': d.pop('highPrice', 0)}) # 今日最高价
@ -1922,7 +1923,7 @@ class TqMdApi():
) )
if symbol.endswith('99') and tick.ask_price_1 == 0.0 and tick.bid_price_1 == 0.0: if symbol.endswith('99') and tick.ask_price_1 == 0.0 and tick.bid_price_1 == 0.0:
price_tick = quote['price_tick'] price_tick = quote['price_tick']
if isinstance(price_tick, float) or isinstance(price_tick,int): if isinstance(price_tick, float) or isinstance(price_tick, int):
tick.ask_price_1 = tick.last_price + price_tick tick.ask_price_1 = tick.last_price + price_tick
tick.ask_volume_1 = 1 tick.ask_volume_1 = 1
tick.bid_price_1 = tick.last_price - price_tick tick.bid_price_1 = tick.last_price - price_tick
@ -1960,7 +1961,7 @@ class TqMdApi():
def query_contracts(self) -> None: def query_contracts(self) -> None:
"""""" """"""
self.all_instruments = [ self.all_instruments = [
v for k, v in self.api._data["quotes"].items() if v["expired"] == False v for k, v in self.api._data["quotes"].items() if not v["expired"]
] ]
for contract in self.all_instruments: for contract in self.all_instruments:
if ( if (

View File

@ -71,7 +71,6 @@ from vnpy.trader.utility import (
) )
from vnpy.trader.event import EVENT_TIMER from vnpy.trader.event import EVENT_TIMER
STATUS_SOPT2VT = { STATUS_SOPT2VT = {
THOST_FTDC_OAS_Submitted: Status.SUBMITTING, THOST_FTDC_OAS_Submitted: Status.SUBMITTING,
THOST_FTDC_OAS_Accepted: Status.SUBMITTING, THOST_FTDC_OAS_Accepted: Status.SUBMITTING,
@ -127,6 +126,7 @@ symbol_name_map = {}
symbol_size_map = {} symbol_size_map = {}
option_name_map = {} option_name_map = {}
class SoptGateway(BaseGateway): class SoptGateway(BaseGateway):
""" """
VN Trader Gateway for SOPT . VN Trader Gateway for SOPT .
@ -282,7 +282,7 @@ class SoptGateway(BaseGateway):
self.td_api.close() self.td_api.close()
self.md_api.close() self.md_api.close()
#def write_error(self, msg: str, error: dict): # def write_error(self, msg: str, error: dict):
# """""" # """"""
# error_id = error["ErrorID"] # error_id = error["ErrorID"]
# error_msg = error["ErrorMsg"] # error_msg = error["ErrorMsg"]
@ -306,7 +306,6 @@ class SoptGateway(BaseGateway):
self.query_functions = [self.query_account, self.query_position] self.query_functions = [self.query_account, self.query_position]
self.event_engine.register(EVENT_TIMER, self.process_timer_event) self.event_engine.register(EVENT_TIMER, self.process_timer_event)
def on_custom_tick(self, tick): def on_custom_tick(self, tick):
"""推送自定义合约行情""" """推送自定义合约行情"""
# 自定义合约行情 # 自定义合约行情
@ -386,9 +385,9 @@ class SoptMdApi(MdApi):
exchange = symbol_exchange_map.get(symbol, "") exchange = symbol_exchange_map.get(symbol, "")
if not exchange: if not exchange:
return return
timestamp = f"{data['TradingDay']} {data['UpdateTime']}.{int(data['UpdateMillisec']/100)}" timestamp = f"{data['TradingDay']} {data['UpdateTime']}.{int(data['UpdateMillisec'] / 100)}"
dt = datetime.strptime(timestamp, "%Y%m%d %H:%M:%S.%f") dt = datetime.strptime(timestamp, "%Y%m%d %H:%M:%S.%f")
#dt = CHINA_TZ.localize(dt) # dt = CHINA_TZ.localize(dt)
tick = TickData( tick = TickData(
symbol=symbol, symbol=symbol,
@ -408,6 +407,7 @@ class SoptMdApi(MdApi):
ask_price_1=data["AskPrice1"], ask_price_1=data["AskPrice1"],
bid_volume_1=data["BidVolume1"], bid_volume_1=data["BidVolume1"],
ask_volume_1=data["AskVolume1"], ask_volume_1=data["AskVolume1"],
trading_day=dt.strftime('%Y-%m-%d'),
gateway_name=self.gateway_name gateway_name=self.gateway_name
) )
@ -597,7 +597,8 @@ class SoptTdApi(TdApi):
) )
self.gateway.on_order(order) self.gateway.on_order(order)
self.gateway.write_error(f"交易委托失败:{symbol} {order.direction.value} {order.offset.value} {order.price}, {order.volume}", error) self.gateway.write_error(
f"交易委托失败:{symbol} {order.direction.value} {order.offset.value} {order.price}, {order.volume}", error)
def onRspOrderAction(self, data: dict, error: dict, reqid: int, last: bool): def onRspOrderAction(self, data: dict, error: dict, reqid: int, last: bool):
"""""" """"""
@ -621,7 +622,7 @@ class SoptTdApi(TdApi):
if not data: if not data:
return return
#self.gateway.write_log(print_dict(data)) # self.gateway.write_log(print_dict(data))
# Get buffered position object # Get buffered position object
key = f"{data['InstrumentID'], data['PosiDirection']}" key = f"{data['InstrumentID'], data['PosiDirection']}"
@ -682,16 +683,20 @@ class SoptTdApi(TdApi):
# 重新累计多头期权动态权益 # 重新累计多头期权动态权益
if position.direction == Direction.LONG: if position.direction == Direction.LONG:
if self.long_option_cost is None: if self.long_option_cost is None:
self.long_option_cost = position.cur_price * position.volume * symbol_size_map.get(position.symbol, 0) self.long_option_cost = position.cur_price * position.volume * symbol_size_map.get(
position.symbol, 0)
else: else:
self.long_option_cost += position.cur_price * position.volume * symbol_size_map.get(position.symbol, 0) self.long_option_cost += position.cur_price * position.volume * symbol_size_map.get(
position.symbol, 0)
# 重新累计空头期权动态权益 # 重新累计空头期权动态权益
if position.direction == Direction.SHORT: if position.direction == Direction.SHORT:
if self.short_option_cost is None: if self.short_option_cost is None:
self.short_option_cost = position.cur_price * position.volume * symbol_size_map.get(position.symbol, 0) self.short_option_cost = position.cur_price * position.volume * symbol_size_map.get(
position.symbol, 0)
else: else:
self.short_option_cost += position.cur_price * position.volume * symbol_size_map.get(position.symbol, 0) self.short_option_cost += position.cur_price * position.volume * symbol_size_map.get(
position.symbol, 0)
self.gateway.on_position(position) self.gateway.on_position(position)
@ -704,7 +709,7 @@ class SoptTdApi(TdApi):
# 资金差额权利金正数是卖call或卖put收入权利金; 负数是买call、买put付出权利金 # 资金差额权利金正数是卖call或卖put收入权利金; 负数是买call、买put付出权利金
cash_in = data.get('CashIn') cash_in = data.get('CashIn')
#balance -= cash_in # balance -= cash_in
if self.long_option_cost is not None: if self.long_option_cost is not None:
balance += self.long_option_cost balance += self.long_option_cost
@ -717,13 +722,14 @@ class SoptTdApi(TdApi):
gateway_name=self.gateway_name gateway_name=self.gateway_name
) )
#self.gateway.write_log(print_dict(data)) # self.gateway.write_log(print_dict(data))
account.available = data["Available"] account.available = data["Available"]
account.commission = round(float(data['Commission']), 7) + round(float(data['SpecProductCommission']), 7) account.commission = round(float(data['Commission']), 7) + round(float(data['SpecProductCommission']), 7)
account.margin = round(float(data['CurrMargin']), 7) account.margin = round(float(data['CurrMargin']), 7)
account.close_profit = round(float(data['CloseProfit']), 7) + round(float(data['SpecProductCloseProfit']), 7) account.close_profit = round(float(data['CloseProfit']), 7) + round(float(data['SpecProductCloseProfit']), 7)
account.holding_profit = round(float(data['PositionProfit']), 7) + round(float(data['SpecProductPositionProfit']), 7) account.holding_profit = round(float(data['PositionProfit']), 7) + round(
float(data['SpecProductPositionProfit']), 7)
account.trading_day = str(data.get('TradingDay', datetime.now().strftime('%Y-%m-%d'))) account.trading_day = str(data.get('TradingDay', datetime.now().strftime('%Y-%m-%d')))
if '-' not in account.trading_day and len(account.trading_day) == 8: if '-' not in account.trading_day and len(account.trading_day) == 8:
@ -765,7 +771,7 @@ class SoptTdApi(TdApi):
) )
contract.option_type = OPTIONTYPE_SOPT2VT.get(data["OptionsType"], None) contract.option_type = OPTIONTYPE_SOPT2VT.get(data["OptionsType"], None)
contract.option_strike = data["StrikePrice"] contract.option_strike = data["StrikePrice"]
#contract.option_index = str(data["StrikePrice"]) # contract.option_index = str(data["StrikePrice"])
contract.option_expiry = datetime.strptime(data["ExpireDate"], "%Y%m%d") contract.option_expiry = datetime.strptime(data["ExpireDate"], "%Y%m%d")
contract.option_index = get_option_index( contract.option_index = get_option_index(
contract.option_strike, data["InstrumentCode"] contract.option_strike, data["InstrumentCode"]
@ -806,7 +812,7 @@ class SoptTdApi(TdApi):
timestamp = f"{data['InsertDate']} {data['InsertTime']}" timestamp = f"{data['InsertDate']} {data['InsertTime']}"
dt = datetime.strptime(timestamp, "%Y%m%d %H:%M:%S") dt = datetime.strptime(timestamp, "%Y%m%d %H:%M:%S")
#dt = CHINA_TZ.localize(dt) # dt = CHINA_TZ.localize(dt)
order = OrderData( order = OrderData(
accountid=self.userid, accountid=self.userid,

View File

@ -128,12 +128,13 @@ symbol_name_map: Dict[str, str] = {}
# 代码 <=> 交易所 # 代码 <=> 交易所
symbol_exchange_map: Dict[str, Exchange] = {} symbol_exchange_map: Dict[str, Exchange] = {}
@lru_cache() @lru_cache()
def get_vt_symbol_name(vt_symbol): def get_vt_symbol_name(vt_symbol):
return symbol_name_map.get(vt_symbol, vt_symbol.split('.')[0]) return symbol_name_map.get(vt_symbol, vt_symbol.split('.')[0])
class XtpGateway(BaseGateway):
class XtpGateway(BaseGateway):
default_setting: Dict[str, Any] = { default_setting: Dict[str, Any] = {
"账号": "", "账号": "",
"密码": "", "密码": "",
@ -301,7 +302,7 @@ class XtpMdApi(MdApi):
tick.ask_volume_1, tick.ask_volume_2, tick.ask_volume_3, tick.ask_volume_4, tick.ask_volume_5 = data["ask_qty"][0:5] tick.ask_volume_1, tick.ask_volume_2, tick.ask_volume_3, tick.ask_volume_4, tick.ask_volume_5 = data["ask_qty"][0:5]
tick.name = get_vt_symbol_name(tick.vt_symbol) tick.name = get_vt_symbol_name(tick.vt_symbol)
#self.gateway.prices.update({tick.vt_symbol: tick.last_price}) # self.gateway.prices.update({tick.vt_symbol: tick.last_price})
self.gateway.on_tick(tick) self.gateway.on_tick(tick)
def onSubOrderBook(self, data: dict, error: dict, last: bool) -> None: def onSubOrderBook(self, data: dict, error: dict, last: bool) -> None:
@ -364,14 +365,14 @@ class XtpMdApi(MdApi):
min_volume=data["buy_qty_unit"], min_volume=data["buy_qty_unit"],
gateway_name=self.gateway_name gateway_name=self.gateway_name
) )
#if contract.symbol.startswith('1230'): # if contract.symbol.startswith('1230'):
# self.gateway.write_log(msg=f'合约信息:{contract.__dict__}') # self.gateway.write_log(msg=f'合约信息:{contract.__dict__}')
self.gateway.on_contract(contract) self.gateway.on_contract(contract)
# 更新最新价 # 更新最新价
pre_close_price = float(data["pre_close_price"]) pre_close_price = float(data["pre_close_price"])
vt_symbol = contract.vt_symbol vt_symbol = contract.vt_symbol
if vt_symbol not in self.gateway.prices and pre_close_price>0: if vt_symbol not in self.gateway.prices and pre_close_price > 0:
self.gateway.prices.update({vt_symbol: pre_close_price}) self.gateway.prices.update({vt_symbol: pre_close_price})
# 更新 symbol <=> 中文名称映射 # 更新 symbol <=> 中文名称映射
@ -573,7 +574,7 @@ class XtpTdApi(TdApi):
direction, offset = DIRECTION_STOCK_XTP2VT[data["side"]] direction, offset = DIRECTION_STOCK_XTP2VT[data["side"]]
trade_time = str(data["trade_time"]) trade_time = str(data["trade_time"])
dt = datetime.strptime(trade_time,'%Y%m%d%H%M%S%f') dt = datetime.strptime(trade_time, '%Y%m%d%H%M%S%f')
trade = TradeData( trade = TradeData(
accountid=self.userid, accountid=self.userid,
@ -634,10 +635,10 @@ class XtpTdApi(TdApi):
pnl=data["unrealized_pnl"], pnl=data["unrealized_pnl"],
yd_volume=data["yesterday_position"], yd_volume=data["yesterday_position"],
gateway_name=self.gateway_name, gateway_name=self.gateway_name,
cur_price=self.gateway.prices.get(vt_symbol,0) cur_price=self.gateway.prices.get(vt_symbol, 0)
) )
if position.volume > 0 and position.cur_price > 0: if position.volume > 0 and position.cur_price > 0:
position.pnl = round(position.volume * (position.cur_price - position.price),2) position.pnl = round(position.volume * (position.cur_price - position.price), 2)
self.gateway.on_position(position) self.gateway.on_position(position)
# 如果持仓>0 获取持仓对应的当前最新价 # 如果持仓>0 获取持仓对应的当前最新价
@ -648,7 +649,7 @@ class XtpTdApi(TdApi):
def update_security_asset(self): def update_security_asset(self):
"""更新资产净值""" """更新资产净值"""
#self.gateway.write_log(f'更新资产净值') # self.gateway.write_log(f'更新资产净值')
total_asset = 0 total_asset = 0
for vt_symbol, volume in self.security_volumes.items(): for vt_symbol, volume in self.security_volumes.items():
price = self.gateway.prices.get(vt_symbol, None) price = self.gateway.prices.get(vt_symbol, None)
@ -662,7 +663,7 @@ class XtpTdApi(TdApi):
return return
total_asset += volume * price total_asset += volume * price
#self.gateway.write_log(f'资产净值 => {total_asset}') # self.gateway.write_log(f'资产净值 => {total_asset}')
self.security_asset = total_asset self.security_asset = total_asset
@ -761,7 +762,7 @@ class XtpTdApi(TdApi):
exchange=exchange, exchange=exchange,
direction=Direction.SHORT, direction=Direction.SHORT,
gateway_name=self.gateway_name, gateway_name=self.gateway_name,
cur_price=self.gateway.prices.get(f'{symbol}.{exchange.value}',0.0) cur_price=self.gateway.prices.get(f'{symbol}.{exchange.value}', 0.0)
) )
self.short_positions[symbol] = position self.short_positions[symbol] = position
@ -860,7 +861,7 @@ class XtpTdApi(TdApi):
"market": MARKET_VT2XTP[req.exchange], "market": MARKET_VT2XTP[req.exchange],
"price": req.price, "price": req.price,
"quantity": int(req.volume), "quantity": int(req.volume),
"side": DIRECTION_STOCK_VT2XTP.get((req.direction,req.offset), ""), "side": DIRECTION_STOCK_VT2XTP.get((req.direction, req.offset), ""),
"price_type": ORDERTYPE_VT2XTP[req.type], "price_type": ORDERTYPE_VT2XTP[req.type],
"business_type": BUSINESS_VT2XTP[req.offset] "business_type": BUSINESS_VT2XTP[req.offset]
} }

View File

@ -165,6 +165,7 @@ class Interval(Enum):
WEEKLY = "w" WEEKLY = "w"
RENKO = 'renko' RENKO = 'renko'
class StockType(Enum): class StockType(Enum):
"""股票类型tdx""" """股票类型tdx"""
STOCK = 'stock_cn' # 股票 STOCK = 'stock_cn' # 股票

View File

@ -177,7 +177,7 @@ class PositionHolding:
self.short_yd -= trade.volume self.short_yd -= trade.volume
# 多,平仓 =》 减少 # 多,平仓 =》 减少
elif trade.offset == Offset.CLOSE: elif trade.offset == Offset.CLOSE:
if trade.exchange in [Exchange.SHFE, Exchange.INE] and self.short_yd >=trade.volume: if trade.exchange in [Exchange.SHFE, Exchange.INE] and self.short_yd >= trade.volume:
self.short_yd -= trade.volume self.short_yd -= trade.volume
else: else:
self.short_td -= trade.volume self.short_td -= trade.volume
@ -196,7 +196,7 @@ class PositionHolding:
elif trade.offset == Offset.CLOSEYESTERDAY: elif trade.offset == Offset.CLOSEYESTERDAY:
self.long_yd -= trade.volume self.long_yd -= trade.volume
elif trade.offset == Offset.CLOSE: elif trade.offset == Offset.CLOSE:
if trade.exchange in [Exchange.SHFE, Exchange.INE] and self.long_yd >=trade.volume: if trade.exchange in [Exchange.SHFE, Exchange.INE] and self.long_yd >= trade.volume:
self.long_yd -= trade.volume self.long_yd -= trade.volume
else: else:
self.long_td -= trade.volume self.long_td -= trade.volume

View File

@ -568,7 +568,7 @@ class OmsEngine(BaseEngine):
return Direction.LONG return Direction.LONG
return direction return direction
def create_spd_position_event(self, symbol, direction ): def create_spd_position_event(self, symbol, direction):
"""创建自定义品种对持仓信息""" """创建自定义品种对持仓信息"""
spd_symbols = self.symbol_spd_maping.get(symbol, []) spd_symbols = self.symbol_spd_maping.get(symbol, [])
if not spd_symbols: if not spd_symbols:
@ -614,7 +614,7 @@ class OmsEngine(BaseEngine):
continue continue
# 根据leg1/leg2的volume ratio计算出最小spd_volume # 根据leg1/leg2的volume ratio计算出最小spd_volume
spd_volume = min(int(leg1_pos.volume/leg1_ratio), int(leg2_pos.volume/leg2_ratio)) spd_volume = min(int(leg1_pos.volume / leg1_ratio), int(leg2_pos.volume / leg2_ratio))
if spd_volume <= 0 and spd_pos is None: if spd_volume <= 0 and spd_pos is None:
continue continue
@ -766,6 +766,7 @@ class OmsEngine(BaseEngine):
"""根据主动腿/被动腿symbol获取自定义套利对的symbol list""" """根据主动腿/被动腿symbol获取自定义套利对的symbol list"""
return self.symbol_spd_maping.get(symbol, []) return self.symbol_spd_maping.get(symbol, [])
class CustomContract(object): class CustomContract(object):
""" """
定制合约 定制合约

View File

@ -334,7 +334,7 @@ class LocalOrderManager:
Management tool to support use local order id for trading. Management tool to support use local order id for trading.
""" """
def __init__(self, gateway: BaseGateway, order_prefix: str = "", order_rjust:int = 8): def __init__(self, gateway: BaseGateway, order_prefix: str = "", order_rjust: int = 8):
"""""" """"""
self.gateway: BaseGateway = gateway self.gateway: BaseGateway = gateway

View File

@ -209,6 +209,7 @@ class TradeData(BaseData):
self.vt_tradeid = f"{self.gateway_name}.{self.tradeid}" self.vt_tradeid = f"{self.gateway_name}.{self.tradeid}"
self.vt_accountid = f"{self.gateway_name}.{self.accountid}" self.vt_accountid = f"{self.gateway_name}.{self.accountid}"
@dataclass @dataclass
class PositionData(BaseData): class PositionData(BaseData):
""" """
@ -238,6 +239,7 @@ class PositionData(BaseData):
if self.name == "": if self.name == "":
self.name = self.vt_symbol self.name = self.vt_symbol
@dataclass @dataclass
class AccountData(BaseData): class AccountData(BaseData):
""" """

View File

@ -9,7 +9,6 @@ from copy import copy
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from vnpy.event import Event, EventEngine from vnpy.event import Event, EventEngine
from ..constant import Direction, Exchange, Offset, OrderType from ..constant import Direction, Exchange, Offset, OrderType
from ..engine import MainEngine from ..engine import MainEngine
@ -628,7 +627,7 @@ class TradingWidget(QtWidgets.QWidget):
[order_type.value for order_type in OrderType]) [order_type.value for order_type in OrderType])
double_validator = QtGui.QDoubleValidator() double_validator = QtGui.QDoubleValidator()
#double_validator.setBottom(0) # double_validator.setBottom(0)
self.price_line = QtWidgets.QLineEdit() self.price_line = QtWidgets.QLineEdit()
self.price_line.setValidator(double_validator) self.price_line.setValidator(double_validator)

View File

@ -14,15 +14,16 @@ import requests
import sys import sys
import traceback import traceback
from datetime import datetime from datetime import datetime
from functools import wraps # from functools import wraps
from vnpy.trader.utility import print_dict from vnpy.trader.utility import print_dict
global wechat_lock global wechat_lock
wechat_lock = Lock() wechat_lock = Lock()
# 这里可以设置UIDS, 多个人可同时接收 # 这里可以设置UIDS, 多个人可同时接收
UIDS = ['UID_kZguGPBQPWn41Ni9FK4CgPts2KjU'] UIDS = ['UID_kZguGPBQPWn41Ni9FK4CgPts2Kjx']
APP_TOKEN = 'AT_aDuiQu41dmAQV2vUMXOaaTDrWyhKJN2z' APP_TOKEN = 'AT_aDuiQu41dmAQV2vUMXOaaTDrWyhKJN2x'
class wechat_thread(Thread): class wechat_thread(Thread):
@ -42,7 +43,7 @@ class wechat_thread(Thread):
self.topic_ids = topic_ids self.topic_ids = topic_ids
self.url = url self.url = url
self.lock = wechat_lock self.lock = wechat_lock
self.app_token = app_token if len(app_token) > 0 else APP_TOKEN self.app_token = app_token if app_token is not None and len(app_token) > 0 else APP_TOKEN
def run(self): def run(self):
if self.content is None or len(self.content) == 0: if self.content is None or len(self.content) == 0:
@ -61,7 +62,7 @@ class wechat_thread(Thread):
if not response.get('success', False): if not response.get('success', False):
print(response) print(response)
except Exception as e: except Exception as e:
print("{} wechat_thread sent failed! ex:{},trace:{}".format(datetime.now(), str(e), traceback.format_exc()), print("{} 微信发送异常 ex:{},trace:{}".format(datetime.now(), str(e), traceback.format_exc()),
file=sys.stderr) file=sys.stderr)
return return
@ -84,8 +85,9 @@ def send_wx_msg(*args, **kwargs):
try: try:
# 如果存在华富资产的微信模块,则使用 # 如果存在华富资产的微信模块,则使用
from vnpy.trader.util_huafu import sendWeChatMsg, WECHAT_URL,WECHAT_GROUP, WECHAT_LEVEL_INFO, WECHAT_MSG_TYPE_ALERT from vnpy.trader.util_huafu import sendWeChatMsg, WECHAT_URL, WECHAT_GROUP, WECHAT_LEVEL_INFO, \
target=kwargs.get('target','XXX') WECHAT_MSG_TYPE_ALERT
target = kwargs.get('target', 'XXX')
sendWeChatMsg(content=content, sendWeChatMsg(content=content,
target=WECHAT_GROUP.get(target), target=WECHAT_GROUP.get(target),
url=kwargs.get('url', WECHAT_URL), url=kwargs.get('url', WECHAT_URL),
@ -93,6 +95,7 @@ def send_wx_msg(*args, **kwargs):
msg_type=kwargs.get('msg_type', WECHAT_MSG_TYPE_ALERT)) msg_type=kwargs.get('msg_type', WECHAT_MSG_TYPE_ALERT))
return return
except Exception as ex: except Exception as ex:
print(f'发送微信异常:{str(ex)}', file=sys.stderr)
pass pass
# dict => str, none str => str # dict => str, none str => str
@ -114,6 +117,7 @@ def send_wx_msg(*args, **kwargs):
# t.run() # t.run()
t.start() t.start()
if __name__ == '__main__': if __name__ == '__main__':
text = u'微信测试标题!!!!\n第二行' text = u'微信测试标题!!!!\n第二行'

View File

@ -163,6 +163,7 @@ def get_trading_date(dt: datetime = None):
else: else:
return dt.strftime('%Y-%m-%d') return dt.strftime('%Y-%m-%d')
def extract_vt_symbol(vt_symbol: str) -> Tuple[str, Exchange]: def extract_vt_symbol(vt_symbol: str) -> Tuple[str, Exchange]:
""" """
:return: (symbol, exchange) :return: (symbol, exchange)
@ -328,6 +329,7 @@ def get_digits(value: float) -> int:
else: else:
return 0 return 0
def print_dict(d: dict): def print_dict(d: dict):
"""返回dict的字符串类型""" """返回dict的字符串类型"""
return '\n'.join([f'{key}:{d[key]}' for key in sorted(d.keys())]) return '\n'.join([f'{key}:{d[key]}' for key in sorted(d.keys())])
@ -356,6 +358,7 @@ def get_csv_last_dt(file_name, dt_index=0, dt_format='%Y-%m-%d %H:%M:%S', line_l
return None return None
return None return None
def append_data(file_name: str, dict_data: dict, field_names: list = [], auto_header=True, encoding='utf8'): def append_data(file_name: str, dict_data: dict, field_names: list = [], auto_header=True, encoding='utf8'):
""" """
添加数据到csv文件中 添加数据到csv文件中
@ -410,11 +413,11 @@ def import_module_by_str(import_module_name):
mod = import_module(loaded_modules) mod = import_module(loaded_modules)
comp = modules[-1] comp = modules[-1]
#if not hasattr(mod, comp): # if not hasattr(mod, comp):
# loaded_modules = '.'.join([loaded_modules, comp]) # loaded_modules = '.'.join([loaded_modules, comp])
print('realod {}'.format(loaded_modules)) print('realod {}'.format(loaded_modules))
mod = reload(mod) mod = reload(mod)
#else: # else:
# print('from {} import {}'.format(loaded_modules, comp)) # print('from {} import {}'.format(loaded_modules, comp))
comp = getattr(mod, comp) comp = getattr(mod, comp)
return comp return comp
@ -669,6 +672,7 @@ def load_data_from_pkb2(pkb2_file_name):
data = pickle.load(f) data = pickle.load(f)
return data return data
def save_data_to_pkb2(data: Any, pkb2_file_name): def save_data_to_pkb2(data: Any, pkb2_file_name):
"""保存本地缓存的配置地址信息""" """保存本地缓存的配置地址信息"""
with bz2.BZ2File(pkb2_file_name, 'wb') as f: with bz2.BZ2File(pkb2_file_name, 'wb') as f: