[bug fix] 修复ctp对FAK支持,修复基础网格组件加载问题,修复转换持仓对非锁定品种支持,修复股票可转债价格问题,增加utility压缩文件方法

This commit is contained in:
msincenselee 2020-04-01 14:26:43 +08:00
parent fa9edcb0d3
commit 91823b8c71
14 changed files with 363 additions and 147 deletions

View File

@ -133,3 +133,26 @@
index-url=http://pypi.douban.com/simple
[install]
trusted-host=pypi.douban.com
13. 升级anaconda
anaconda用法
查看已经安装的包:
pip list 或者 conda list
安装和更新:
pip install requests
pip install requests --upgrade
或者
conda install requests
conda update requests
更新所有库
conda update --all
更新 conda 自身
conda update conda
更新 anaconda 自身
conda update anaconda

View File

@ -1238,7 +1238,7 @@ class CtaEngine(BaseEngine):
try:
# 5.保存策略切片
snapshot = strategy.get_klines_snapshot()
if len(snapshot) == 0:
if not snapshot:
self.write_log(f'{strategy_name}返回得K线切片数据为空')
return

View File

@ -789,6 +789,7 @@ class CtaFutureTemplate(CtaTemplate):
self.write_log(f'剩余委托单号:{grid.order_ids}')
self.gt.save()
# 在策略得活动订单中,移除
self.active_orders.pop(order.vt_orderid, None)

View File

@ -793,6 +793,10 @@ class CtaEngine(BaseEngine):
def get_price(self, vt_symbol: str):
"""查询合约的最新价格"""
price = self.main_engine.get_price(vt_symbol)
if price:
return price
tick = self.main_engine.get_tick(vt_symbol)
if tick:
return tick.last_price
@ -819,6 +823,10 @@ class CtaEngine(BaseEngine):
def get_position(self, vt_symbol: str, direction: Direction, gateway_name: str = ''):
""" 查询合约在账号的持仓,需要指定方向"""
if len(gateway_name) == 0:
contract = self.main_engine.get_contract(vt_symbol)
if contract and contract.gateway_name:
gateway_name = contract.gateway_name
vt_position_id = f"{gateway_name}.{vt_symbol}.{direction.value}"
return self.main_engine.get_position(vt_position_id)
@ -1178,7 +1186,7 @@ class CtaEngine(BaseEngine):
try:
# 5.保存策略切片
snapshot = strategy.get_klines_snapshot()
if len(snapshot) == 0:
if not snapshot:
self.write_log(f'{strategy_name}返回得K线切片数据为空')
return

View File

