[增强功能] 一般更新

This commit is contained in:
msincenselee 2020-07-02 17:28:11 +08:00
parent 08175de6d0
commit 3a086af423
6 changed files with 120 additions and 78 deletions

View File

@ -519,6 +519,8 @@ class AccountRecorder(BaseEngine):
data = event.data data = event.data
dt = data.get('datetime') dt = data.get('datetime')
# db.today_strategy_pos.createIndex({'account_id':1,'strategy_group':1,'strategy_name':1,'date':1},{'name':'accountid_strategy_group_strategy_name_date'})
account_id = data.get('accountid') account_id = data.get('accountid')
fld = { fld = {
'account_id': account_id, 'account_id': account_id,

View File

@ -859,7 +859,8 @@ class CtaEngine(BaseEngine):
vt_symbol: str, vt_symbol: str,
days: int, days: int,
interval: Interval, interval: Interval,
callback: Callable[[BarData], None] callback: Callable[[BarData], None],
interval_num: int = 1
): ):
"""""" """"""
symbol, exchange = extract_vt_symbol(vt_symbol) symbol, exchange = extract_vt_symbol(vt_symbol)
@ -875,6 +876,7 @@ class CtaEngine(BaseEngine):
symbol=symbol, symbol=symbol,
exchange=exchange, exchange=exchange,
interval=interval, interval=interval,
interval_num=interval_num,
start=start, start=start,
end=end end=end
) )

View File

