[一般更新] Flask8检查代码,套利模板,股票下载更新,天勤更新
This commit is contained in:
parent
74d156b3ae
commit
b32ca3b9d5
@ -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')
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
|
||||||
# 结束一个交易日后,更新每日净值
|
# 结束一个交易日后,更新每日净值
|
||||||
|
@ -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)
|
||||||
|
|
||||||
# 结束一个交易日后,更新每日净值
|
# 结束一个交易日后,更新每日净值
|
||||||
|
@ -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,
|
||||||
|
@ -168,7 +168,7 @@ class StrategyManager(QtWidgets.QFrame):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, cta_manager: CtaManager, cta_engine: CtaEngine, data: dict
|
self, cta_manager: CtaManager, cta_engine: CtaEngine, data: dict
|
||||||
):
|
):
|
||||||
""""""
|
""""""
|
||||||
super(StrategyManager, self).__init__()
|
super(StrategyManager, self).__init__()
|
||||||
@ -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.
|
||||||
@ -408,7 +409,7 @@ class SettingEditor(QtWidgets.QDialog):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, parameters: dict, strategy_name: str = "", class_name: str = ""
|
self, parameters: dict, strategy_name: str = "", class_name: str = ""
|
||||||
):
|
):
|
||||||
""""""
|
""""""
|
||||||
super(SettingEditor, self).__init__()
|
super(SettingEditor, self).__init__()
|
||||||
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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'
|
||||||
|
|
||||||
|
@ -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():
|
||||||
""" 获取股票基础信息"""
|
""" 获取股票基础信息"""
|
||||||
|
@ -46,7 +46,6 @@ NUM_MINUTE_MAPPING['1day'] = 60 * 5.5 # 股票,收盘时间是15:00,开
|
|||||||
# 常量
|
# 常量
|
||||||
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"')
|
||||||
@ -549,7 +550,7 @@ class TdxStockData(object):
|
|||||||
hq_codelist.append(
|
hq_codelist.append(
|
||||||
{
|
{
|
||||||
"code": row['code'],
|
"code": row['code'],
|
||||||
"exchange": Exchange.SSE.value if row['sse'] == 'sh' else Exchange.SZSE.value,
|
"exchange": Exchange.SSE.value if row['sse'] == 'sh' else Exchange.SZSE.value,
|
||||||
"market_id": 1 if row['sse'] == 'sh' else 0,
|
"market_id": 1 if row['sse'] == 'sh' else 0,
|
||||||
"name": row['name']
|
"name": row['name']
|
||||||
|
|
||||||
@ -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
|
||||||
|
@ -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')
|
||||||
|
@ -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",
|
||||||
|
@ -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"]),
|
||||||
@ -126,7 +127,7 @@ def generate_tick_from_dict(vt_symbol: str, data: dict) -> TickData:
|
|||||||
class TqFutureData():
|
class TqFutureData():
|
||||||
|
|
||||||
def __init__(self, strategy=None):
|
def __init__(self, strategy=None):
|
||||||
self.strategy = strategy # 传进来策略实例,这样可以写日志到策略实例
|
self.strategy = strategy # 传进来策略实例,这样可以写日志到策略实例
|
||||||
|
|
||||||
self.api = TqApi(TqSim(), url="wss://u.shinnytech.com/t/md/front/mobile")
|
self.api = TqApi(TqSim(), url="wss://u.shinnytech.com/t/md/front/mobile")
|
||||||
|
|
||||||
@ -139,7 +140,7 @@ class TqFutureData():
|
|||||||
with closing(self.api):
|
with closing(self.api):
|
||||||
# 获得 pp2009 tick序列的引用
|
# 获得 pp2009 tick序列的引用
|
||||||
ticks = self.api.get_tick_serial(symbol=tq_symbol, data_length=8964) # 每个序列最大支持请求 8964 个数据
|
ticks = self.api.get_tick_serial(symbol=tq_symbol, data_length=8964) # 每个序列最大支持请求 8964 个数据
|
||||||
return ticks # 8964/3/60=49.8分钟
|
return ticks # 8964/3/60=49.8分钟
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print(u'获取历史tick数据出错:{},{}'.format(str(ex), traceback.format_exc()))
|
print(u'获取历史tick数据出错:{},{}'.format(str(ex), traceback.format_exc()))
|
||||||
return None
|
return None
|
||||||
@ -148,7 +149,7 @@ class TqFutureData():
|
|||||||
|
|
||||||
symbol, exchange = extract_vt_symbol(vt_symbol)
|
symbol, exchange = extract_vt_symbol(vt_symbol)
|
||||||
tq_symbol = to_tq_symbol(symbol, exchange)
|
tq_symbol = to_tq_symbol(symbol, exchange)
|
||||||
td = DataDownloader(self.api, symbol_list=tq_symbol, dur_sec=0, # Tick数据为dur_sec=0
|
td = DataDownloader(self.api, symbol_list=tq_symbol, dur_sec=0, # Tick数据为dur_sec=0
|
||||||
start_dt=start_date, end_dt=end_date,
|
start_dt=start_date, end_dt=end_date,
|
||||||
csv_file_name=cache_file)
|
csv_file_name=cache_file)
|
||||||
|
|
||||||
@ -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])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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("持仓信息查询成功")
|
||||||
|
|
||||||
|
@ -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,20 +1803,19 @@ 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)}) # 今日最高价
|
||||||
d.update({'low_price': d.pop('lowPrice', 0)}) # 今日最低价
|
d.update({'low_price': d.pop('lowPrice', 0)}) # 今日最低价
|
||||||
d.update({'pre_close': d.pop('preClosePrice', 0)}) # 昨收盘价
|
d.update({'pre_close': d.pop('preClosePrice', 0)}) # 昨收盘价
|
||||||
d.update({'limit_up': d.pop('upperLimit', 0)}) # 涨停价
|
d.update({'limit_up': d.pop('upperLimit', 0)}) # 涨停价
|
||||||
d.update({'limit_down': d.pop('lowerLimit', 0)}) # 跌停价
|
d.update({'limit_down': d.pop('lowerLimit', 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
|
||||||
@ -1993,8 +1997,8 @@ class TqMdApi():
|
|||||||
]
|
]
|
||||||
for contract in self.all_instruments:
|
for contract in self.all_instruments:
|
||||||
if (
|
if (
|
||||||
"SSWE" in contract["instrument_id"]
|
"SSWE" in contract["instrument_id"]
|
||||||
or "CSI" in contract["instrument_id"]
|
or "CSI" in contract["instrument_id"]
|
||||||
):
|
):
|
||||||
# vnpy没有这两个交易所,需要可以自行修改vnpy代码
|
# vnpy没有这两个交易所,需要可以自行修改vnpy代码
|
||||||
continue
|
continue
|
||||||
|
@ -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
|
||||||
|
@ -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())
|
||||||
|
@ -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,13 +477,13 @@ 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}
|
||||||
self.api_dict = {} # API 的连接会话对象字典
|
self.api_dict = {} # API 的连接会话对象字典
|
||||||
@ -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)))
|
||||||
|
|
||||||
|
@ -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"],
|
||||||
@ -1125,14 +1127,14 @@ class RohonTdApi(TdApi):
|
|||||||
self.gateway.on_trade(trade)
|
self.gateway.on_trade(trade)
|
||||||
|
|
||||||
def connect(
|
def connect(
|
||||||
self,
|
self,
|
||||||
address: str,
|
address: str,
|
||||||
userid: str,
|
userid: str,
|
||||||
password: str,
|
password: str,
|
||||||
brokerid: int,
|
brokerid: int,
|
||||||
auth_code: str,
|
auth_code: str,
|
||||||
appid: str,
|
appid: str,
|
||||||
product_info
|
product_info
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Start connection to server.
|
Start connection to server.
|
||||||
@ -1760,29 +1762,28 @@ 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)}) # 今日最高价
|
||||||
d.update({'low_price': d.pop('lowPrice', 0)}) # 今日最低价
|
d.update({'low_price': d.pop('lowPrice', 0)}) # 今日最低价
|
||||||
d.update({'pre_close': d.pop('preClosePrice', 0)}) # 昨收盘价
|
d.update({'pre_close': d.pop('preClosePrice', 0)}) # 昨收盘价
|
||||||
d.update({'limit_up': d.pop('upperLimit', 0)}) # 涨停价
|
d.update({'limit_up': d.pop('upperLimit', 0)}) # 涨停价
|
||||||
d.update({'limit_down': d.pop('lowerLimit', 0)}) # 跌停价
|
d.update({'limit_down': d.pop('lowerLimit', 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,12 +1961,12 @@ 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 (
|
||||||
"SSWE" in contract["instrument_id"]
|
"SSWE" in contract["instrument_id"]
|
||||||
or "CSI" in contract["instrument_id"]
|
or "CSI" in contract["instrument_id"]
|
||||||
):
|
):
|
||||||
# vnpy没有这两个交易所,需要可以自行修改vnpy代码
|
# vnpy没有这两个交易所,需要可以自行修改vnpy代码
|
||||||
continue
|
continue
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -523,8 +523,8 @@ class SoptTdApi(TdApi):
|
|||||||
self.positions = {}
|
self.positions = {}
|
||||||
self.sysid_orderid_map = {}
|
self.sysid_orderid_map = {}
|
||||||
|
|
||||||
self.long_option_cost = None # 多头期权动态市值
|
self.long_option_cost = None # 多头期权动态市值
|
||||||
self.short_option_cost = None # 空头期权动态市值
|
self.short_option_cost = None # 空头期权动态市值
|
||||||
|
|
||||||
def onFrontConnected(self):
|
def onFrontConnected(self):
|
||||||
""""""
|
""""""
|
||||||
@ -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:
|
||||||
@ -758,14 +764,14 @@ class SoptTdApi(TdApi):
|
|||||||
if contract.product == Product.OPTION:
|
if contract.product == Product.OPTION:
|
||||||
contract.option_portfolio = data["UnderlyingInstrID"] + "_O"
|
contract.option_portfolio = data["UnderlyingInstrID"] + "_O"
|
||||||
contract.option_underlying = (
|
contract.option_underlying = (
|
||||||
data["UnderlyingInstrID"]
|
data["UnderlyingInstrID"]
|
||||||
+ "-"
|
+ "-"
|
||||||
+ str(data["DeliveryYear"])
|
+ str(data["DeliveryYear"])
|
||||||
+ str(data["DeliveryMonth"]).rjust(2, "0")
|
+ str(data["DeliveryMonth"]).rjust(2, "0")
|
||||||
)
|
)
|
||||||
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,
|
||||||
@ -862,14 +868,14 @@ class SoptTdApi(TdApi):
|
|||||||
self.gateway.on_trade(trade)
|
self.gateway.on_trade(trade)
|
||||||
|
|
||||||
def connect(
|
def connect(
|
||||||
self,
|
self,
|
||||||
address: str,
|
address: str,
|
||||||
userid: str,
|
userid: str,
|
||||||
password: str,
|
password: str,
|
||||||
brokerid: int,
|
brokerid: int,
|
||||||
auth_code: str,
|
auth_code: str,
|
||||||
appid: str,
|
appid: str,
|
||||||
product_info
|
product_info
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Start connection to server.
|
Start connection to server.
|
||||||
|
@ -43,9 +43,9 @@ EXCHANGE_VT2XTP: Dict[Exchange, int] = {v: k for k, v in EXCHANGE_XTP2VT.items()
|
|||||||
|
|
||||||
# 方向 <=> Direction, Offset
|
# 方向 <=> Direction, Offset
|
||||||
DIRECTION_STOCK_XTP2VT: Dict[int, Any] = {
|
DIRECTION_STOCK_XTP2VT: Dict[int, Any] = {
|
||||||
1: (Direction.LONG, Offset.NONE), # 买
|
1: (Direction.LONG, Offset.NONE), # 买
|
||||||
2: (Direction.SHORT, Offset.NONE), # 卖
|
2: (Direction.SHORT, Offset.NONE), # 卖
|
||||||
21: (Direction.LONG, Offset.OPEN), # 多,开
|
21: (Direction.LONG, Offset.OPEN), # 多,开
|
||||||
22: (Direction.SHORT, Offset.OPEN), # 空,开
|
22: (Direction.SHORT, Offset.OPEN), # 空,开
|
||||||
24: (Direction.LONG, Offset.CLOSE), # 多,平
|
24: (Direction.LONG, Offset.CLOSE), # 多,平
|
||||||
23: (Direction.SHORT, Offset.CLOSE) # 空, 平
|
23: (Direction.SHORT, Offset.CLOSE) # 空, 平
|
||||||
@ -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 <=> 中文名称映射
|
||||||
@ -422,13 +423,13 @@ class XtpMdApi(MdApi):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def connect(
|
def connect(
|
||||||
self,
|
self,
|
||||||
userid: str,
|
userid: str,
|
||||||
password: str,
|
password: str,
|
||||||
client_id: int,
|
client_id: int,
|
||||||
server_ip: str,
|
server_ip: str,
|
||||||
server_port: int,
|
server_port: int,
|
||||||
quote_protocol: int
|
quote_protocol: int
|
||||||
) -> None:
|
) -> None:
|
||||||
""""""
|
""""""
|
||||||
self.userid = userid
|
self.userid = userid
|
||||||
@ -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,
|
||||||
@ -609,12 +610,12 @@ class XtpTdApi(TdApi):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def onQueryPosition(
|
def onQueryPosition(
|
||||||
self,
|
self,
|
||||||
data: dict,
|
data: dict,
|
||||||
error: dict,
|
error: dict,
|
||||||
request: int,
|
request: int,
|
||||||
last: bool,
|
last: bool,
|
||||||
session: int
|
session: int
|
||||||
) -> None:
|
) -> None:
|
||||||
"""普通账号持仓"""
|
"""普通账号持仓"""
|
||||||
# self.gateway.write_log(f"------\n {print_dict(data)}")
|
# self.gateway.write_log(f"------\n {print_dict(data)}")
|
||||||
@ -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,17 +663,17 @@ 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
|
||||||
|
|
||||||
def onQueryAsset(
|
def onQueryAsset(
|
||||||
self,
|
self,
|
||||||
data: dict,
|
data: dict,
|
||||||
error: dict,
|
error: dict,
|
||||||
request: int,
|
request: int,
|
||||||
last: bool,
|
last: bool,
|
||||||
session: int
|
session: int
|
||||||
) -> None:
|
) -> None:
|
||||||
""""""
|
""""""
|
||||||
# XTP_ACCOUNT_NORMAL = 0, ///<普通账户
|
# XTP_ACCOUNT_NORMAL = 0, ///<普通账户
|
||||||
@ -691,8 +692,8 @@ class XtpTdApi(TdApi):
|
|||||||
|
|
||||||
account = AccountData(
|
account = AccountData(
|
||||||
accountid=self.userid,
|
accountid=self.userid,
|
||||||
balance=balance, # 总资产
|
balance=balance, # 总资产
|
||||||
margin=self.security_asset, # 证券资产
|
margin=self.security_asset, # 证券资产
|
||||||
frozen=data["withholding_amount"],
|
frozen=data["withholding_amount"],
|
||||||
gateway_name=self.gateway_name,
|
gateway_name=self.gateway_name,
|
||||||
trading_day=datetime.now().strftime('%Y-%m-%d')
|
trading_day=datetime.now().strftime('%Y-%m-%d')
|
||||||
@ -740,12 +741,12 @@ class XtpTdApi(TdApi):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def onQueryCreditDebtInfo(
|
def onQueryCreditDebtInfo(
|
||||||
self,
|
self,
|
||||||
data: dict,
|
data: dict,
|
||||||
error: dict,
|
error: dict,
|
||||||
request: int,
|
request: int,
|
||||||
last: bool,
|
last: bool,
|
||||||
session: int
|
session: int
|
||||||
) -> None:
|
) -> None:
|
||||||
"""信用账号持仓"""
|
"""信用账号持仓"""
|
||||||
self.gateway.write_log(f"------\n {print_dict(data)}")
|
self.gateway.write_log(f"------\n {print_dict(data)}")
|
||||||
@ -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
|
||||||
|
|
||||||
@ -774,13 +775,13 @@ class XtpTdApi(TdApi):
|
|||||||
self.short_positions.clear()
|
self.short_positions.clear()
|
||||||
|
|
||||||
def connect(
|
def connect(
|
||||||
self,
|
self,
|
||||||
userid: str,
|
userid: str,
|
||||||
password: str,
|
password: str,
|
||||||
client_id: int,
|
client_id: int,
|
||||||
server_ip: str,
|
server_ip: str,
|
||||||
server_port: int,
|
server_port: int,
|
||||||
software_key: str
|
software_key: str
|
||||||
) -> None:
|
) -> None:
|
||||||
""""""
|
""""""
|
||||||
|
|
||||||
@ -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]
|
||||||
}
|
}
|
||||||
|
@ -88,45 +88,45 @@ class Exchange(Enum):
|
|||||||
Exchange.
|
Exchange.
|
||||||
"""
|
"""
|
||||||
# Chinese
|
# Chinese
|
||||||
CFFEX = "CFFEX" # China Financial Futures Exchange
|
CFFEX = "CFFEX" # China Financial Futures Exchange
|
||||||
SHFE = "SHFE" # Shanghai Futures Exchange
|
SHFE = "SHFE" # Shanghai Futures Exchange
|
||||||
CZCE = "CZCE" # Zhengzhou Commodity Exchange
|
CZCE = "CZCE" # Zhengzhou Commodity Exchange
|
||||||
DCE = "DCE" # Dalian Commodity Exchange
|
DCE = "DCE" # Dalian Commodity Exchange
|
||||||
INE = "INE" # Shanghai International Energy Exchange
|
INE = "INE" # Shanghai International Energy Exchange
|
||||||
SSE = "SSE" # Shanghai Stock Exchange
|
SSE = "SSE" # Shanghai Stock Exchange
|
||||||
SZSE = "SZSE" # Shenzhen Stock Exchange
|
SZSE = "SZSE" # Shenzhen Stock Exchange
|
||||||
SGE = "SGE" # Shanghai Gold Exchange
|
SGE = "SGE" # Shanghai Gold Exchange
|
||||||
WXE = "WXE" # Wuxi Steel Exchange
|
WXE = "WXE" # Wuxi Steel Exchange
|
||||||
CFETS = "CFETS" # China Foreign Exchange Trade System
|
CFETS = "CFETS" # China Foreign Exchange Trade System
|
||||||
|
|
||||||
# Global
|
# Global
|
||||||
SMART = "SMART" # Smart Router for US stocks
|
SMART = "SMART" # Smart Router for US stocks
|
||||||
NYSE = "NYSE" # New York Stock Exchnage
|
NYSE = "NYSE" # New York Stock Exchnage
|
||||||
NASDAQ = "NASDAQ" # Nasdaq Exchange
|
NASDAQ = "NASDAQ" # Nasdaq Exchange
|
||||||
NYMEX = "NYMEX" # New York Mercantile Exchange
|
NYMEX = "NYMEX" # New York Mercantile Exchange
|
||||||
COMEX = "COMEX" # a division of theNew York Mercantile Exchange
|
COMEX = "COMEX" # a division of theNew York Mercantile Exchange
|
||||||
GLOBEX = "GLOBEX" # Globex of CME
|
GLOBEX = "GLOBEX" # Globex of CME
|
||||||
IDEALPRO = "IDEALPRO" # Forex ECN of Interactive Brokers
|
IDEALPRO = "IDEALPRO" # Forex ECN of Interactive Brokers
|
||||||
CME = "CME" # Chicago Mercantile Exchange
|
CME = "CME" # Chicago Mercantile Exchange
|
||||||
ICE = "ICE" # Intercontinental Exchange
|
ICE = "ICE" # Intercontinental Exchange
|
||||||
SEHK = "SEHK" # Stock Exchange of Hong Kong
|
SEHK = "SEHK" # Stock Exchange of Hong Kong
|
||||||
HKFE = "HKFE" # Hong Kong Futures Exchange
|
HKFE = "HKFE" # Hong Kong Futures Exchange
|
||||||
HKSE = "HKSE" # Hong Kong Stock Exchange
|
HKSE = "HKSE" # Hong Kong Stock Exchange
|
||||||
SGX = "SGX" # Singapore Global Exchange
|
SGX = "SGX" # Singapore Global Exchange
|
||||||
CBOT = "CBT" # Chicago Board of Trade
|
CBOT = "CBT" # Chicago Board of Trade
|
||||||
CBOE = "CBOE" # Chicago Board Options Exchange
|
CBOE = "CBOE" # Chicago Board Options Exchange
|
||||||
CFE = "CFE" # CBOE Futures Exchange
|
CFE = "CFE" # CBOE Futures Exchange
|
||||||
DME = "DME" # Dubai Mercantile Exchange
|
DME = "DME" # Dubai Mercantile Exchange
|
||||||
EUREX = "EUX" # Eurex Exchange
|
EUREX = "EUX" # Eurex Exchange
|
||||||
APEX = "APEX" # Asia Pacific Exchange
|
APEX = "APEX" # Asia Pacific Exchange
|
||||||
LME = "LME" # London Metal Exchange
|
LME = "LME" # London Metal Exchange
|
||||||
BMD = "BMD" # Bursa Malaysia Derivatives
|
BMD = "BMD" # Bursa Malaysia Derivatives
|
||||||
TOCOM = "TOCOM" # Tokyo Commodity Exchange
|
TOCOM = "TOCOM" # Tokyo Commodity Exchange
|
||||||
EUNX = "EUNX" # Euronext Exchange
|
EUNX = "EUNX" # Euronext Exchange
|
||||||
KRX = "KRX" # Korean Exchange
|
KRX = "KRX" # Korean Exchange
|
||||||
AMEX = "AMEX" # NESE American
|
AMEX = "AMEX" # NESE American
|
||||||
|
|
||||||
OANDA = "OANDA" # oanda.com
|
OANDA = "OANDA" # oanda.com
|
||||||
|
|
||||||
# CryptoCurrency
|
# CryptoCurrency
|
||||||
BITMEX = "BITMEX"
|
BITMEX = "BITMEX"
|
||||||
@ -134,15 +134,15 @@ class Exchange(Enum):
|
|||||||
HUOBI = "HUOBI"
|
HUOBI = "HUOBI"
|
||||||
BITFINEX = "BITFINEX"
|
BITFINEX = "BITFINEX"
|
||||||
BINANCE = "BINANCE"
|
BINANCE = "BINANCE"
|
||||||
BYBIT = "BYBIT" # bybit.com
|
BYBIT = "BYBIT" # bybit.com
|
||||||
COINBASE = "COINBASE"
|
COINBASE = "COINBASE"
|
||||||
DERIBIT = "DERIBIT"
|
DERIBIT = "DERIBIT"
|
||||||
GATEIO = "GATEIO"
|
GATEIO = "GATEIO"
|
||||||
BITSTAMP = "BITSTAMP"
|
BITSTAMP = "BITSTAMP"
|
||||||
|
|
||||||
# Special Function
|
# Special Function
|
||||||
LOCAL = "LOCAL" # For local generated data
|
LOCAL = "LOCAL" # For local generated data
|
||||||
SPD = "SPD" # Customer Spread data
|
SPD = "SPD" # Customer Spread data
|
||||||
|
|
||||||
|
|
||||||
class Currency(Enum):
|
class Currency(Enum):
|
||||||
@ -165,12 +165,13 @@ 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' # 股票
|
||||||
STOCKB = 'stockB_cn' # 深圳B股票(特别)
|
STOCKB = 'stockB_cn' # 深圳B股票(特别)
|
||||||
INDEX = 'index_cn' # 指数
|
INDEX = 'index_cn' # 指数
|
||||||
BOND = 'bond_cn' # 企业债券
|
BOND = 'bond_cn' # 企业债券
|
||||||
ETF = 'etf_cn' # ETF
|
ETF = 'etf_cn' # ETF
|
||||||
CB = 'cb_cn' # 可转债
|
CB = 'cb_cn' # 可转债
|
||||||
UNDEFINED = 'undefined' # 未定义
|
UNDEFINED = 'undefined' # 未定义
|
||||||
|
@ -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
|
||||||
@ -194,9 +194,9 @@ class PositionHolding:
|
|||||||
elif trade.offset == Offset.CLOSETODAY:
|
elif trade.offset == Offset.CLOSETODAY:
|
||||||
self.long_td -= trade.volume
|
self.long_td -= trade.volume
|
||||||
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
|
||||||
|
@ -431,8 +431,8 @@ class OmsEngine(BaseEngine):
|
|||||||
self.today_contracts: Dict[str, ContractData] = {}
|
self.today_contracts: Dict[str, ContractData] = {}
|
||||||
|
|
||||||
# 自定义合约
|
# 自定义合约
|
||||||
self.custom_contracts = {} # vt_symbol: ContractData
|
self.custom_contracts = {} # vt_symbol: ContractData
|
||||||
self.custom_settings = {} # symbol: dict
|
self.custom_settings = {} # symbol: dict
|
||||||
self.symbol_spd_maping = {} # symbol: [spd_symbol]
|
self.symbol_spd_maping = {} # symbol: [spd_symbol]
|
||||||
|
|
||||||
self.prices = {}
|
self.prices = {}
|
||||||
@ -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):
|
||||||
"""
|
"""
|
||||||
定制合约
|
定制合约
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ class BarData(BaseData):
|
|||||||
trading_day: str = "" # '%Y-%m-%d'
|
trading_day: str = "" # '%Y-%m-%d'
|
||||||
|
|
||||||
interval: Interval = None # constant.py Internal 1m, 1h, 1d, 1w .etc
|
interval: Interval = None # constant.py Internal 1m, 1h, 1d, 1w .etc
|
||||||
interval_num: int = 1 # 5 for 5m, 5h etc
|
interval_num: int = 1 # 5 for 5m, 5h etc
|
||||||
volume: float = 0
|
volume: float = 0
|
||||||
open_interest: float = 0
|
open_interest: float = 0
|
||||||
open_price: float = 0
|
open_price: float = 0
|
||||||
@ -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):
|
||||||
"""
|
"""
|
||||||
@ -218,7 +219,7 @@ class PositionData(BaseData):
|
|||||||
symbol: str
|
symbol: str
|
||||||
exchange: Exchange
|
exchange: Exchange
|
||||||
direction: Direction
|
direction: Direction
|
||||||
accountid: str = "" # 账号id
|
accountid: str = "" # 账号id
|
||||||
name: str = ""
|
name: str = ""
|
||||||
volume: float = 0
|
volume: float = 0
|
||||||
frozen: float = 0
|
frozen: float = 0
|
||||||
@ -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):
|
||||||
"""
|
"""
|
||||||
@ -330,7 +332,7 @@ class ContractData(BaseData):
|
|||||||
option_underlying: str = "" # vt_symbol of underlying contract
|
option_underlying: str = "" # vt_symbol of underlying contract
|
||||||
option_type: OptionType = None
|
option_type: OptionType = None
|
||||||
option_expiry: datetime = None
|
option_expiry: datetime = None
|
||||||
option_index: str = "" # vt_symbol mapping cur option
|
option_index: str = "" # vt_symbol mapping cur option
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
""""""
|
""""""
|
||||||
|
@ -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)
|
||||||
@ -721,9 +720,9 @@ class TradingWidget(QtWidgets.QWidget):
|
|||||||
self.setLayout(vbox)
|
self.setLayout(vbox)
|
||||||
|
|
||||||
def create_label(
|
def create_label(
|
||||||
self,
|
self,
|
||||||
color: str = "",
|
color: str = "",
|
||||||
alignment: int = QtCore.Qt.AlignLeft
|
alignment: int = QtCore.Qt.AlignLeft
|
||||||
) -> QtWidgets.QLabel:
|
) -> QtWidgets.QLabel:
|
||||||
"""
|
"""
|
||||||
Create label with certain font color.
|
Create label with certain font color.
|
||||||
|
@ -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,7 +95,8 @@ 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:
|
||||||
pass
|
print(f'发送微信异常:{str(ex)}', file=sys.stderr)
|
||||||
|
pass
|
||||||
|
|
||||||
# dict => str, none str => str
|
# dict => str, none str => str
|
||||||
if not isinstance(content, str):
|
if not isinstance(content, 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第二行'
|
||||||
|
|
||||||
|
@ -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())])
|
||||||
@ -352,10 +354,11 @@ def get_csv_last_dt(file_name, dt_index=0, dt_format='%Y-%m-%d %H:%M:%S', line_l
|
|||||||
try:
|
try:
|
||||||
last_dt = datetime.strptime(datas[dt_index], dt_format)
|
last_dt = datetime.strptime(datas[dt_index], dt_format)
|
||||||
return last_dt
|
return last_dt
|
||||||
except: # noqa
|
except: # noqa
|
||||||
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文件中
|
||||||
@ -366,7 +369,7 @@ def append_data(file_name: str, dict_data: dict, field_names: list = [], auto_he
|
|||||||
dict_fieldnames = sorted(list(dict_data.keys())) if len(field_names) == 0 else field_names
|
dict_fieldnames = sorted(list(dict_data.keys())) if len(field_names) == 0 else field_names
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not os.path.exists(file_name): # or os.path.getsize(file_name) == 0:
|
if not os.path.exists(file_name): # or os.path.getsize(file_name) == 0:
|
||||||
print(u'create csv file:{}'.format(file_name))
|
print(u'create csv file:{}'.format(file_name))
|
||||||
with open(file_name, 'a', encoding='utf8', newline='\n') as csvWriteFile:
|
with open(file_name, 'a', encoding='utf8', newline='\n') as csvWriteFile:
|
||||||
writer = csv.DictWriter(f=csvWriteFile, fieldnames=dict_fieldnames, dialect='excel')
|
writer = csv.DictWriter(f=csvWriteFile, fieldnames=dict_fieldnames, dialect='excel')
|
||||||
@ -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:
|
||||||
@ -687,11 +691,11 @@ class BarGenerator:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
on_bar: Callable,
|
on_bar: Callable,
|
||||||
window: int = 0,
|
window: int = 0,
|
||||||
on_window_bar: Callable = None,
|
on_window_bar: Callable = None,
|
||||||
interval: Interval = Interval.MINUTE
|
interval: Interval = Interval.MINUTE
|
||||||
):
|
):
|
||||||
"""Constructor"""
|
"""Constructor"""
|
||||||
self.bar: BarData = None
|
self.bar: BarData = None
|
||||||
@ -1087,11 +1091,11 @@ class ArrayManager(object):
|
|||||||
return result[-1]
|
return result[-1]
|
||||||
|
|
||||||
def macd(
|
def macd(
|
||||||
self,
|
self,
|
||||||
fast_period: int,
|
fast_period: int,
|
||||||
slow_period: int,
|
slow_period: int,
|
||||||
signal_period: int,
|
signal_period: int,
|
||||||
array: bool = False
|
array: bool = False
|
||||||
) -> Union[
|
) -> Union[
|
||||||
Tuple[np.ndarray, np.ndarray, np.ndarray],
|
Tuple[np.ndarray, np.ndarray, np.ndarray],
|
||||||
Tuple[float, float, float]
|
Tuple[float, float, float]
|
||||||
@ -1179,10 +1183,10 @@ class ArrayManager(object):
|
|||||||
return result[-1]
|
return result[-1]
|
||||||
|
|
||||||
def boll(
|
def boll(
|
||||||
self,
|
self,
|
||||||
n: int,
|
n: int,
|
||||||
dev: float,
|
dev: float,
|
||||||
array: bool = False
|
array: bool = False
|
||||||
) -> Union[
|
) -> Union[
|
||||||
Tuple[np.ndarray, np.ndarray],
|
Tuple[np.ndarray, np.ndarray],
|
||||||
Tuple[float, float]
|
Tuple[float, float]
|
||||||
@ -1199,10 +1203,10 @@ class ArrayManager(object):
|
|||||||
return up, down
|
return up, down
|
||||||
|
|
||||||
def keltner(
|
def keltner(
|
||||||
self,
|
self,
|
||||||
n: int,
|
n: int,
|
||||||
dev: float,
|
dev: float,
|
||||||
array: bool = False
|
array: bool = False
|
||||||
) -> Union[
|
) -> Union[
|
||||||
Tuple[np.ndarray, np.ndarray],
|
Tuple[np.ndarray, np.ndarray],
|
||||||
Tuple[float, float]
|
Tuple[float, float]
|
||||||
@ -1219,7 +1223,7 @@ class ArrayManager(object):
|
|||||||
return up, down
|
return up, down
|
||||||
|
|
||||||
def donchian(
|
def donchian(
|
||||||
self, n: int, array: bool = False
|
self, n: int, array: bool = False
|
||||||
) -> Union[
|
) -> Union[
|
||||||
Tuple[np.ndarray, np.ndarray],
|
Tuple[np.ndarray, np.ndarray],
|
||||||
Tuple[float, float]
|
Tuple[float, float]
|
||||||
@ -1235,9 +1239,9 @@ class ArrayManager(object):
|
|||||||
return up[-1], down[-1]
|
return up[-1], down[-1]
|
||||||
|
|
||||||
def aroon(
|
def aroon(
|
||||||
self,
|
self,
|
||||||
n: int,
|
n: int,
|
||||||
array: bool = False
|
array: bool = False
|
||||||
) -> Union[
|
) -> Union[
|
||||||
Tuple[np.ndarray, np.ndarray],
|
Tuple[np.ndarray, np.ndarray],
|
||||||
Tuple[float, float]
|
Tuple[float, float]
|
||||||
|
Loading…
Reference in New Issue
Block a user