Skip to content

Commit

Permalink
[增强功能] 回测引擎增加跨品种套利bar模式; 价差行情模块移动=> gateway.py; kline增加缠论支持
Browse files Browse the repository at this point in the history
  • Loading branch information
msincenselee committed Oct 22, 2020
1 parent ce1a85b commit bd7280b
Show file tree
Hide file tree
Showing 13 changed files with 2,194 additions and 429 deletions.
1 change: 1 addition & 0 deletions vnpy/app/cta_strategy_pro/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .template import (
Direction,
Offset,
Exchange,
Status,
Color,
TickData,
Expand Down
56 changes: 37 additions & 19 deletions vnpy/app/cta_strategy_pro/back_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1240,7 +1240,7 @@ def convert_spd_trade(self, trade):
active_exchange = self.get_exchange(active_symbol)
active_vt_symbol = active_symbol + '.' + active_exchange.value
passive_exchange = self.get_exchange(passive_symbol)
# passive_vt_symbol = active_symbol + '.' + passive_exchange.value
passive_vt_symbol = passive_symbol + '.' + passive_exchange.value
# 主动腿成交记录
act_trade = TradeData(gateway_name=self.gateway_name,
symbol=active_symbol,
Expand Down Expand Up @@ -1438,10 +1438,10 @@ def realtime_calculate(self):
# 如果当前没有空单,属于异常行为
if len(self.short_position_list) == 0:
self.write_error(u'异常!没有空单持仓,不能cover')
raise Exception(u'异常!没有空单持仓,不能cover')
# raise Exception(u'异常!没有空单持仓,不能cover')
return

cur_short_pos_list = [s_pos.volume for s_pos in self.short_position_list]
cur_short_pos_list = [s_pos.volume for s_pos in self.short_position_list if s_pos.vt_symbol == trade.vt_symbol]

self.write_log(u'{}当前空单:{}'.format(trade.vt_symbol, cur_short_pos_list))

Expand All @@ -1450,9 +1450,13 @@ def realtime_calculate(self):
val.vt_symbol == trade.vt_symbol and val.strategy_name == trade.strategy_name]

if len(pop_indexs) < 1:
self.write_error(u'异常,{}没有对应symbol:{}的空单持仓'.format(trade.strategy_name, trade.vt_symbol))
raise Exception(u'realtimeCalculate2() Exception,没有对应symbol:{0}的空单持仓'.format(trade.vt_symbol))
return
if 'spd' in vt_tradeid:
self.write_error(f'没有{trade.strategy_name}对应的symbol:{trade.vt_symbol}的空单持仓, 继续')
break
else:
self.write_error(u'异常,{}没有对应symbol:{}的空单持仓, 终止'.format(trade.strategy_name, trade.vt_symbol))
# raise Exception(u'realtimeCalculate2() Exception,没有对应symbol:{0}的空单持仓'.format(trade.vt_symbol))
return

pop_index = pop_indexs[0]
# 从未平仓的空头交易
Expand Down Expand Up @@ -1494,7 +1498,7 @@ def realtime_calculate(self):
self.trade_pnl_list.append(t)

# 非自定义套利对,才更新到策略盈亏
if not open_trade.vt_symbol.endswith('SPD'):
if not (open_trade.vt_symbol.endswith('SPD') or open_trade.vt_symbol.endswith('SPD99')):
# 更新策略实例的累加盈亏
self.pnl_strategy_dict.update(
{open_trade.strategy_name: self.pnl_strategy_dict.get(open_trade.strategy_name,
Expand All @@ -1506,7 +1510,9 @@ def realtime_calculate(self):
open_trade.volume, result.pnl, result.commission)

self.write_log(msg)
result_list.append(result)

# 添加到交易结果汇总
result_list.append(result)

if g_result is None:
if cover_volume > 0:
Expand Down Expand Up @@ -1569,6 +1575,9 @@ def realtime_calculate(self):

self.write_log(msg)

# 添加到交易结果汇总
result_list.append(result)

# 更新(减少)开仓单的volume,重新推进开仓单列表中
open_trade.volume = remain_volume
self.write_log(u'更新(减少)开仓单的volume,重新推进开仓单列表中:{}'.format(open_trade.volume))
Expand All @@ -1577,7 +1586,7 @@ def realtime_calculate(self):
self.write_log(u'当前空单:{}'.format(cur_short_pos_list))

cover_volume = 0
result_list.append(result)


if g_result is not None:
# 更新组合的数据
Expand Down Expand Up @@ -1606,18 +1615,21 @@ def realtime_calculate(self):
while sell_volume > 0:
if len(self.long_position_list) == 0:
self.write_error(f'异常,没有{trade.vt_symbol}的多仓')
raise RuntimeError(u'realtimeCalculate2() Exception,没有开多单')
# raise RuntimeError(u'realtimeCalculate2() Exception,没有开多单')
return

pop_indexs = [i for i, val in enumerate(self.long_position_list) if
val.vt_symbol == trade.vt_symbol and val.strategy_name == trade.strategy_name]
if len(pop_indexs) < 1:
self.write_error(f'没有{trade.strategy_name}对应的symbol{trade.vt_symbol}多单数据,')
raise RuntimeError(
f'realtimeCalculate2() Exception,没有对应的symbol{trade.vt_symbol}多单数据,')
return
if 'spd' in vt_tradeid:
self.write_error(f'没有{trade.strategy_name}对应的symbol:{trade.vt_symbol}多单数据, 继续')
break
else:
self.write_error(f'没有{trade.strategy_name}对应的symbol:{trade.vt_symbol}多单数据, 终止')
# raise RuntimeError(f'realtimeCalculate2() Exception,没有对应的symbol:{trade.vt_symbol}多单数据,')
return

cur_long_pos_list = [s_pos.volume for s_pos in self.long_position_list]
cur_long_pos_list = [s_pos.volume for s_pos in self.long_position_list if s_pos.vt_symbol == trade.vt_symbol]

self.write_log(u'{}当前多单:{}'.format(trade.vt_symbol, cur_long_pos_list))

Expand Down Expand Up @@ -1669,7 +1681,9 @@ def realtime_calculate(self):
open_trade.volume, result.pnl, result.commission)

self.write_log(msg)
result_list.append(result)

# 添加到交易结果汇总
result_list.append(result)

if g_result is None:
if sell_volume > 0:
Expand Down Expand Up @@ -1728,13 +1742,14 @@ def realtime_calculate(self):
result.commission)

self.write_log(msg)
# 添加到交易结果汇总
result_list.append(result)

# 减少开多volume,重新推进多单持仓列表中
open_trade.volume = remain_volume
self.long_position_list.append(open_trade)

sell_volume = 0
result_list.append(result)

if g_result is not None:
# 更新组合的数据
Expand Down Expand Up @@ -1786,8 +1801,11 @@ def realtime_calculate(self):
continue
# 当前空单保证金
if self.use_margin:
cur_occupy_money = max(self.get_price(t.vt_symbol), t.price) * abs(t.volume) * self.get_size(
t.vt_symbol) * self.get_margin_rate(t.vt_symbol)
try:
cur_occupy_money = max(self.get_price(t.vt_symbol), t.price) * abs(t.volume) * self.get_size(
t.vt_symbol) * self.get_margin_rate(t.vt_symbol)
except Exception as ex:
self.write_error(ex)
else:
cur_occupy_money = self.get_price(t.vt_symbol) * abs(t.volume) * self.get_size(
t.vt_symbol) * self.get_margin_rate(t.vt_symbol)
Expand Down
79 changes: 48 additions & 31 deletions vnpy/app/cta_strategy_pro/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,10 @@ def subscribe_symbol(self, strategy_name: str, vt_symbol: str, gateway_name: str

return True

@lru_cache()
def get_exchange(self, symbol):
return self.main_engine.get_exchange(symbol)

@lru_cache()
def get_name(self, vt_symbol: str):
"""查询合约的name"""
Expand Down Expand Up @@ -868,6 +872,9 @@ def get_price(self, vt_symbol: str):
def get_contract(self, vt_symbol):
return self.main_engine.get_contract(vt_symbol)

def get_custom_contract(self, vt_symbol):
return self.main_engine.get_custom_contract(vt_symbol.split('.')[0])

def get_all_contracts(self):
return self.main_engine.get_all_contracts()

Expand Down Expand Up @@ -986,38 +993,47 @@ def add_strategy(
"""
Add a new strategy.
"""
if strategy_name in self.strategies:
msg = f"创建策略失败,存在重名{strategy_name}"
self.write_log(msg=msg,
level=logging.CRITICAL)
return False, msg

strategy_class = self.classes.get(class_name, None)
if not strategy_class:
msg = f"创建策略失败,找不到策略类{class_name}"
self.write_log(msg=msg,
level=logging.CRITICAL)
return False, msg
try:
if strategy_name in self.strategies:
msg = f"创建策略失败,存在重名{strategy_name}"
self.write_log(msg=msg,
level=logging.CRITICAL)
return False, msg

strategy_class = self.classes.get(class_name, None)
if not strategy_class:
msg = f"创建策略失败,找不到策略类{class_name}"
self.write_log(msg=msg,
level=logging.CRITICAL)
return False, msg

self.write_log(f'开始添加策略类{class_name},实例名:{strategy_name}')
strategy = strategy_class(self, strategy_name, vt_symbol, setting)
self.strategies[strategy_name] = strategy

# Add vt_symbol to strategy map.
strategies = self.symbol_strategy_map[vt_symbol]
strategies.append(strategy)

self.write_log(f'开始添加策略类{class_name},实例名:{strategy_name}')
strategy = strategy_class(self, strategy_name, vt_symbol, setting)
self.strategies[strategy_name] = strategy
subscribe_symbol_set = self.strategy_symbol_map[strategy_name]
subscribe_symbol_set.add(vt_symbol)

# Add vt_symbol to strategy map.
strategies = self.symbol_strategy_map[vt_symbol]
strategies.append(strategy)
# Update to setting file.
self.update_strategy_setting(strategy_name, setting, auto_init, auto_start)

subscribe_symbol_set = self.strategy_symbol_map[strategy_name]
subscribe_symbol_set.add(vt_symbol)
self.put_strategy_event(strategy)

# Update to setting file.
self.update_strategy_setting(strategy_name, setting, auto_init, auto_start)
# 判断设置中是否由自动初始化和自动启动项目
if auto_init:
self.init_strategy(strategy_name, auto_start=auto_start)

self.put_strategy_event(strategy)
except Exception as ex:
msg = f'添加策略实例{strategy_name}失败,{str(ex)}'
self.write_error(msg)
self.write_error(traceback.format_exc())
self.send_wechat(msg)

# 判断设置中是否由自动初始化和自动启动项目
if auto_init:
self.init_strategy(strategy_name, auto_start=auto_start)
return False, f'添加策略实例{strategy_name}失败'

return True, f'成功添加{strategy_name}'

Expand Down Expand Up @@ -1789,7 +1805,7 @@ def compare_pos(self, strategy_pos_list=[], auto_balance=False):
# 其他期货:帐号多单 vs 除了多单, 空单 vs 空单
if vt_symbol.endswith(".CFFEX"):
diff_match = (symbol_pos.get('账号多单', 0) - symbol_pos.get('账号空单', 0)) == (
symbol_pos.get('策略多单', 0) - symbol_pos.get('策略空单', 0))
symbol_pos.get('策略多单', 0) - symbol_pos.get('策略空单', 0))
pos_match = symbol_pos.get('账号空单', 0) == symbol_pos.get('策略空单', 0) and \
symbol_pos.get('账号多单', 0) == symbol_pos.get('策略多单', 0)
match = diff_match
Expand All @@ -1803,11 +1819,12 @@ def compare_pos(self, strategy_pos_list=[], auto_balance=False):
symbol_pos.get('策略多单', 0),
symbol_pos.get('策略空单', 0)
))
diff_pos_dict.update({vt_symbol: {"long":symbol_pos.get('账号多单', 0) - symbol_pos.get('策略多单', 0),
"short":symbol_pos.get('账号空单', 0) - symbol_pos.get('策略空单', 0)}})
diff_pos_dict.update({vt_symbol: {"long": symbol_pos.get('账号多单', 0) - symbol_pos.get('策略多单', 0),
"short": symbol_pos.get('账号空单', 0) - symbol_pos.get('策略空单',
0)}})
else:
match = round(symbol_pos.get('账号空单', 0), 7) == round(symbol_pos.get('策略空单', 0), 7) and \
round(symbol_pos.get('账号多单', 0), 7) == round(symbol_pos.get('策略多单', 0), 7)
round(symbol_pos.get('账号多单', 0), 7) == round(symbol_pos.get('策略多单', 0), 7)
# 多空都一致
if match:
msg = u'{}多空都一致.{}\n'.format(vt_symbol, json.dumps(symbol_pos, indent=2, ensure_ascii=False))
Expand Down Expand Up @@ -1862,7 +1879,7 @@ def compare_pos(self, strategy_pos_list=[], auto_balance=False):
else:
self.write_log(u'账户持仓与策略一致')
if len(diff_pos_dict) > 0:
for k,v in diff_pos_dict.items():
for k, v in diff_pos_dict.items():
self.write_log(f'{k} 存在大于策略的轧差持仓:{v}')
return True, compare_info

Expand Down
2 changes: 1 addition & 1 deletion vnpy/app/cta_strategy_pro/portfolio_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def run_bar_test(self):
bar.high_price = float(bar_data['high'])
bar.low_price = float(bar_data['low'])
bar.volume = int(bar_data['volume'])
bar.open_interest = int(bar_data.get('open_interest', 0))
bar.open_interest = float(bar_data.get('open_interest', 0))
bar.date = bar_datetime.strftime('%Y-%m-%d')
bar.time = bar_datetime.strftime('%H:%M:%S')
str_td = str(bar_data.get('trading_day', ''))
Expand Down

0 comments on commit bd7280b

Please sign in to comment.