@ -109,8 +109,15 @@ class CtaEngine(BaseEngine):
""" """
super().__init__(main_engine, event_engine, APP_NAME) super().__init__(main_engine, event_engine, APP_NAME)
# 股票引擎得配置,包括
# "accountid" : "xxxx", 资金账号,一般用于推送消息时附带
# "strategy_group": "cta_strategy_pro", # 当前实例名。多个实例时,区分开
# "trade_2_wx": true # 是否交易记录转发至微信通知
# "event_log: false # 是否转发日志到event bus显示在图形界面
# "snapshot2file": false # 是否保存切片到文件
self.engine_config = {} self.engine_config = {}
# 是否激活 write_log写入event bus(比较耗资源)
self.event_log = False
self.strategy_setting = {} # strategy_name: dict self.strategy_setting = {} # strategy_name: dict
self.strategy_data = {} # strategy_name: dict self.strategy_data = {} # strategy_name: dict
@ -222,8 +229,8 @@ class CtaEngine(BaseEngine):
# 每5分钟检查一次 # 每5分钟检查一次
if dt.minute % 10 == 0: if dt.minute % 10 == 0:
# 比对仓位,使用上述获取得持仓信息,不用重复获取 # 比对仓位,使用上述获取得持仓信息,不用重复获取
#self.compare_pos(strategy_pos_list=copy(all_strategy_pos)) self.compare_pos(strategy_pos_list=copy(all_strategy_pos))
pass
# 推送到事件 # 推送到事件
self.put_all_strategy_pos_event(all_strategy_pos) self.put_all_strategy_pos_event(all_strategy_pos)
@ -1301,12 +1308,13 @@ class CtaEngine(BaseEngine):
self.write_log(f'{strategy_name}返回得K线切片数据为空') self.write_log(f'{strategy_name}返回得K线切片数据为空')
return return
# 剩下工作:保存本地文件/数据库 if self.engine_config.get('snapshot2file', False):
snapshot_folder = get_folder_path(f'data/snapshots/{strategy_name}') # 剩下工作:保存本地文件/数据库
snapshot_file = snapshot_folder.joinpath('{}.pkb2'.format(datetime.now().strftime('%Y%m%d_%H%M%S'))) snapshot_folder = get_folder_path(f'data/snapshots/{strategy_name}')
with bz2.BZ2File(str(snapshot_file), 'wb') as f: snapshot_file = snapshot_folder.joinpath('{}.pkb2'.format(datetime.now().strftime('%Y%m%d_%H%M%S')))
pickle.dump(snapshot, f) with bz2.BZ2File(str(snapshot_file), 'wb') as f:
self.write_log(u'切片保存成功:{}'.format(str(snapshot_file))) pickle.dump(snapshot, f)
self.write_log(u'切片保存成功:{}'.format(str(snapshot_file)))
# 通过事件方式传导到account_recorder # 通过事件方式传导到account_recorder
snapshot.update({ snapshot.update({
@ -1681,8 +1689,13 @@ class CtaEngine(BaseEngine):
Load setting file. Load setting file.
""" """
# 读取引擎得配置 # 读取引擎得配置
# "accountid" : "xxxx", 资金账号,一般用于推送消息时附带
# "strategy_group": "cta_strategy_pro", # 当前实例名。多个实例时,区分开
# "trade_2_wx": true # 是否交易记录转发至微信通知
# "event_log: false # 是否转发日志到event bus显示在图形界面
self.engine_config = load_json(self.engine_filename) self.engine_config = load_json(self.engine_filename)
# 是否产生event log 日志一般GUI界面才产生而且比好消耗资源)
self.event_log = self.engine_config.get('event_log', False)
# 读取策略得配置 # 读取策略得配置
self.strategy_setting = load_json(self.setting_filename) self.strategy_setting = load_json(self.setting_filename)
@ -1754,12 +1767,13 @@ class CtaEngine(BaseEngine):
""" """
Create cta engine log event. Create cta engine log event.
""" """
# 推送至全局CTA_LOG Event if self.event_log:
log = LogData(msg=f"{strategy_name}: {msg}" if strategy_name else msg, # 推送至全局CTA_LOG Event
gateway_name="CtaStrategy", log = LogData(msg=f"{strategy_name}: {msg}" if strategy_name else msg,
level=level) gateway_name="CtaStrategy",
event = Event(type=EVENT_CTA_LOG, data=log) level=level)
self.event_engine.put(event) event = Event(type=EVENT_CTA_LOG, data=log)
self.event_engine.put(event)
# 保存单独的策略日志 # 保存单独的策略日志
if strategy_name: if strategy_name:

View File

@ -565,7 +565,7 @@ class CtaStockTemplate(CtaTemplate):
"""初始化Policy""" """初始化Policy"""
self.write_log(u'init_policy(),初始化执行逻辑') self.write_log(u'init_policy(),初始化执行逻辑')
self.policy.load() self.policy.load()
self.write_log('{}'.format(json.dumps(self.policy.to_json(),indent=2, ensure_ascii=True))) self.write_log('{}'.format(json.dumps(self.policy.to_json(),indent=2, ensure_ascii=False)))
def init_position(self): def init_position(self):
""" """
@ -637,7 +637,7 @@ class CtaStockTemplate(CtaTemplate):
return pos return pos
def compare_pos(self): def compare_pos(self,auto_balance=False):
"""比较仓位""" """比较仓位"""
for vt_symbol, position in self.positions.items(): for vt_symbol, position in self.positions.items():
name = self.cta_engine.get_name(vt_symbol) name = self.cta_engine.get_name(vt_symbol)
@ -752,13 +752,13 @@ class CtaStockTemplate(CtaTemplate):
if len(grid.order_ids) > 0: if len(grid.order_ids) > 0:
self.write_log(f'剩余委托单号:{grid.order_ids}') self.write_log(f'剩余委托单号:{grid.order_ids}')
"""
# 网格的所有委托单已经执行完毕 # 网格的所有委托单已经执行完毕
if grid.volume <= grid.traded_volume: if grid.volume <= grid.traded_volume:
grid.order_status = False grid.order_status = False
if grid.volume < grid.traded_volume: if grid.volume < grid.traded_volume:
self.write_error(f'{order.vt_symbol} 已成交总量:{grid.traded_volume}超出{grid.volume}, 更新=>{grid.traded_volume}') self.write_error(f'{order.vt_symbol} 已成交总量:{grid.traded_volume}超出{grid.volume}, 更新=>{grid.traded_volume}')
grid.volume = grid.traded_volume grid.volume = grid.traded_volume
grid.traded_volume = 0
# 卖出完毕sell # 卖出完毕sell
if order.direction != Direction.LONG: if order.direction != Direction.LONG:
@ -774,10 +774,11 @@ class CtaStockTemplate(CtaTemplate):
# 开仓完毕( buy) # 开仓完毕( buy)
else: else:
grid.open_status = True grid.open_status = True
grid.traded_volume = 0
grid.open_time = self.cur_datetime grid.open_time = self.cur_datetime
self.write_log(f'买入{order.vt_symbol}完毕,总量:{grid.volume},最后一笔委托价:{order.price}' self.write_log(f'买入{order.vt_symbol}完毕,总量:{grid.volume},最后一笔委托价:{order.price}'
+ f',成交:{order.volume}') + f',成交:{order.volume}')
"""
self.gt.save() self.gt.save()
# 在策略得活动订单中,移除 # 在策略得活动订单中,移除
@ -872,6 +873,7 @@ class CtaStockTemplate(CtaTemplate):
return return
remove_gids = [] remove_gids = []
changed = False
# 多单网格逐一止损/止盈检查: # 多单网格逐一止损/止盈检查:
long_grids = self.gt.get_opened_grids(direction=Direction.LONG) long_grids = self.gt.get_opened_grids(direction=Direction.LONG)
for lg in long_grids: for lg in long_grids:
@ -896,7 +898,7 @@ class CtaStockTemplate(CtaTemplate):
lg.close_price, lg.close_price,
lg.open_price, lg.open_price,
lg.volume)) lg.volume))
changed = True
if lg.traded_volume > 0: if lg.traded_volume > 0:
lg.volume -= lg.traded_volume lg.volume -= lg.traded_volume
lg.traded_volume = 0 lg.traded_volume = 0
@ -910,6 +912,7 @@ class CtaStockTemplate(CtaTemplate):
lg.order_status = True lg.order_status = True
lg.close_status = True lg.close_status = True
self.write_log(f'{lg.vt_symbol}[{cn_name}] 数量:{lg.volume},准备卖出') self.write_log(f'{lg.vt_symbol}[{cn_name}] 数量:{lg.volume},准备卖出')
continue continue
# 止损 # 止损
@ -925,7 +928,7 @@ class CtaStockTemplate(CtaTemplate):
lg.stop_price, lg.stop_price,
lg.open_price, lg.open_price,
lg.volume)) lg.volume))
changed = True
if lg.traded_volume > 0: if lg.traded_volume > 0:
lg.volume -= lg.traded_volume lg.volume -= lg.traded_volume
lg.traded_volume = 0 lg.traded_volume = 0
@ -940,8 +943,9 @@ class CtaStockTemplate(CtaTemplate):
lg.close_status = True lg.close_status = True
self.write_log(f'{lg.vt_symbol}[{cn_name}] 数量:{lg.volume},准备卖出') self.write_log(f'{lg.vt_symbol}[{cn_name}] 数量:{lg.volume},准备卖出')
if len(remove_gids) > 0: if changed:
self.gt.remove_grids_by_ids(direction=Direction.LONG, ids=remove_gids) if len(remove_gids) > 0:
self.gt.remove_grids_by_ids(direction=Direction.LONG, ids=remove_gids)
self.gt.save() self.gt.save()
def tns_excute_sell_grids(self, vt_symbol=None): def tns_excute_sell_grids(self, vt_symbol=None):
@ -993,7 +997,7 @@ class CtaStockTemplate(CtaTemplate):
vt_symbol=ordering_grid.vt_symbol, vt_symbol=ordering_grid.vt_symbol,
direction=Direction.NET) direction=Direction.NET)
if acc_symbol_pos is None: if acc_symbol_pos is None:
self.write_error(u'当前{}持仓查询不到'.format(ordering_grid.vt_symbol)) self.write_error(f'{self.strategy_name}当前{ordering_grid.vt_symbol}持仓查询不到, 无法执行卖出')
return return
vt_symbol = ordering_grid.vt_symbol vt_symbol = ordering_grid.vt_symbol
@ -1038,10 +1042,10 @@ class CtaStockTemplate(CtaTemplate):
order_time=self.cur_datetime, order_time=self.cur_datetime,
grid=ordering_grid) grid=ordering_grid)
if vt_orderids is None or len(vt_orderids) == 0: if vt_orderids is None or len(vt_orderids) == 0:
self.write_error(f'委托卖出失败,{vt_symbol} 委托价:{sell_price} 数量:{sell_volume}') self.write_error(f'{vt_symbol} 委托卖出失败,委托价:{sell_price} 数量:{sell_volume}')
return return
else: else:
self.write_log(f'已委托卖出,{sell_volume},委托价:{sell_price}, 数量:{sell_volume}') self.write_log(f'{vt_symbol} 已委托卖出,{sell_volume},委托价:{sell_price}, 数量:{sell_volume}')
def tns_finish_sell_grid(self, grid): def tns_finish_sell_grid(self, grid):
@ -1177,7 +1181,7 @@ class CtaStockTemplate(CtaTemplate):
self.write_error(f'委托买入失败,{vt_symbol} 委托价:{buy_price} 数量:{buy_volume}') self.write_error(f'委托买入失败,{vt_symbol} 委托价:{buy_price} 数量:{buy_volume}')
return return
else: else:
self.write_error(f'{vt_orderids},已委托买入,{vt_symbol} 委托价:{buy_price} 数量:{buy_volume}') self.write_log(f'{self.strategy_name}, {vt_orderids},已委托买入,{vt_symbol} 委托价:{buy_price} 数量:{buy_volume}')
def tns_finish_buy_grid(self, grid): def tns_finish_buy_grid(self, grid):
""" """
@ -1185,7 +1189,7 @@ class CtaStockTemplate(CtaTemplate):
:return: :return:
""" """
self.write_log(u'事务完成买入网格:{},计划数量:{},计划价格:{},实际数量:{}' self.write_log(u'事务完成买入网格:{},计划数量:{},计划价格:{},实际数量:{}'
.format(grid.type, grid.volume, grid.openPrice, grid.traded_volume)) .format(grid.type, grid.volume, grid.open_price, grid.traded_volume))
if grid.volume != grid.traded_volume: if grid.volume != grid.traded_volume:
grid.volume = grid.traded_volume grid.volume = grid.traded_volume
grid.traded_volume = 0 grid.traded_volume = 0
@ -1276,15 +1280,15 @@ class CtaStockTemplate(CtaTemplate):
name = self.cta_engine.get_name(grid.vt_symbol) name = self.cta_engine.get_name(grid.vt_symbol)
if not grid.open_status and grid.order_status: if not grid.open_status and grid.order_status:
opening_info += f'网格{grid.type},买入状态:{name}[{grid.vt_symbol}], [已买入:{grid.traded_volume} => 目标:{grid.volume}, 委托时间:{grid.order_time}\n' opening_info += f'网格{grid.type},买入状态:{name}[{grid.vt_symbol}], 买入价:{grid.open_price} [已买入:{grid.traded_volume} => 目标:{grid.volume}, 委托时间:{grid.order_time}\n'
continue continue
if grid.open_status and not grid.close_status: if grid.open_status and not grid.close_status:
holding_info += f'网格{grid.type},持有状态:{name}[{grid.vt_symbol}],[数量:{grid.volume}, 开仓时间:{grid.open_time}]\n' holding_info += f'网格{grid.type},持有状态:{name}[{grid.vt_symbol}],买入价:{grid.open_price} [数量:{grid.volume}, 开仓时间:{grid.open_time}]\n'
continue continue
if grid.open_status and grid.close_status: if grid.open_status and grid.close_status:
closing_info += f'网格{grid.type},卖出状态:{name}[{grid.vt_symbol}], [已卖出:{grid.traded_volume} => 目标:{grid.volume}, 委托时间:{grid.order_time}\n' closing_info += f'网格{grid.type},卖出状态:{name}[{grid.vt_symbol}],卖出价:{grid.close_price} [已卖出:{grid.traded_volume} => 目标:{grid.volume}, 委托时间:{grid.order_time}\n'
if len(opening_info) > 0: if len(opening_info) > 0:
self.write_log(opening_info) self.write_log(opening_info)

View File

@ -114,8 +114,15 @@ class CtaEngine(BaseEngine):
:param event_engine: 事件引擎 :param event_engine: 事件引擎
""" """
super().__init__(main_engine, event_engine, APP_NAME) super().__init__(main_engine, event_engine, APP_NAME)
# 增强策略引擎得特殊参数配置
# "accountid" : "xxxx", 资金账号,一般用于推送消息时附带
# "strategy_group": "cta_strategy_pro", # 当前实例名。多个实例时,区分开
# "trade_2_wx": true # 是否交易记录转发至微信通知
# "event_log: false # 是否转发日志到event bus显示在图形界面
# "snapshot2file": false # 是否保存切片到文件
self.engine_config = {} self.engine_config = {}
# 是否激活 write_log写入event bus(比较耗资源)
self.event_log = False
self.strategy_setting = {} # strategy_name: dict self.strategy_setting = {} # strategy_name: dict
self.strategy_data = {} # strategy_name: dict self.strategy_data = {} # strategy_name: dict
@ -812,8 +819,8 @@ class CtaEngine(BaseEngine):
"""查询价格最小跳动""" """查询价格最小跳动"""
contract = self.main_engine.get_contract(vt_symbol) contract = self.main_engine.get_contract(vt_symbol)
if contract is None: if contract is None:
self.write_error(f'查询不到{vt_symbol}合约信息,缺省使用0.1作为价格跳动') self.write_error(f'查询不到{vt_symbol}合约信息,缺省使用1作为价格跳动')
return 0.1 return 1
return contract.pricetick return contract.pricetick
@ -1313,12 +1320,13 @@ class CtaEngine(BaseEngine):
self.write_log(f'{strategy_name}返回得K线切片数据为空') self.write_log(f'{strategy_name}返回得K线切片数据为空')
return return
# 剩下工作:保存本地文件/数据库 if self.engine_config.get('snapshot2file', False):
snapshot_folder = get_folder_path(f'data/snapshots/{strategy_name}') # 剩下工作:保存本地文件/数据库
snapshot_file = snapshot_folder.joinpath('{}.pkb2'.format(datetime.now().strftime('%Y%m%d_%H%M%S'))) snapshot_folder = get_folder_path(f'data/snapshots/{strategy_name}')
with bz2.BZ2File(str(snapshot_file), 'wb') as f: snapshot_file = snapshot_folder.joinpath('{}.pkb2'.format(datetime.now().strftime('%Y%m%d_%H%M%S')))
pickle.dump(snapshot, f) with bz2.BZ2File(str(snapshot_file), 'wb') as f:
self.write_log(u'切片保存成功:{}'.format(str(snapshot_file))) pickle.dump(snapshot, f)
self.write_log(u'切片保存成功:{}'.format(str(snapshot_file)))
# 通过事件方式传导到account_recorder # 通过事件方式传导到account_recorder
snapshot.update({ snapshot.update({
@ -1498,7 +1506,7 @@ class CtaEngine(BaseEngine):
spd_vt_symbol = pos.get('vt_symbol', None) spd_vt_symbol = pos.get('vt_symbol', None)
if spd_vt_symbol is not None and spd_vt_symbol.endswith('SPD'): if spd_vt_symbol is not None and spd_vt_symbol.endswith('SPD'):
spd_symbol, spd_exchange = extract_vt_symbol(spd_vt_symbol) spd_symbol, spd_exchange = extract_vt_symbol(spd_vt_symbol)
spd_setting = self.main_engine.get_all_custom_contracts().get(spd_symbol, None) spd_setting = self.main_engine.get_all_custom_contracts(rtn_setting=True).get(spd_symbol, None)
if spd_setting is None: if spd_setting is None:
self.write_error(u'获取不到:{}得设置信息,检查自定义合约配置文件'.format(spd_symbol)) self.write_error(u'获取不到:{}得设置信息,检查自定义合约配置文件'.format(spd_symbol))
@ -1511,13 +1519,13 @@ class CtaEngine(BaseEngine):
leg1_pos = {} leg1_pos = {}
leg1_pos.update({'symbol': spd_setting.get('leg1_symbol')}) leg1_pos.update({'symbol': spd_setting.get('leg1_symbol')})
leg1_pos.update({'vt_symbol': spd_setting.get('leg1_symbol')}) leg1_pos.update({'vt_symbol': '{}.{}'.format(spd_setting.get('leg1_symbol'), spd_setting.get('leg1_exchange'))})
leg1_pos.update({'direction': leg1_direction}) leg1_pos.update({'direction': leg1_direction})
leg1_pos.update({'volume': spd_setting.get('leg1_ratio', 1) * spd_volume}) leg1_pos.update({'volume': spd_setting.get('leg1_ratio', 1) * spd_volume})
leg2_pos = {} leg2_pos = {}
leg2_pos.update({'symbol': spd_setting.get('leg2_symbol')}) leg2_pos.update({'symbol': spd_setting.get('leg2_symbol')})
leg2_pos.update({'vt_symbol': spd_setting.get('leg2_symbol')}) leg2_pos.update({'vt_symbol': '{}.{}'.format(spd_setting.get('leg2_symbol'), spd_setting.get('leg2_exchange'))})
leg2_pos.update({'direction': leg2_direction}) leg2_pos.update({'direction': leg2_direction})
leg2_pos.update({'volume': spd_setting.get('leg2_ratio', 1) * spd_volume}) leg2_pos.update({'volume': spd_setting.get('leg2_ratio', 1) * spd_volume})
@ -1649,7 +1657,7 @@ class CtaEngine(BaseEngine):
continue continue
if holding.exchange == Exchange.SPD: if holding.exchange == Exchange.SPD:
continue continue
if '&' in holding.vt_symbol and (holding.vt_symbol.startswith('SP') or holding.vt_symbol.startswith('STG')): if '&' in holding.vt_symbol and (holding.vt_symbol.startswith('SP') or holding.vt_symbol.startswith('STG') or holding.vt_symbol.startswith('PRT')):
continue continue
compare_pos[vt_symbol] = OrderedDict( compare_pos[vt_symbol] = OrderedDict(
@ -1672,7 +1680,7 @@ class CtaEngine(BaseEngine):
vt_symbols.add(vt_symbol) vt_symbols.add(vt_symbol)
symbol_pos = compare_pos.get(vt_symbol, None) symbol_pos = compare_pos.get(vt_symbol, None)
if symbol_pos is None: if symbol_pos is None:
self.write_log(u'账号持仓信息获取不到{},创建一个'.format(vt_symbol)) # self.write_log(u'账号持仓信息获取不到{},创建一个'.format(vt_symbol))
symbol_pos = OrderedDict( symbol_pos = OrderedDict(
{ {
"账号空单": 0, "账号空单": 0,
@ -1700,9 +1708,8 @@ class CtaEngine(BaseEngine):
compare_info = '' compare_info = ''
for vt_symbol in sorted(vt_symbols): for vt_symbol in sorted(vt_symbols):
# 发送不一致得结果 # 发送不一致得结果
symbol_pos = compare_pos.pop(vt_symbol, None) symbol_pos = compare_pos.pop(vt_symbol, {})
if symbol_pos is None:
continue
d_long = { d_long = {
'account_id': self.engine_config.get('accountid', '-'), 'account_id': self.engine_config.get('accountid', '-'),
'vt_symbol': vt_symbol, 'vt_symbol': vt_symbol,
@ -1716,21 +1723,21 @@ class CtaEngine(BaseEngine):
'strategy_list': symbol_pos.get('空单策略', [])} 'strategy_list': symbol_pos.get('空单策略', [])}
# 多空都一致 # 多空都一致
if round(symbol_pos['账号空单'], 7) == round(symbol_pos['策略空单'], 7) and \ if round(symbol_pos.get('账号空单',0), 7) == round(symbol_pos.get('策略空单',0), 7) and \
round(symbol_pos['账号多单'], 7) == round(symbol_pos['策略多单'], 7): round(symbol_pos.get('账号多单',0), 7) == round(symbol_pos.get('策略多单',0), 7):
msg = u'{}多空都一致.{}\n'.format(vt_symbol, json.dumps(symbol_pos, indent=2, ensure_ascii=False)) msg = u'{}多空都一致.{}\n'.format(vt_symbol, json.dumps(symbol_pos, indent=2, ensure_ascii=False))
self.write_log(msg) self.write_log(msg)
compare_info += msg compare_info += msg
else: else:
pos_compare_result += '\n{}: '.format(vt_symbol) pos_compare_result += '\n{}: '.format(vt_symbol)
# 判断是多单不一致? # 判断是多单不一致?
diff_long_volume = round(symbol_pos['账号多单'], 7) - round(symbol_pos['策略多单'], 7) diff_long_volume = round(symbol_pos.get('账号多单',0), 7) - round(symbol_pos.get('策略多单',0), 7)
if diff_long_volume != 0: if diff_long_volume != 0:
msg = '{}多单[账号({}), 策略{},共({})], ' \ msg = '{}多单[账号({}), 策略{},共({})], ' \
.format(vt_symbol, .format(vt_symbol,
symbol_pos['账号多单'], symbol_pos.get('账号多单'),
symbol_pos['多单策略'], symbol_pos.get('多单策略'),
symbol_pos['策略多单']) symbol_pos.get('策略多单'))
pos_compare_result += msg pos_compare_result += msg
self.write_error(u'{}不一致:{}'.format(vt_symbol, msg)) self.write_error(u'{}不一致:{}'.format(vt_symbol, msg))
@ -1739,14 +1746,14 @@ class CtaEngine(BaseEngine):
self.balance_pos(vt_symbol, Direction.LONG, diff_long_volume) self.balance_pos(vt_symbol, Direction.LONG, diff_long_volume)
# 判断是空单不一致: # 判断是空单不一致:
diff_short_volume = round(symbol_pos['账号空单'], 7) - round(symbol_pos['策略空单'], 7) diff_short_volume = round(symbol_pos.get('账号空单',0), 7) - round(symbol_pos.get('策略空单',0), 7)
if diff_short_volume != 0: if diff_short_volume != 0:
msg = '{}空单[账号({}), 策略{},共({})], ' \ msg = '{}空单[账号({}), 策略{},共({})], ' \
.format(vt_symbol, .format(vt_symbol,
symbol_pos['账号空单'], symbol_pos.get('账号空单'),
symbol_pos['空单策略'], symbol_pos.get('空单策略'),
symbol_pos['策略空单']) symbol_pos.get('策略空单'))
pos_compare_result += msg pos_compare_result += msg
self.write_error(u'{}不一致:{}'.format(vt_symbol, msg)) self.write_error(u'{}不一致:{}'.format(vt_symbol, msg))
compare_info += u'{}不一致:{}\n'.format(vt_symbol, msg) compare_info += u'{}不一致:{}\n'.format(vt_symbol, msg)
@ -1841,6 +1848,8 @@ class CtaEngine(BaseEngine):
""" """
# 读取引擎得配置 # 读取引擎得配置
self.engine_config = load_json(self.engine_filename) self.engine_config = load_json(self.engine_filename)
# 是否产生event log 日志一般GUI界面才产生而且比好消耗资源)
self.event_log = self.engine_config.get('event_log', False)
# 读取策略得配置 # 读取策略得配置
self.strategy_setting = load_json(self.setting_filename) self.strategy_setting = load_json(self.setting_filename)
@ -1913,12 +1922,13 @@ class CtaEngine(BaseEngine):
""" """
Create cta engine log event. Create cta engine log event.
""" """
# 推送至全局CTA_LOG Event if self.event_log:
log = LogData(msg=f"{strategy_name}: {msg}" if strategy_name else msg, # 推送至全局CTA_LOG Event
gateway_name="CtaStrategy", log = LogData(msg=f"{strategy_name}: {msg}" if strategy_name else msg,
level=level) gateway_name="CtaStrategy",
event = Event(type=EVENT_CTA_LOG, data=log) level=level)
self.event_engine.put(event) event = Event(type=EVENT_CTA_LOG, data=log)
self.event_engine.put(event)
# 保存单独的策略日志 # 保存单独的策略日志
if strategy_name: if strategy_name:

View File

@ -384,6 +384,7 @@ class CtaTemplate(ABC):
days: int, days: int,
interval: Interval = Interval.MINUTE, interval: Interval = Interval.MINUTE,
callback: Callable = None, callback: Callable = None,
interval_num: int = 1
): ):
""" """
Load historical bar data for initializing strategy. Load historical bar data for initializing strategy.
@ -391,7 +392,7 @@ class CtaTemplate(ABC):
if not callback: if not callback:
callback = self.on_bar callback = self.on_bar
self.cta_engine.load_bar(self.vt_symbol, days, interval, callback) self.cta_engine.load_bar(self.vt_symbol, days, interval, callback, interval_num)
def load_tick(self, days: int): def load_tick(self, days: int):
""" """
@ -1059,7 +1060,7 @@ class CtaProTemplate(CtaTemplate):
def save_tns(self, tns_data): def save_tns(self, tns_data):
""" """
保存多空事务记录=csv文件,便于后续分析 保存多空事务记录=csv文件,便于后续分析
:param tns_data: :param tns_data: {"datetime":xxx, "direction":"long"或者"short", "price":xxx}
:return: :return:
""" """
if self.backtesting: if self.backtesting:
@ -1770,6 +1771,7 @@ class CtaProFutureTemplate(CtaProTemplate):
if self.activate_today_lock: if self.activate_today_lock:
self.write_log(u'昨仓多单:{},没有今仓,满足条件,直接平昨仓'.format(grid_pos.long_yd)) self.write_log(u'昨仓多单:{},没有今仓,满足条件,直接平昨仓'.format(grid_pos.long_yd))
sell_price = self.cta_engine.get_price(sell_symbol) sell_price = self.cta_engine.get_price(sell_symbol)
if sell_price is None: if sell_price is None:
self.write_error(f'暂时不能获取{sell_symbol}价格,不能平仓') self.write_error(f'暂时不能获取{sell_symbol}价格,不能平仓')
@ -1780,12 +1782,16 @@ class CtaProFutureTemplate(CtaProTemplate):
grid.volume -= grid.traded_volume grid.volume -= grid.traded_volume
grid.traded_volume = 0 grid.traded_volume = 0
if grid_pos.long_pos <grid.volume:
self.write_error(f'账号{sell_symbol}多单持仓:{grid_pos.long_pos}不满足平仓:{grid.volume}要求:')
return False
vt_orderids = self.sell(price=sell_price, vt_orderids = self.sell(price=sell_price,
volume=grid.volume, volume=grid.volume,
vt_symbol=sell_symbol, vt_symbol=sell_symbol,
order_type=self.order_type, order_type=self.order_type,
order_time=self.cur_datetime, order_time=self.cur_datetime,
grid=grid) grid=grid)
if len(vt_orderids) == 0: if len(vt_orderids) == 0:
self.write_error(u'多单平仓委托失败') self.write_error(u'多单平仓委托失败')
return False return False
@ -1870,6 +1876,10 @@ class CtaProFutureTemplate(CtaProTemplate):
grid.volume -= grid.traded_volume grid.volume -= grid.traded_volume
grid.traded_volume = 0 grid.traded_volume = 0
if grid_pos.short_pos < grid.volume:
self.write_error(f'账号{cover_symbol}多单持仓:{grid_pos.short_pos}不满足平仓:{grid.volume}要求:')
return False
vt_orderids = self.cover(price=cover_price, vt_orderids = self.cover(price=cover_price,
volume=grid.volume, volume=grid.volume,
vt_symbol=cover_symbol, vt_symbol=cover_symbol,
@ -1997,7 +2007,7 @@ class CtaProFutureTemplate(CtaProTemplate):
target_long_grid = None target_long_grid = None
remove_long_grid_ids = [] remove_long_grid_ids = []
for g in sorted(locked_long_grids, key=lambda grid: grid.volume): for g in sorted(locked_long_grids, key=lambda grid: grid.volume):
if g.orderStatus or len(g.orderRef) > 0: if g.order_status or len(g.orderRef) > 0:
continue continue
if target_long_grid is None: if target_long_grid is None:
target_long_grid = g target_long_grid = g
@ -2133,7 +2143,7 @@ class CtaProFutureTemplate(CtaProTemplate):
vt_symbol = g.snapshot.get('mi_symbol', self.vt_symbol) vt_symbol = g.snapshot.get('mi_symbol', self.vt_symbol)
volume = g.volume - g.traded_volume volume = g.volume - g.traded_volume
locked_long_dict.update({vt_symbol: locked_long_dict.get(vt_symbol, 0) + volume}) locked_long_dict.update({vt_symbol: locked_long_dict.get(vt_symbol, 0) + volume})
if g.orderStatus or g.order_ids: if g.order_status or g.order_ids:
self.write_log(u'当前对锁格:{}存在委托,不进行解锁'.format(g.to_json())) self.write_log(u'当前对锁格:{}存在委托,不进行解锁'.format(g.to_json()))
return return
@ -2150,7 +2160,7 @@ class CtaProFutureTemplate(CtaProTemplate):
vt_symbol = g.snapshot.get('mi_symbol', self.vt_symbol) vt_symbol = g.snapshot.get('mi_symbol', self.vt_symbol)
volume = g.volume - g.traded_volume volume = g.volume - g.traded_volume
locked_short_dict.update({vt_symbol: locked_short_dict.get(vt_symbol, 0) + volume}) locked_short_dict.update({vt_symbol: locked_short_dict.get(vt_symbol, 0) + volume})
if g.orderStatus or g.order_ids: if g.order_status or g.order_ids:
self.write_log(u'当前对锁格:{}存在委托,不进行解锁'.format(g.to_json())) self.write_log(u'当前对锁格:{}存在委托,不进行解锁'.format(g.to_json()))
return return
@ -2238,7 +2248,7 @@ class CtaProFutureTemplate(CtaProTemplate):
for g in long_grids: for g in long_grids:
# 满足离场条件,或者碰到止损价格 # 满足离场条件,或者碰到止损价格
if g.stop_price > 0 and g.stop_price > self.cur_99_price \ if g.stop_price > 0 and g.stop_price > self.cur_99_price \
and g.openStatus and not g.orderStatus: and g.open_status and not g.order_status:
dist_record = dict() dist_record = dict()
dist_record['datetime'] = self.cur_datetime dist_record['datetime'] = self.cur_datetime
dist_record['symbol'] = self.idx_symbol dist_record['symbol'] = self.idx_symbol
@ -2262,7 +2272,7 @@ class CtaProFutureTemplate(CtaProTemplate):
short_grids = self.gt.get_opened_grids_without_types(direction=Direction.SHORT, types=[LOCK_GRID]) short_grids = self.gt.get_opened_grids_without_types(direction=Direction.SHORT, types=[LOCK_GRID])
for g in short_grids: for g in short_grids:
if g.stop_price > 0 and g.stop_price < self.cur_99_price \ if g.stop_price > 0 and g.stop_price < self.cur_99_price \
and g.openStatus and not g.orderStatus: and g.open_status and not g.order_status:
dist_record = dict() dist_record = dict()
dist_record['datetime'] = self.cur_datetime dist_record['datetime'] = self.cur_datetime
dist_record['symbol'] = self.idx_symbol dist_record['symbol'] = self.idx_symbol