@ -1246,6 +1246,8 @@ class CtaProFutureTemplate(CtaProTemplate):
self.write_log(f'剩余委托单号:{grid.order_ids}')
self.gt.save()
# 在策略得活动订单中,移除
self.active_orders.pop(order.vt_orderid, None)
@ -1274,6 +1276,16 @@ class CtaProFutureTemplate(CtaProTemplate):
old_order['traded'] = order.traded
order_vt_symbol = copy(old_order['vt_symbol'])
order_volume = old_order['volume'] - old_order['traded']
order_price = old_order['price']
order_type = old_order.get('order_type', OrderType.LIMIT)
order_retry = old_order.get('retry', 0)
grid = old_order.get('grid', None)
if grid:
if order.vt_orderid in grid.order_ids:
grid.order_ids.remove(order.vt_orderid)
if order_volume <= 0:
msg = u'{} {}{}需重新开仓数量为{},不再开仓' \
.format(self.strategy_name,
@ -1286,10 +1298,6 @@ class CtaProFutureTemplate(CtaProTemplate):
self.active_orders.pop(order.vt_orderid, None)
return
order_price = old_order['price']
order_type = old_order.get('order_type', OrderType.LIMIT)
order_retry = old_order.get('retry', 0)
grid = old_order.get('grid', None)
if order_retry > 20:
# 这里超过20次尝试失败后不再尝试,发出告警信息
msg = u'{} {}/{}手, 重试开仓次数{}>20' \
@ -1299,15 +1307,9 @@ class CtaProFutureTemplate(CtaProTemplate):
order_retry)
self.write_error(msg)
self.send_wechat(msg)
if grid:
if order.vt_orderid in grid.order_ids:
grid.order_ids.remove(order.vt_orderid)
# 网格的所有委托单已经执行完毕
if len(grid.order_ids) == 0:
grid.order_status = False
# 网格的所有委托单已经执行完毕
if len(grid.order_ids) == 0:
grid.order_status = False
self.gt.save()
self.write_log(u'网格信息更新:{}'.format(grid.__dict__))
@ -1319,8 +1321,18 @@ class CtaProFutureTemplate(CtaProTemplate):
# FAK 重新开单
if old_order['direction'] == Direction.LONG and order_type == OrderType.FAK:
# 更新网格交易器
# 删除旧的委托记录
self.write_log(u'移除旧的委托记录:{}'.format(order.vt_orderid))
self.active_orders.pop(order.vt_orderid, None)
if order.traded > 0:
old_traded_volume = grid.traded_volume
grid.traded_volume += order.traded
self.write_log(f'{grid.direction.value}单部分{order.offset}仓,'
+ f'网格volume:{grid.volume}, traded_volume:{old_traded_volume}=>{grid.traded_volume}')
# 更新网格交易器
self.write_log(u'FAK模式需要重新发送buy委托.grid:{}'.format(grid.__dict__))
# 更新委托平仓价
buy_price = max(self.cur_mi_tick.ask_price_1, self.cur_mi_tick.last_price, order_price) + self.price_tick
@ -1350,11 +1362,18 @@ class CtaProFutureTemplate(CtaProTemplate):
info.update({'retry': order_retry})
self.gt.save()
elif old_order['direction'] == Direction.SHORT and order_type == OrderType.FAK:
# 删除旧的委托记录
self.write_log(u'移除旧的委托记录:{}'.format(order.vt_orderid))
self.active_orders.pop(order.vt_orderid, None)
elif old_order['direction'] == Direction.SHORT and order_type == OrderType.FAK:
if order.traded > 0:
old_traded_volume = grid.traded_volume
grid.traded_volume += order.traded
self.write_log(f'{grid.direction.value}单部分{order.offset}仓,'
+ f'网格volume:{grid.volume}, traded_volume:{old_traded_volume}=>{grid.traded_volume}')
self.write_log(u'FAK模式需要重新发送short委托.grid:{}'.format(grid.__dict__))
short_price = min(self.cur_mi_tick.bid_price_1, self.cur_mi_tick.last_price, order_price) - self.price_tick
@ -1385,9 +1404,7 @@ class CtaProFutureTemplate(CtaProTemplate):
info.update({'retry': order_retry})
self.gt.save()
# 删除旧的委托记录
self.write_log(u'移除旧的委托记录:{}'.format(order.vt_orderid))
self.active_orders.pop(order.vt_orderid, None)
else:
pre_status = old_order.get('status', Status.NOTTRADED)
old_order.update({'status': Status.CANCELLED})
@ -1423,6 +1440,15 @@ class CtaProFutureTemplate(CtaProTemplate):
# order_time = old_order['order_time']
order_vt_symbol = copy(old_order['vt_symbol'])
order_volume = old_order['volume'] - old_order['traded']
order_price = old_order['price']
order_type = old_order.get('order_type', OrderType.LIMIT)
order_retry = old_order.get('retry', 0)
grid = old_order.get('grid', None)
if grid:
if order.vt_orderid in grid.order_ids:
grid.order_ids.remove(order.vt_orderid)
if order_volume <= 0:
msg = u'{} {}{}重新平仓数量为{},不再平仓' \
.format(self.strategy_name, order.vt_orderid, order_vt_symbol, order_volume)
@ -1432,20 +1458,15 @@ class CtaProFutureTemplate(CtaProTemplate):
self.active_orders.pop(order.vt_orderid, None)
return
order_price = old_order['price']
order_type = old_order.get('order_type', OrderType.LIMIT)
order_retry = old_order.get('retry', 0)
grid = old_order.get('grid', None)
if order_retry > 20:
msg = u'{} 平仓撤单 {}/{}手, 重试平仓次数{}>20' \
.format(self.strategy_name, order_vt_symbol, order_volume, order_retry)
self.write_error(msg)
self.send_wechat(msg)
if grid:
if order.vt_orderid in grid.order_ids:
grid.order_ids.remove(order.vt_orderid)
if not grid.order_ids:
grid.order_status = False
if not grid.order_ids:
grid.order_status = False
self.gt.save()
self.write_log(u'更新网格=>{}'.format(grid.__dict__))
@ -1456,6 +1477,14 @@ class CtaProFutureTemplate(CtaProTemplate):
order_retry += 1
if old_order['direction'] == Direction.LONG and order_type == OrderType.FAK:
self.write_log(u'移除活动订单:{}'.format(order.vt_orderid))
self.active_orders.pop(order.vt_orderid, None)
if order.traded > 0:
old_traded_volume = grid.traded_volume
grid.traded_volume += order.traded
self.write_log(f'{grid.direction.value}单部分{order.offset}仓,'
+ f'网格volume:{grid.volume}, traded_volume:{old_traded_volume}=>{grid.traded_volume}')
self.write_log(u'FAK模式需要重新发送cover委托.grid:{}'.format(grid.__dict__))
# 更新委托平仓价
cover_tick = self.tick_dict.get(order_vt_symbol, self.cur_mi_tick)
@ -1484,10 +1513,17 @@ class CtaProFutureTemplate(CtaProTemplate):
info.update({'retry': order_retry})
self.gt.save()
self.write_log(u'移除活动订单:{}'.format(order.vt_orderid))
self.active_orders.pop(order.vt_orderid, None)
elif old_order['direction'] == Direction.SHORT and order_type == OrderType.FAK:
self.write_log(u'移除活动订单:{}'.format(order.vt_orderid))
self.active_orders.pop(order.vt_orderid, None)
if order.traded > 0:
old_traded_volume = grid.traded_volume
grid.traded_volume += order.traded
self.write_log(f'{grid.direction.value}单部分{order.offset}仓,'
+ f'网格volume:{grid.volume}, traded_volume:{old_traded_volume}=>{grid.traded_volume}')
self.write_log(u'FAK模式需要重新发送sell委托.grid:{}'.format(grid.__dict__))
sell_tick = self.tick_dict.get(order_vt_symbol, self.cur_mi_tick)
sell_price = min(sell_tick.bid_price_1, sell_tick.last_price, order_price) - self.price_tick
@ -1518,9 +1554,6 @@ class CtaProFutureTemplate(CtaProTemplate):
self.gt.save()
self.write_log(u'移除活动订单:{}'.format(order.vt_orderid))
self.active_orders.pop(order.vt_orderid, None)
else:
pre_status = old_order.get('status', Status.NOTTRADED)
old_order.update({'status': Status.CANCELLED})
@ -1583,6 +1616,8 @@ class CtaProFutureTemplate(CtaProTemplate):
if order_grid:
if vt_orderid in order_grid.order_ids:
order_grid.order_ids.remove(vt_orderid)
if len(order_grid.order_ids) == 0:
order_grid.order_status = False
continue
# 处理状态为‘撤销’的委托单

View File

@ -123,9 +123,9 @@ class CtaGrid(object):
def to_str(self):
"""转换字符串显示内容"""
str = u'o:{}/{};c:{}/{},r:{}/opentime:{}/ordertime:{}' \
str = u'o:{}/{};c:{}/{},r:{}/opentime:{}/ordertime:{},v:{}' \
.format(self.open_price, self.open_status, self.close_price,
self.close_status, self.order_ids, self.open_time, self.order_time)
self.close_status, self.order_ids, self.open_time, self.order_time, self.volume)
if len(self.vt_symbol) > 0:
return u'{} {}'.format(self.vt_symbol, str)
else:

View File

@ -373,7 +373,7 @@ class CtaLineBar(object):
self.para_boll2_len = 0 # 第二条布林的计算K线周期
self.para_boll2_tb_len = 0 # 第二跳布林的计算K线周期( 适用于TB的计算方式
self.para_boll2_std_sate = 2 # 第二条布林标准差缺省2倍
self.para_boll2_std_rate = 2 # 第二条布林标准差缺省2倍
self.para_kdj_len = 0 # KDJ指标的长度,缺省是9
self.para_kdj_tb_len = 0 # KDJ指标的长度,缺省是9 ( for TB)
@ -2059,9 +2059,9 @@ class CtaLineBar(object):
boll2Len = min(self.bar_len, self.para_boll2_len)
# 不包含当前最新的Bar
upper_list, middle_list, lower_list = ta.BBANDS(self.close_array[-2 * self.para_boll2_len],
timeperiod=boll2Len, nbdevup=self.para_boll2_std_sate,
nbdevdn=self.para_boll2_std_sate, matype=0)
upper_list, middle_list, lower_list = ta.BBANDS(self.close_array,
timeperiod=boll2Len, nbdevup=self.para_boll2_std_rate,
nbdevdn=self.para_boll2_std_rate, matype=0)
if len(self.line_boll2_upper) > self.max_hold_bars:
del self.line_boll2_upper[0]
if len(self.line_boll2_middle) > self.max_hold_bars:
@ -2072,7 +2072,7 @@ class CtaLineBar(object):
del self.line_boll2_std[0]
# 1标准差
std = (upper_list[-1] - lower_list[-1]) / (self.para_boll2_std_sate * 2)
std = (upper_list[-1] - lower_list[-1]) / (self.para_boll2_std_rate * 2)
self.line_boll2_std.append(std)
upper = round(upper_list[-1], self.round_n)
@ -2188,15 +2188,15 @@ class CtaLineBar(object):
middle = np.mean(self.close_array[-2 * boll2Len:])
self.line_boll2_middle.append(middle) # 中轨
self.cur_middle2 = middle - middle % self.price_tick # 中轨取整
self.cur_middle2 = middle # 中轨取整
upper = middle + self.para_boll2_std_sate * std
upper = middle + self.para_boll2_std_rate * std
self.line_boll2_upper.append(upper) # 上轨
self.cur_upper2 = upper - upper % self.price_tick # 上轨取整
self.cur_upper2 = upper # 上轨取整
lower = middle - self.para_boll2_std_sate * std
lower = middle - self.para_boll2_std_rate * std
self.line_boll2_lower.append(lower) # 下轨
self.cur_lower2 = lower - lower % self.price_tick # 下轨取整
self.cur_lower2 = lower # 下轨取整
# 计算斜率
if len(self.line_boll2_upper) > 2 and self.line_boll2_upper[-2] != 0:
@ -2229,6 +2229,8 @@ class CtaLineBar(object):
if not (boll_01_len > 0 or boll_02_len > 0): # 不计算
return
rt_close_array = np.append(self.close_array, [self.line_bar[-1].close_price])
if boll_01_len > 0:
if self.bar_len < min(14, boll_01_len) + 1:
return
@ -2236,7 +2238,7 @@ class CtaLineBar(object):
bollLen = min(boll_01_len, self.bar_len)
if self.para_boll_tb_len == 0:
upper_list, middle_list, lower_list = ta.BBANDS(self.close_array[-bollLen:],
upper_list, middle_list, lower_list = ta.BBANDS(rt_close_array,
timeperiod=bollLen, nbdevup=self.para_boll_std_rate,
nbdevdn=self.para_boll_std_rate, matype=0)
@ -2247,8 +2249,8 @@ class CtaLineBar(object):
self._rt_lower = round(lower_list[-1], self.round_n)
else:
# 1标准差
std = np.std(np.append(self.close_array[-boll_01_len:], [self.line_bar[-1].close]), ddof=1)
middle = np.mean(np.append(self.close_array[-boll_01_len:], [self.line_bar[-1].close]))
std = np.std(rt_close_array[-boll_01_len:])
middle = np.mean(rt_close_array[-boll_01_len:])
self._rt_middle = round(middle, self.round_n)
upper = middle + self.para_boll_std_rate * std
self._rt_upper = round(upper, self.round_n)
@ -2275,19 +2277,20 @@ class CtaLineBar(object):
bollLen = min(boll_02_len, self.bar_len)
if self.para_boll2_tb_len == 0:
upper_list, middle_list, lower_list = ta.BBANDS(self.close_array[-bollLen:],
timeperiod=bollLen, nbdevup=self.para_boll_std_rate,
nbdevdn=self.para_boll_std_rate, matype=0)
upper_list, middle_list, lower_list = ta.BBANDS(
rt_close_array,
timeperiod=bollLen, nbdevup=self.para_boll2_std_rate,
nbdevdn=self.para_boll2_std_rate, matype=0)
# 1标准差
std = (upper_list[-1] - lower_list[-1]) / (self.para_boll2_std_sate * 2)
std = (upper_list[-1] - lower_list[-1]) / (self.para_boll2_std_rate * 2)
self._rt_upper2 = round(upper_list[-1], self.round_n)
self._rt_middle2 = round(middle_list[-1], self.round_n)
self._rt_lower2 = round(lower_list[-1], self.round_n)
else:
# 1标准差
std = np.std(np.append(self.close_array[-boll_02_len:], [self.line_bar[-1].close]), ddof=1)
middle = np.mean(np.append(self.close_array[-boll_02_len:], [self.line_bar[-1].close]))
std = np.std(rt_close_array[-bollLen:], ddof=1)
middle = np.mean(rt_close_array[-bollLen:])
self._rt_middle2 = round(middle, self.round_n)
upper = middle + self.para_boll_std_rate * std
self._rt_upper2 = round(upper, self.round_n)

View File

@ -4,7 +4,7 @@
"mi_symbol": "a2005",
"full_symbol": "A2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.06,
"symbol_size": 10,
"price_tick": 1.0
},
@ -13,7 +13,7 @@
"mi_symbol": "ag2007",
"full_symbol": "AG2007",
"exchange": "SHFE",
"margin_rate": 0.08,
"margin_rate": 0.09,
"symbol_size": 15,
"price_tick": 1.0
},
@ -31,7 +31,7 @@
"mi_symbol": "AP005",
"full_symbol": "AP2005",
"exchange": "CZCE",
"margin_rate": 0.07,
"margin_rate": 0.08,
"symbol_size": 10,
"price_tick": 1.0
},
@ -67,7 +67,7 @@
"mi_symbol": "bu2006",
"full_symbol": "BU2006",
"exchange": "SHFE",
"margin_rate": 0.1,
"margin_rate": 0.11,
"symbol_size": 10,
"price_tick": 2.0
},
@ -85,7 +85,7 @@
"mi_symbol": "CF009",
"full_symbol": "CF2009",
"exchange": "CZCE",
"margin_rate": 0.05,
"margin_rate": 0.07,
"symbol_size": 5,
"price_tick": 5.0
},
@ -112,7 +112,7 @@
"mi_symbol": "cu2004",
"full_symbol": "CU2004",
"exchange": "SHFE",
"margin_rate": 0.09,
"margin_rate": 0.1,
"symbol_size": 5,
"price_tick": 10.0
},
@ -121,7 +121,7 @@
"mi_symbol": "CY005",
"full_symbol": "CY2005",
"exchange": "CZCE",
"margin_rate": 0.05,
"margin_rate": 0.07,
"symbol_size": 5,
"price_tick": 5.0
},
@ -130,7 +130,7 @@
"mi_symbol": "eb2005",
"full_symbol": "EB2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.11,
"symbol_size": 5,
"price_tick": 1.0
},
@ -139,7 +139,7 @@
"mi_symbol": "eg2005",
"full_symbol": "EG2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.11,
"symbol_size": 10,
"price_tick": 1.0
},
@ -148,9 +148,9 @@
"mi_symbol": "fb2005",
"full_symbol": "FB2005",
"exchange": "DCE",
"margin_rate": 0.2,
"symbol_size": 500,
"price_tick": 0.05
"margin_rate": 0.1,
"symbol_size": 10,
"price_tick": 0.5
},
"FG": {
"underlying_symbol": "FG",
@ -166,7 +166,7 @@
"mi_symbol": "fu2005",
"full_symbol": "FU2005",
"exchange": "SHFE",
"margin_rate": 0.2,
"margin_rate": 0.11,
"symbol_size": 10,
"price_tick": 1.0
},
@ -175,7 +175,7 @@
"mi_symbol": "hc2005",
"full_symbol": "HC2005",
"exchange": "SHFE",
"margin_rate": 0.1,
"margin_rate": 0.09,
"symbol_size": 10,
"price_tick": 1.0
},
@ -184,7 +184,7 @@
"mi_symbol": "i2005",
"full_symbol": "I2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.08,
"symbol_size": 100,
"price_tick": 0.5
},
@ -220,7 +220,7 @@
"mi_symbol": "j2005",
"full_symbol": "J2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.08,
"symbol_size": 100,
"price_tick": 0.5
},
@ -229,7 +229,7 @@
"mi_symbol": "jd2005",
"full_symbol": "JD2005",
"exchange": "DCE",
"margin_rate": 0.08,
"margin_rate": 0.09,
"symbol_size": 10,
"price_tick": 1.0
},
@ -238,7 +238,7 @@
"mi_symbol": "jm2005",
"full_symbol": "JM2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.08,
"symbol_size": 60,
"price_tick": 0.5
},
@ -256,7 +256,7 @@
"mi_symbol": "l2005",
"full_symbol": "L2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.07,
"symbol_size": 5,
"price_tick": 5.0
},
@ -274,7 +274,7 @@
"mi_symbol": "m2005",
"full_symbol": "M2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.06,
"symbol_size": 10,
"price_tick": 1.0
},
@ -301,7 +301,7 @@
"mi_symbol": "nr2004",
"full_symbol": "NR2004",
"exchange": "INE",
"margin_rate": 0.09,
"margin_rate": 0.11,
"symbol_size": 10,
"price_tick": 5.0
},
@ -319,14 +319,14 @@
"mi_symbol": "p2005",
"full_symbol": "P2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.07,
"symbol_size": 10,
"price_tick": 2.0
},
"PB": {
"underlying_symbol": "PB",
"mi_symbol": "pb2003",
"full_symbol": "PB2003",
"mi_symbol": "pb2006",
"full_symbol": "PB2006",
"exchange": "SHFE",
"margin_rate": 0.1,
"symbol_size": 5,
@ -346,7 +346,7 @@
"mi_symbol": "pp2005",
"full_symbol": "PP2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.07,
"symbol_size": 5,
"price_tick": 1.0
},
@ -355,7 +355,7 @@
"mi_symbol": "rb2005",
"full_symbol": "RB2005",
"exchange": "SHFE",
"margin_rate": 0.1,
"margin_rate": 0.09,
"symbol_size": 10,
"price_tick": 1.0
},
@ -373,7 +373,7 @@
"mi_symbol": "RM005",
"full_symbol": "RM2005",
"exchange": "CZCE",
"margin_rate": 0.05,
"margin_rate": 0.06,
"symbol_size": 10,
"price_tick": 1.0
},
@ -391,7 +391,7 @@
"mi_symbol": "RS011",
"full_symbol": "RS2011",
"exchange": "CZCE",
"margin_rate": 0.05,
"margin_rate": 0.2,
"symbol_size": 10,
"price_tick": 1.0
},
@ -400,7 +400,7 @@
"mi_symbol": "ru2005",
"full_symbol": "RU2005",
"exchange": "SHFE",
"margin_rate": 0.1,
"margin_rate": 0.11,
"symbol_size": 10,
"price_tick": 5.0
},
@ -418,7 +418,7 @@
"mi_symbol": "sc2004",
"full_symbol": "SC2004",
"exchange": "INE",
"margin_rate": 0.05,
"margin_rate": 0.2,
"symbol_size": 1000,
"price_tick": 0.1
},
@ -427,7 +427,7 @@
"mi_symbol": "SF005",
"full_symbol": "SF2005",
"exchange": "CZCE",
"margin_rate": 0.05,
"margin_rate": 0.07,
"symbol_size": 5,
"price_tick": 2.0
},
@ -436,7 +436,7 @@
"mi_symbol": "SM005",
"full_symbol": "SM2005",
"exchange": "CZCE",
"margin_rate": 0.05,
"margin_rate": 0.07,
"symbol_size": 5,
"price_tick": 2.0
},
@ -445,7 +445,7 @@
"mi_symbol": "sn2006",
"full_symbol": "SN2006",
"exchange": "SHFE",
"margin_rate": 0.09,
"margin_rate": 0.1,
"symbol_size": 1,
"price_tick": 10.0
},
@ -454,7 +454,7 @@
"mi_symbol": "sp2005",
"full_symbol": "SP2005",
"exchange": "SHFE",
"margin_rate": 0.07,
"margin_rate": 0.08,
"symbol_size": 10,
"price_tick": 2.0
},
@ -472,7 +472,7 @@
"mi_symbol": "ss2006",
"full_symbol": "SS2006",
"exchange": "SHFE",
"margin_rate": 0.08,
"margin_rate": 0.09,
"symbol_size": 5,
"price_tick": 5.0
},
@ -490,14 +490,14 @@
"mi_symbol": "TA005",
"full_symbol": "TA2005",
"exchange": "CZCE",
"margin_rate": 0.05,
"margin_rate": 0.07,
"symbol_size": 5,
"price_tick": 2.0
},
"TF": {
"underlying_symbol": "TF",
"mi_symbol": "TF2003",
"full_symbol": "TF2003",
"mi_symbol": "TF2004",
"full_symbol": "TF2004",
"exchange": "CFFEX",
"margin_rate": 0.012,
"symbol_size": 10000,
@ -526,7 +526,7 @@
"mi_symbol": "v2005",
"full_symbol": "V2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.1,
"symbol_size": 5,
"price_tick": 5.0
},
@ -535,7 +535,7 @@
"mi_symbol": "WH011",
"full_symbol": "WH2011",
"exchange": "CZCE",
"margin_rate": 0.05,
"margin_rate": 0.07,
"symbol_size": 20,
"price_tick": 1.0
},
@ -544,7 +544,7 @@
"mi_symbol": "wr2101",
"full_symbol": "WR2101",
"exchange": "SHFE",
"margin_rate": 0.2,
"margin_rate": 0.09,
"symbol_size": 10,
"price_tick": 1.0
},
@ -553,7 +553,7 @@
"mi_symbol": "y2005",
"full_symbol": "Y2005",
"exchange": "DCE",
"margin_rate": 0.05,
"margin_rate": 0.06,
"symbol_size": 10,
"price_tick": 2.0
},
@ -562,14 +562,14 @@
"mi_symbol": "ZC005",
"full_symbol": "ZC2005",
"exchange": "CZCE",
"margin_rate": 0.05,
"margin_rate": 0.06,
"symbol_size": 100,
"price_tick": 0.2
},
"ZN": {
"underlying_symbol": "ZN",
"mi_symbol": "zn2003",
"full_symbol": "ZN2003",
"mi_symbol": "zn2005",
"full_symbol": "ZN2005",
"exchange": "SHFE",
"margin_rate": 0.1,
"symbol_size": 5,

View File

@ -11,6 +11,20 @@ from vnpy.trader.utility import load_json, save_json
# 期货的配置文件
TDX_FUTURE_CONFIG = 'tdx_future_config.json'
# 股票的配置文件
# 存储格式 dict{
# "cache_time": datetime,
# "symbol_dict": {
# "symbol_marketid": {
# 'code', '395001',
# 'volunit', 100,
# 'decimal_point', 2,
# 'name', '主板A股',
# 'pre_close', 458.0,
# 'exchagne','SZSE',
# 'stock_type', 'index_cn',
# 'market_id', 0
# }
# } }
TDX_STOCK_CONFIG = 'tdx_stock_config.pkb2'
@ -112,6 +126,64 @@ def save_cache_json(data_dict: dict, json_file_name: str):
save_json(filename=config_file_name, data=data_dict)
def get_stock_type(code):
"""获取股票得分类"""
market_id = get_tdx_market_code(code)
if market_id == 0:
return get_stock_type_sz(code)
else:
return get_stock_type_sh(code)
def get_stock_type_sz(code):
"""深市代码分类
Arguments:
code {[type]} -- [description]
Returns:
[type] -- [description]
"""
if str(code)[0:2] in ['00', '30', '02']:
return 'stock_cn'
elif str(code)[0:2] in ['39']:
return 'index_cn'
elif str(code)[0:2] in ['15']:
return 'etf_cn'
elif str(code)[0:2] in ['10', '11', '13']:
# 10xxxx 国债现货
# 11xxxx 债券
# 12xxxx 国债回购
return 'bond_cn'
elif str(code)[0:2] in ['12']:
# 12xxxx 可转换债券
return 'cb_cn'
elif str(code)[0:2] in ['20']:
return 'stockB_cn'
else:
return 'undefined'
def get_stock_type_sh(code):
if str(code)[0] == '6':
return 'stock_cn'
elif str(code)[0:3] in ['000', '880']:
return 'index_cn'
elif str(code)[0:2] == '51':
return 'etf_cn'
# 110×××120×××企业债券
# 129×××100×××可转换债券
elif str(code)[0:3] in ["009", "112", '120', "132", "204"]:
return 'bond_cn'
elif str(code)[0:3] in ["110", "113", "121", "122", "126",
"130", "181", "190", "191", "192", "201", "202", "203"]:
return 'cb_cn'
else:
return 'undefined'
class FakeStrategy(object):
"""制作一个假得策略,用于测试"""

View File

@ -241,6 +241,7 @@ class TdxFutureData(object):
self.symbol_exchange_dict.update({tdx_symbol: Tdx_Vn_Exchange_Map.get(str(tdx_market_id))})
self.symbol_market_dict.update({tdx_symbol: tdx_market_id})
# ----------------------------------------------------------------------
def get_bars(self,
symbol: str,
@ -292,7 +293,7 @@ class TdxFutureData(object):
end_date = end_dt
if qry_start_date > end_date:
qry_start_date = end_date
self.write_log('{}开始下载tdx:{} {}数据, {} to {}.'
self.write_log('{}开始下载tdx:{},周期类型:{}数据, {} to {}.'
.format(datetime.now(), tdx_symbol, period, qry_start_date, end_date))
# print('{}开始下载tdx:{} {}数据, {} to {}.'.format(datetime.now(), tdx_symbol, tdx_period, last_date, end_date))

View File

@ -28,6 +28,7 @@ from vnpy.data.tdx.tdx_common import (
get_tdx_market_code,
get_cache_config,
save_cache_config,
get_stock_type,
TDX_STOCK_CONFIG)
# 每个周期包含多少分钟
@ -58,6 +59,8 @@ TDX_RQ_STOCK_MARKET_MAP = {
RQ_TDX_STOCK_MARKET_MAP = {v: k for k, v in TDX_RQ_STOCK_MARKET_MAP.items()}
# 本地缓存文件
class TdxStockData(object):
def __init__(self, strategy=None):
@ -139,6 +142,12 @@ class TdxStockData(object):
continue
for security in security_list:
tdx_symbol = security.get('code', None)
exchange = Exchange.SZSE.value if market_id == 0 else Exchange.SSE.value
stock_type = get_stock_type(tdx_symbol)
security.update({'market_id': market_id})
security.update({'stock_type': stock_type})
security.update({'exchange': exchange})
if tdx_symbol:
self.symbol_dict.update({f'{tdx_symbol}_{market_id}': security})
@ -170,13 +179,21 @@ class TdxStockData(object):
return results
def get_name(self, code, market_id):
symbol_info = self.symbol_dict.get(f'{code}_{market_id}')
if symbol_info:
return symbol_info.get('name', code)
return code
# ----------------------------------------------------------------------
def get_bars(self,
symbol: str,
period: str,
callback=None,
bar_freq: int = 1,
start_dt: datetime = None):
start_dt: datetime = None,
return_bar: bool = True):
"""
返回k线数据
symbol股票 000001.XG
@ -192,14 +209,15 @@ class TdxStockData(object):
if '.' in symbol:
tdx_code, market_str = symbol.split('.')
# 1, 上交所 0 深交所
market_code = 1 if market_str.upper() in ['XSHG', Exchange.SSE.value] else 0
market_id = 1 if market_str.upper() in ['XSHG', Exchange.SSE.value] else 0
self.symbol_exchange_dict.update({tdx_code: symbol}) # tdx合约与vn交易所的字典
self.symbol_market_dict.update({tdx_code: market_code}) # tdx合约与tdx市场的字典
self.symbol_market_dict.update({tdx_code: market_id}) # tdx合约与tdx市场的字典
else:
market_code = get_tdx_market_code(symbol)
market_id = get_tdx_market_code(symbol)
tdx_code = symbol
self.symbol_exchange_dict.update({symbol: symbol}) # tdx合约与vn交易所的字典
self.symbol_market_dict.update({symbol: market_code}) # tdx合约与tdx市场的字典
self.symbol_market_dict.update({symbol: market_id}) # tdx合约与tdx市场的字典
name = self.get_name(tdx_code, market_id)
# period => tdx_period
if period not in PERIOD_MAPPING.keys():
@ -220,8 +238,8 @@ class TdxStockData(object):
if qry_start_date > qry_end_date:
qry_start_date = qry_end_date
self.write_log('{}开始下载tdx股票:{} {}数据, {} to {}.'
.format(datetime.now(), tdx_code, tdx_period, qry_start_date, qry_end_date))
self.write_log('{}开始下载tdx股票: {},代码:{} {}数据, {} to {}.'
.format(datetime.now(), name, tdx_code, tdx_period, qry_start_date, qry_end_date))
try:
_start_date = qry_end_date
@ -230,7 +248,7 @@ class TdxStockData(object):
while _start_date > qry_start_date:
_res = self.api.get_security_bars(
category=PERIOD_MAPPING[period],
market=market_code,
market=market_id,
code=tdx_code,
start=_pos,
count=QSIZE)
@ -273,43 +291,48 @@ class TdxStockData(object):
data['time'] = data['datetime'].apply(lambda x: (x.strftime('%H:%M:%S')))
data = data.set_index('datetime', drop=False)
for index, row in data.iterrows():
add_bar = BarData()
try:
add_bar.symbol = symbol
add_bar.datetime = index
add_bar.date = row['date']
add_bar.time = row['time']
add_bar.trading_date = row['trading_date']
add_bar.open_price = float(row['open'])
add_bar.high_price = float(row['high'])
add_bar.low_price = float(row['low'])
add_bar.close_price = float(row['close'])
add_bar.volume = float(row['volume'])
except Exception as ex:
self.write_error('error when convert bar:{},ex:{},t:{}'
.format(row, str(ex), traceback.format_exc()))
# print('error when convert bar:{},ex:{},t:{}'.format(row, str(ex), traceback.format_exc()))
return False
if return_bar:
self.write_log('dataframe => [BarData]')
for index, row in data.iterrows():
add_bar = BarData()
try:
add_bar.symbol = symbol
add_bar.datetime = index
add_bar.date = row['date']
add_bar.time = row['time']
add_bar.trading_date = row['trading_date']
add_bar.open_price = float(row['open'])
add_bar.high_price = float(row['high'])
add_bar.low_price = float(row['low'])
add_bar.close_price = float(row['close'])
add_bar.volume = float(row['volume'])
except Exception as ex:
self.write_error('error when convert bar:{},ex:{},t:{}'
.format(row, str(ex), traceback.format_exc()))
# print('error when convert bar:{},ex:{},t:{}'.format(row, str(ex), traceback.format_exc()))
return False, ret_bars
if start_dt is not None and index < start_dt:
continue
ret_bars.append(add_bar)
if start_dt is not None and index < start_dt:
continue
ret_bars.append(add_bar)
if callback is not None:
freq = bar_freq
bar_is_completed = True
if period != '1min' and index == data['datetime'][-1]:
# 最后一个bar可能是不完整的强制修改
# - 5min修改后freq基本正确
# - 1day在VNPY合成时不关心已经收到多少Bar, 所以影响也不大
# - 但其它分钟周期因为不好精确到每个品种, 修改后的freq可能有错
if index > current_datetime:
bar_is_completed = False
# 根据秒数算的话,要+1例如13:31,freq=31第31根bar
freq = NUM_MINUTE_MAPPING[period] - int((index - current_datetime).total_seconds() / 60)
callback(add_bar, bar_is_completed, freq)
if callback is not None:
freq = bar_freq
bar_is_completed = True
if period != '1min' and index == data['datetime'][-1]:
# 最后一个bar可能是不完整的强制修改
# - 5min修改后freq基本正确
# - 1day在VNPY合成时不关心已经收到多少Bar, 所以影响也不大
# - 但其它分钟周期因为不好精确到每个品种, 修改后的freq可能有错
if index > current_datetime:
bar_is_completed = False
# 根据秒数算的话,要+1例如13:31,freq=31第31根bar
freq = NUM_MINUTE_MAPPING[period] - int((index - current_datetime).total_seconds() / 60)
callback(add_bar, bar_is_completed, freq)
else:
self.write_log('dataframe => [ dict ]')
ret_bars = list(data.T.to_dict().values())
return True, ret_bars
except Exception as ex:
self.write_error('exception in get:{},{},{}'.format(tdx_code, str(ex), traceback.format_exc()))
@ -400,6 +423,9 @@ class TdxStockData(object):
self.symbol_exchange_dict.update({symbol: symbol}) # tdx合约与vn交易所的字典
self.symbol_market_dict.update({symbol: market_code}) # tdx合约与tdx市场的字典
symbol_config = self.symbol_dict.get(f'{tdx_code}_{market_code}', {})
decimal_point = symbol_config.get('decimal_point', 2)
q_size = QSIZE * 5
# 每秒 2个 10小时
max_data_size = 1000000
@ -462,6 +488,10 @@ class TdxStockData(object):
last_dt = last_dt + timedelta(seconds=1)
d.update({'datetime': last_dt})
d.update({'volume': d.pop('vol', 0)})
if decimal_point > 2:
price = round(d.get('price') / (10 ** (decimal_point - 2)), decimal_point)
d.update({'price': price})
d.update({'trading_date': last_dt.strftime('%Y-%m-%d')})
_datas = sorted(_datas, key=lambda s: s['datetime'])

View File

@ -693,10 +693,22 @@ class CtpTdApi(TdApi):
symbol = data["InstrumentID"]
exchange = symbol_exchange_map[symbol]
order_type = OrderType.LIMIT
if data["OrderPriceType"] == THOST_FTDC_OPT_LimitPrice and data["TimeCondition"] == THOST_FTDC_TC_IOC:
if data["VolumeCondition"] == THOST_FTDC_VC_AV:
order_type = OrderType.FAK
elif data["VolumeCondition"] == THOST_FTDC_VC_CV:
order_type = OrderType.FOK
if data["OrderPriceType"] == THOST_FTDC_OPT_AnyPrice:
order_type = OrderType.MARKET
order = OrderData(
symbol=symbol,
exchange=exchange,
orderid=orderid,
type=order_type,
direction=DIRECTION_CTP2VT[data["Direction"]],
offset=OFFSET_CTP2VT.get(data["CombOffsetFlag"], Offset.NONE),
price=data["LimitPrice"],
@ -913,12 +925,22 @@ class CtpTdApi(TdApi):
order_ref = data["OrderRef"]
orderid = f"{frontid}_{sessionid}_{order_ref}"
order_type = OrderType.LIMIT
if data["OrderPriceType"] == THOST_FTDC_OPT_LimitPrice and data["TimeCondition"] == THOST_FTDC_TC_IOC:
if data["VolumeCondition"] == THOST_FTDC_VC_AV:
order_type = OrderType.FAK
elif data["VolumeCondition"] == THOST_FTDC_VC_CV:
order_type = OrderType.FOK
if data["OrderPriceType"] == THOST_FTDC_OPT_AnyPrice:
order_type = OrderType.MARKET
order = OrderData(
symbol=symbol,
exchange=exchange,
orderid=orderid,
sys_orderid=data.get('OrderSysID', ""),
type=ORDERTYPE_CTP2VT[data["OrderPriceType"]],
type=order_type,
direction=DIRECTION_CTP2VT[data["Direction"]],
offset=OFFSET_CTP2VT[data["CombOffsetFlag"]],
price=data["LimitPrice"],

View File

@ -25,8 +25,8 @@ class OffsetConverter:
def update_position(self, position: PositionData) -> None:
""""""
if not self.is_convert_required(position.vt_symbol):
return
# if not self.is_convert_required(position.vt_symbol):
# return
holding = self.get_position_holding(position.vt_symbol, position.gateway_name)
holding.update_position(position)
@ -57,6 +57,10 @@ class OffsetConverter:
def get_position_holding(self, vt_symbol: str, gateway_name: str = '') -> "PositionHolding":
"""获取持仓信息"""
if len(gateway_name) == 0:
contract = self.main_engine.get_contract(vt_symbol)
if contract:
gateway_name = contract.gateway_name
k = f'{gateway_name}.{vt_symbol}'
holding = self.holdings.get(k, None)
if not holding:

View File

@ -9,7 +9,7 @@ import os
import csv
import re
from pathlib import Path
from typing import Callable, Dict, Tuple, Union
from typing import Callable, Dict, Tuple, Union, Any
from decimal import Decimal
from math import floor, ceil
from time import time
@ -17,6 +17,8 @@ from datetime import datetime, timedelta
from functools import wraps, lru_cache
import numpy as np
import talib
import pickle
import bz2
from .object import BarData, TickData
from .constant import Exchange, Interval
@ -615,6 +617,21 @@ def display_dual_axis(df, columns1, columns2=[], invert_yaxis1=False, invert_yax
plt.show()
def load_data_from_pkb2(pkb2_file_name):
"""获取本地压缩的数据"""
data = None
if not os.path.exists(pkb2_file_name):
return data
with bz2.BZ2File(pkb2_file_name, 'rb') as f:
data = pickle.load(f)
return data
def save_data_to_pkb2(data: Any, pkb2_file_name):
"""保存本地缓存的配置地址信息"""
with bz2.BZ2File(pkb2_file_name, 'wb') as f:
pickle.dump(data, f)
class BarGenerator:
"""
For: