This commit is contained in:
msincenselee 2019-06-21 23:34:55 +08:00
parent 6db1b12611
commit 145bfa55c3
8 changed files with 1801 additions and 1200 deletions

File diff suppressed because it is too large Load Diff

View File

@ -42,16 +42,17 @@ NIGHT_MARKET_SQ3 = {'RU': 0, 'RB': 0, 'HC': 0,'SP':0}
# 郑商所夜盘9:00~10:15, 10:30~11:30, 13:30~15:00, 21:00 ~23:30
NIGHT_MARKET_ZZ = {'TA': 0, 'JR': 0, 'OI': 0, 'RO': 0, 'PM': 0, 'WT': 0, 'WS': 0, 'WH': 0, 'CF': 0, 'SR': 0, 'FG': 0,
'ME': 0, 'MA': 0, 'RS': 0, 'RM': 0, 'TC': 0, 'RI': 0, 'ER': 0,'ZC':0}
# 郑商所夜盘9:00~10:15, 10:30~11:30, 13:30~15:00, 21:00 ~23:30
# 郑商所夜盘9:00~10:15, 10:30~11:30, 13:30~15:00, 21:00 ~23:00
NIGHT_MARKET_DL = {'V': 0, 'L': 0, 'BB': 0, 'I': 0, 'FB': 0, 'C': 0, 'PP': 0, 'A': 0, 'B': 0, 'M': 0, 'Y': 0, 'P': 0,
'JM': 0, 'J': 0}
'JM': 0, 'J': 0,'EG':0}
# 中金日盘9:15 ~11:30, 13:00~15:15
MARKET_ZJ = {'IC': 0, 'IF': 0, 'IH': 0, 'T': 0, 'TF': 0}
# 只有日盘得合约
MARKET_DAY_ONLY = {'IC': 0, 'IF': 0, 'IH': 0, 'T': 0, 'TF': 0,'PP':0,'JD':0,'BB':0,'C':0,'CS':0,'FB':0,'L':0,'V':0,
'JR':0, 'LR':0,'PM':0,'RI':0,'RS':0,'SM':0,'WH':0,'AP':0}
'JR':0, 'LR':0,'PM':0,'RI':0,'RS':0,'SM':0,'WH':0,'AP':0,'CJ':0}
# 数据库名称
SETTING_DB_NAME = 'VnTrader_Setting_Db'
POSITION_DB_NAME = 'VnTrader_Position_Db'

View File

@ -37,6 +37,8 @@ from vnpy.trader.vtGateway import VtSubscribeReq, VtOrderReq, VtCancelOrderReq,
from vnpy.trader.app.ctaStrategy.ctaBase import *
from vnpy.trader.setup_logger import setup_logger
from vnpy.trader.vtFunction import todayDate, getJsonPath
from vnpy.trader.vtObject import VtPositionData,PositionBuffer
from vnpy.trader.app.ctaStrategy.fundKline import FundKline
from vnpy.trader.util_mail import sendmail
from vnpy.trader.vtGlobal import globalSetting
# 加载 strategy目录下所有的策略
@ -97,6 +99,9 @@ class CtaEngine(object):
# key为vtSymbolvalue为PositionBuffer对象
self.posBufferDict = {}
# Strategy pos dict,key:strategy instance name, value: pos dict
self.strategy_pos_dict = {}
# 成交号集合,用来过滤已经收到过的成交推送
self.tradeSet = set()
@ -109,6 +114,9 @@ class CtaEngine(object):
# 未能订阅的symbols
self.pendingSubcribeSymbols = {}
# 订阅的bar与strategy映射关系
self.barStrategyDict ={}
# 注册事件监听
self.registerEvent()
@ -120,6 +128,49 @@ class CtaEngine(object):
self.strategy_loggers = {}
self.createLogger()
self.fund_kline_dict = {}
# 登记vtSymbol对应的最新价
self.price_dict = {}
def create_fund_kline(self, name,load_trade=False):
"""
创建资金曲线
:param: name 账号的ID或者策略的实例name
:return:
"""
setting = {}
setting.update({'name':name})
setting['inputMa1Len'] = 5
setting['inputMa2Len'] = 10
setting['inputMa3Len'] = 20
setting['inputYb'] = True
setting['minDiff'] = 0.01
setting['shortSymbol'] = 'fund'
fund_kline = FundKline(cta_engine=self,setting=setting,load_trade=load_trade)
self.fund_kline_dict.update({name:fund_kline})
return fund_kline
def get_fund_kline(self, name=None):
""" 获取账号的资金k线对象"""
# 指定资金账号
if name:
kline = self.fund_kline_dict.get(name, None)
return kline
# 没有指定账号并且存在一个或多个资金K线
if len(self.fund_kline_dict)>0:
# 优先找vt_setting中配置了strategy_groud的资金K线
kline = self.fund_kline_dict.get(globalSetting.get('strategy_group'),None)
# 找不到,返回第一个
if kline is None:
kline = self.fund_kline_dict.values()[0]
return kline
else:
return None
def analysis_vtSymbol(self, vtSymbol):
"""
分析合约
@ -165,8 +216,8 @@ class CtaEngine(object):
req.volume = self.roundToVolumeTick(volumeTick=contract.volumeTick,volume=volume) # 数量
if strategy:
req.productClass = strategy.productClass
req.currency = strategy.currency
req.productClass = getattr(strategy,'productClass','')
req.currency = getattr(strategy,'currency','')
else:
req.productClass = ''
req.currency = ''
@ -183,7 +234,7 @@ class CtaEngine(object):
req.direction = DIRECTION_SHORT
# 只有上期所才要考虑平今平昨
if contract.exchange != EXCHANGE_SHFE:
if contract.exchange not in [EXCHANGE_SHFE,EXCHANGE_SHFE]:
req.offset = OFFSET_CLOSE
else:
# 获取持仓缓存数据
@ -221,8 +272,8 @@ class CtaEngine(object):
elif orderType == CTAORDER_COVER:
req.direction = DIRECTION_LONG
# 只有上期所才要考虑平今平昨
if contract.exchange != EXCHANGE_SHFE:
# 只有上期所,能源所才要考虑平今平昨
if contract.exchange not in [EXCHANGE_SHFE,EXCHANGE_INE]:
req.offset = OFFSET_CLOSE
else:
# 获取持仓缓存数据
@ -251,16 +302,16 @@ class CtaEngine(object):
# 其他情况使用平昨
# else:
# req.offset = OFFSET_CLOSE
vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) # 发单
strategy_name = getattr(strategy,'name') if strategy is not None else None
vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName, strategyName=strategy_name) # 发单
if vtOrderID is None or len(vtOrderID) == 0:
self.writeCtaError(u'{} 发送委托失败. {} {} {} {}'.format(strategy.name if strategy else 'CtaEngine', vtSymbol, req.offset, req.direction, volume, price))
self.writeCtaError(u'{} 发送委托失败. {} {} {} {}'.format(getattr(strategy,'name','') if strategy else 'CtaEngine', vtSymbol, req.offset, req.direction, volume, price))
return ''
if strategy:
self.orderStrategyDict[vtOrderID] = strategy # 保存vtOrderID和策略的映射关系
msg = u'策略%s发送委托,%s, %s%s%s@%s' % (strategy.name, vtSymbol, req.offset, req.direction, volume, price)
msg = u'策略%s发送委托,%s, %s%s%s@%s' % (getattr(strategy,'name',''), vtSymbol, req.offset, req.direction, volume, price)
self.writeCtaLog(msg)
else:
msg = u'%s发送委托,%s, %s%s%s@%s' % ('CtaEngine', vtSymbol, req.offset, req.direction, volume, price)
@ -457,12 +508,13 @@ class CtaEngine(object):
del self.workingStopOrderDict[so.stopOrderID]
# ----------------------------------------------------------------------
def procecssTickEvent(self, event):
def processTickEvent(self, event):
"""处理行情推送事件"""
# 1. 获取事件的Tick数据
tick = event.dict_['data']
tick = copy.copy(tick)
# 移除待订阅的合约清单
if '.' in tick.vtSymbol:
symbol = tick.vtSymbol.split('.')[0]
@ -478,6 +530,7 @@ class CtaEngine(object):
# 缓存最新tick
self.tickDict[tick.vtSymbol] = tick
self.setPrice(vtSymbol=tick.vtSymbol,price=tick.lastPrice)
# 2.收到tick行情后优先处理本地停止单检查是否要立即发出
self.processStopOrder(tick)
@ -502,6 +555,18 @@ class CtaEngine(object):
for strategy in l:
self.callStrategyFunc(strategy, strategy.onTick, ctaTick)
def processBarEvent(self,event):
# 1. 获取事件的Tick数据
bar = event.dict_['data']
# 3.推送tick到对应的策略对象进行处理
if bar.vtSymbol in self.barStrategyDict:
# 逐个推送到策略实例中
l = self.barStrategyDict[bar.vtSymbol]
for strategy in l:
self.writeCtaLog(u'推送{}bar到策略:{}'.format(bar.vtSymbol,strategy.name))
self.callStrategyFunc(strategy, strategy.onBar, copy.copy(bar))
# ----------------------------------------------------------------------
def processOrderEvent(self, event):
"""处理委托推送事件"""
@ -547,8 +612,10 @@ class CtaEngine(object):
# else:
# strategy.pos -= trade.volume
copy_trade = copy.copy(trade)
# 根据策略名称,写入 data\straetgy_name_trade.csv文件
strategy_name = getattr(strategy,'name',None)
strategy_name = getattr(strategy,'name','no_strategy_name')
trade_fields = ['symbol','exchange','vtSymbol','tradeID','vtTradeID','orderID','vtOrderID','direction','offset','price','volume','tradeTime']
trade_dict = OrderedDict()
try:
@ -567,10 +634,14 @@ class CtaEngine(object):
# 推送到策略onTrade事件
self.callStrategyFunc(strategy, strategy.onTrade, trade)
# 保存策略持仓到数据库
self.saveSyncData(strategy)
if globalSetting.get('activate_strategy_fund_kline',False):
kline = self.get_fund_kline(strategy_name)
if kline is not None:
kline.update_trade(copy_trade)
else:
self.writeCtaError(u'未能推送成交记录到{}资金曲线'.format(strategy_name))
# 更新持仓缓存数据
# 更新持仓缓存数据
if trade.vtSymbol in self.tickStrategyDict:
posBuffer = self.posBufferDict.get(trade.vtSymbol, None)
if not posBuffer:
@ -580,26 +651,194 @@ class CtaEngine(object):
posBuffer.updateTradeData(trade)
# ----------------------------------------------------------------------
def processPositionEvent(self, event):
"""处理持仓推送"""
pos = event.dict_['data']
# 更新持仓缓存数据
if True: # pos.vtSymbol in self.tickStrategyDict:
posBuffer = self.posBufferDict.get(pos.vtSymbol, None)
if not posBuffer:
posBuffer = PositionBuffer()
posBuffer.vtSymbol = pos.vtSymbol
self.posBufferDict[pos.vtSymbol] = posBuffer
posBuffer.updatePositionData(pos)
posBuffer = self.posBufferDict.get(pos.vtSymbol, None)
if not posBuffer:
posBuffer = PositionBuffer()
posBuffer.vtSymbol = pos.vtSymbol
self.posBufferDict[pos.vtSymbol] = posBuffer
posBuffer.updatePositionData(pos)
if pos.vtSymbol.endswith('SPD'):
return
if not hasattr(self.mainEngine,'dataEngine'):
return
# 2、如果是普通合约持仓则查询是否为自定义套利合约的更新部分
if pos.vtSymbol not in self.mainEngine.dataEngine.contract_spd_mapping:
return
# 找到对应的spd合约
spd_list = self.mainEngine.dataEngine.contract_spd_mapping.get(pos.vtSymbol, [])
for spd_name in spd_list:
spd_setting = self.mainEngine.dataEngine.custom_contract_setting.get(spd_name, None)
if spd_setting is None:
continue
leg1_symbol = spd_setting.get('leg1_symbol')
leg2_symbol = spd_setting.get('leg2_symbol')
leg1_ratio = spd_setting.get('leg1_ratio',1)
leg2_ratio = spd_setting.get('leg2_ratio',1)
leg1_pos = self.posBufferDict.get(leg1_symbol,None)
leg2_pos = self.posBufferDict.get(leg2_symbol,None)
# leg1或者leg2没有持仓
if leg1_pos is None or leg2_pos is None:
continue
spd_long_pos = 0
spd_short_pos = 0
if leg1_pos.longPosition > 0 and leg2_pos.shortPosition > 0 and leg2_pos.shortPrice >0:
# 正套持仓量
leg1_volume = int(leg1_pos.longPosition/leg1_ratio)
leg2_volume = int(leg2_pos.shortPosition/leg2_ratio)
spd_long_pos = min(leg1_volume,leg2_volume)
if spd_long_pos > 0:
spd_pos = VtPositionData()
spd_pos.vtSymbol = spd_name
spd_pos.symbol = spd_name
spd_pos.exchange = pos.exchange
spd_pos.gatewayName = pos.gatewayName
spd_pos.direction = DIRECTION_LONG
spd_pos.position = spd_long_pos
# 开仓均价
if spd_setting.get('is_ratio', False):
# 使用百分比
spd_pos.price = 100 * leg1_pos.longPrice * leg1_ratio/(leg2_pos.shortPrice*leg2_ratio)
elif spd_setting.get('is_spread', False):
spd_pos.price = leg1_pos.longPrice * leg1_ratio - leg2_pos.shortPrice * leg2_ratio
# 冻结仓位
spd_pos.frozen = int(min(leg1_pos.longFrozen/leg1_ratio,leg2_pos.shortFrozen/leg2_ratio))
# 持仓盈亏
leg1_profit = leg1_pos.longProfit * spd_long_pos * leg1_ratio / leg1_pos.longPosition
leg2_profit = leg2_pos.shortProfit * spd_long_pos * leg2_ratio / leg2_pos.shortPosition
spd_pos.positionProfit = leg1_profit + leg2_profit
spd_pos.vtPositionName = '.'.join([spd_pos.vtSymbol,spd_pos.direction,spd_pos.gatewayName])
# 通用事件
event1 = Event(type_=EVENT_POSITION)
event1.dict_['data'] = spd_pos
self.eventEngine.put(event1)
elif (leg1_pos.longPosition == 0 or leg2_pos.shortPosition == 0) and self.posBufferDict.get(spd_name,None) is not None:
# 没有持有正套单,单有套利合约得记录信息
spd_pos = VtPositionData()
spd_pos.vtSymbol = spd_name
spd_pos.symbol = spd_name
spd_pos.exchange = pos.exchange
spd_pos.gatewayName = pos.gatewayName
spd_pos.direction = DIRECTION_LONG
spd_pos.position = 0
spd_pos.price = 0
# 冻结仓位
spd_pos.frozen = 0
# 持仓盈亏
spd_pos.positionProfit = 0
spd_pos.vtPositionName = '.'.join([spd_pos.vtSymbol, spd_pos.direction, spd_pos.gatewayName])
# 通用事件
event1 = Event(type_=EVENT_POSITION)
event1.dict_['data'] = spd_pos
self.eventEngine.put(event1)
if leg1_pos.shortPosition > 0 and leg2_pos.longPosition > 0 and leg2_pos.longPrice > 0:
spd_short_pos = int(min(leg1_pos.shortPosition / leg1_ratio, leg2_pos.longPosition / leg2_ratio))
if spd_short_pos > 0:
spd_pos = VtPositionData()
spd_pos.vtSymbol = spd_name
spd_pos.symbol = spd_name
spd_pos.exchange = pos.exchange
spd_pos.gatewayName = pos.gatewayName
spd_pos.direction = DIRECTION_SHORT
spd_pos.position = spd_short_pos
# 开仓均价
if spd_setting.get('is_ratio', False):
# 使用百分比
spd_pos.price = 100 * leg1_pos.shortPrice * leg1_ratio / (leg2_pos.longPrice * leg2_ratio)
elif spd_setting.get('is_spread', False):
spd_pos.price = leg1_pos.shortPrice * leg1_ratio - leg2_pos.longPrice * leg2_ratio
# 冻结仓位
spd_pos.frozen = int(min(leg1_pos.shortFrozen / leg1_ratio, leg2_pos.longFrozen / leg2_ratio))
# 持仓盈亏
leg1_profit = leg1_pos.shortProfit * spd_short_pos * leg1_ratio / leg1_pos.shortPosition
leg2_profit = leg2_pos.longProfit * spd_short_pos * leg2_ratio / leg2_pos.longPosition
spd_pos.positionProfit = leg1_profit + leg2_profit
spd_pos.vtPositionName = '.'.join([spd_pos.vtSymbol, spd_pos.direction, spd_pos.gatewayName])
# 通用事件
event1 = Event(type_=EVENT_POSITION)
event1.dict_['data'] = spd_pos
self.eventEngine.put(event1)
elif (leg1_pos.shortPosition == 0 or leg2_pos.longPosition == 0) and self.posBufferDict.get(spd_name,None) is not None:
# 没有持有反套单,但有套利合约得记录信息
spd_pos = VtPositionData()
spd_pos.vtSymbol = spd_name
spd_pos.symbol = spd_name
spd_pos.exchange = pos.exchange
spd_pos.gatewayName = pos.gatewayName
spd_pos.direction = DIRECTION_SHORT
spd_pos.position = 0
spd_pos.price = 0
# 冻结仓位
spd_pos.frozen = 0
# 持仓盈亏
spd_pos.positionProfit = 0
spd_pos.vtPositionName = '.'.join([spd_pos.vtSymbol, spd_pos.direction, spd_pos.gatewayName])
# 通用事件
event1 = Event(type_=EVENT_POSITION)
event1.dict_['data'] = spd_pos
self.eventEngine.put(event1)
def processAccountEvent(self,event):
"""
账号资金事件更新
:param event:
:return:
"""
dt = datetime.now()
if dt.hour in [9, 10, 11, 13, 14, 15, 21, 22, 23, 0, 1, 2]:
account = event.dict_['data']
account_id = account.accountID
# 更新账号得资金曲线
if globalSetting.get('activate_account_fund_kline',False):
fund_kline = self.fund_kline_dict.get(account_id,None)
if fund_kline is None:
fund_kline = self.create_fund_kline(account_id)
if fund_kline:
balance = account.balance
fund_kline.update_account(dt,balance)
# 更新各策略实例的资金曲线
if len(self.tickDict) > 0 and globalSetting.get('activate_strategy_fund_kline',False):
for strategy_name in self.strategy_pos_dict.keys():
fund_kline = self.fund_kline_dict.get(strategy_name,None)
if fund_kline is not None:
hold_pnl = fund_kline.get_hold_pnl()
if hold_pnl !=0:
fund_kline.update_strategy(dt=dt,hold_pnl=hold_pnl)
# 检查未订阅信息
self.checkUnsubscribedSymbols()
# ----------------------------------------------------------------------
def registerEvent(self):
"""注册事件监听"""
# 注册行情数据推送Tick数据到达的响应事件
self.eventEngine.register(EVENT_TICK, self.procecssTickEvent)
self.eventEngine.register(EVENT_TICK, self.processTickEvent)
# 注册bar行情数据推送Bar数据到达的响应事件
self.eventEngine.register(EVENT_BAR, self.processBarEvent)
# 注册订单推送的响应事件
self.eventEngine.register(EVENT_ORDER, self.processOrderEvent)
@ -611,7 +850,7 @@ class CtaEngine(object):
self.eventEngine.register(EVENT_POSITION, self.processPositionEvent)
# 账号更新事件(借用账号更新事件,来检查是否有未订阅的合约信息)
self.eventEngine.register(EVENT_ACCOUNT, self.checkUnsubscribedSymbols)
self.eventEngine.register(EVENT_ACCOUNT, self.processAccountEvent)
# 注册定时器事件
self.eventEngine.register(EVENT_TIMER, self.processTimerEvent)
@ -878,8 +1117,10 @@ class CtaEngine(object):
# ----------------------------------------------------------------------
# 订阅合约相关
def subscribe(self, strategy, symbol):
def subscribe(self, strategy, symbol,is_bar=False):
"""订阅合约,不成功时,加入到待订阅列表"""
if len(symbol)==0:
return
contract = self.mainEngine.getContract(symbol)
if contract:
@ -887,7 +1128,7 @@ class CtaEngine(object):
req = VtSubscribeReq()
req.symbol = contract.symbol
req.exchange = contract.exchange
req.is_bar = is_bar
# 对于IB接口订阅行情时所需的货币和产品类型从策略属性中获取
if hasattr(strategy,'currency'):
req.currency = strategy.currency
@ -900,9 +1141,11 @@ class CtaEngine(object):
print(u'Warning, can not find {0} in contracts'.format(symbol))
self.writeCtaLog(u'交易合约{}无法找到,添加到待订阅列表'.format(symbol))
self.pendingSubcribeSymbols[symbol] = strategy
try:
req = VtSubscribeReq()
req.symbol = symbol
req.is_bar = is_bar
self.mainEngine.subscribe(req,None)
@ -919,10 +1162,19 @@ class CtaEngine(object):
strategies.append(strategy)
self.tickStrategyDict.update({symbol: strategies})
def checkUnsubscribedSymbols(self, event):
"""持仓更新信息时,检查未提交的合约"""
if is_bar:
s_list = self.barStrategyDict.get(symbol,[])
if symbol not in s_list:
self.writeCtaLog(u'添加:{} bar订阅映射到策略:{}'.format(symbol,strategy.name))
s_list.append(strategy)
self.barStrategyDict.update({symbol:s_list})
def checkUnsubscribedSymbols(self):
"""检查未提交的合约"""
for symbol in self.pendingSubcribeSymbols.keys():
contract = self.mainEngine.getContract(symbol)
is_bar = True if symbol in self.barStrategyDict else False
if contract:
# 获取合约的缩写号
s = self.getShortSymbol(symbol)
@ -935,11 +1187,12 @@ class CtaEngine(object):
self.writeCtaLog(u'重新提交合约{0}订阅请求'.format(symbol))
strategy = self.pendingSubcribeSymbols[symbol]
self.subscribe(strategy=strategy, symbol=symbol)
self.subscribe(strategy=strategy, symbol=symbol,is_bar=is_bar)
else:
try:
req = VtSubscribeReq()
req.symbol = symbol
req.is_bar = is_bar
self.mainEngine.subscribe(req, None)
except Exception as ex:
@ -1054,6 +1307,18 @@ class CtaEngine(object):
symbols.append(strategy.vtSymbol)
else:
symbols.append(s[0])
elif strategy.vtSymbol.endswith('SPD'):
# 增加自定义套利合约
if strategy.vtSymbol not in symbols:
symbols.append(strategy.vtSymbol)
symbol = strategy.vtSymbol[0:-4]
lists = symbol.split('-')
leg1_symbol = lists[0]
leg2_symbol = lists[2]
if leg1_symbol not in symbols:
symbols.append(leg1_symbol)
if leg2_symbol not in symbols:
symbols.append(leg2_symbol)
else:
symbols = strategy.vtSymbol.split(';')
@ -1070,6 +1335,19 @@ class CtaEngine(object):
if hasattr(strategy, 'Leg2Symbol'):
if strategy.Leg2Symbol not in symbols:
symbols.append(strategy.Leg2Symbol)
if hasattr(strategy, 'miSymbol'):
if strategy.miSymbol not in symbols:
symbols.append(strategy.miSymbol)
if strategy.miSymbol.endswith('SPD'):
# 增加自定义套利合约
symbol = strategy.miSymbol[0:-4]
lists = symbol.split('-')
leg1_symbol = lists[0]
leg2_symbol = lists[2]
if leg1_symbol not in symbols:
symbols.append(leg1_symbol)
if leg2_symbol not in symbols:
symbols.append(leg2_symbol)
for symbol in symbols:
self.writeCtaLog(u'添加合约{}与策略{}的匹配目录'.format(symbol,strategy.name))
@ -1103,6 +1381,11 @@ class CtaEngine(object):
except Exception as ex:
self.writeCtaCritical(u'自动启动策略:{} 异常,{},{}'.format(name, str(ex), traceback.format_exc()))
return False
# 激活策略实例的资金曲线
if globalSetting.get('activate_strategy_fund_kline',False):
self.create_fund_kline(name, load_trade=True)
return True
def initStrategy(self, name, force=False):
@ -1114,7 +1397,6 @@ class CtaEngine(object):
self.callStrategyFunc(strategy, strategy.onInit, force)
# strategy.onInit(force=force)
# strategy.inited = True
self.loadSyncData(strategy) # 初始化完成后加载同步数据
else:
self.writeCtaLog(u'请勿重复初始化策略实例:%s' % name)
return True
@ -1536,6 +1818,7 @@ class CtaEngine(object):
'volume': sell_longYd, 'action': 'clean',
'comment': 'sell_longYd',
'result': True if order_id else False, 'datetime': datetime.now()}
self.mainEngine.dbInsert(MATRIX_DB_NAME, POSITION_DISPATCH_HISTORY_COLL_NAME, h)
if sell_longToday > 0:
@ -1906,10 +2189,11 @@ class CtaEngine(object):
except Exception as ex:
self.writeCtaCritical(u'加载策略配置{}:异常{}{}'.format(setting, str(ex), traceback.format_exc()))
traceback.print_exc()
self.loadPosition()
except Exception as ex:
self.writeCtaCritical(u'加载策略配置异常:{},{}'.format(str(ex),traceback.format_exc()))
# ----------------------------------------------------------------------
# 策略运行监控相关
def getStrategyVar(self, name):
@ -1944,11 +2228,11 @@ class CtaEngine(object):
self.writeCtaLog(u'策略实例不存在:' + name)
return None
def getStategyPos(self, name,strategy=None):
def getStategyPos(self, name, strategy=None):
"""
获取策略的持仓字典
:param name:策略名
:return:
:return: [ {},{}]
"""
# 兼容处理如果strategy是None通过name获取
if strategy is None:
@ -1961,13 +2245,14 @@ class CtaEngine(object):
pos_list = []
if strategy.inited:
# 如果策略具有getPositions得方法则调用该方法
if hasattr(strategy,'getPositions'):
pos_list=strategy.getPositions()
for pos in pos_list:
pos.update({'symbol':pos.get('vtSymbol')})
return pos_list
# 有 ctaPosition属性
if hasattr(strategy, 'position'):
# 如果策略有 ctaPosition属性
elif hasattr(strategy, 'position'):
# 多仓
long_pos = {}
long_pos['symbol'] = strategy.vtSymbol
@ -1984,7 +2269,7 @@ class CtaEngine(object):
if short_pos['volume'] > 0:
pos_list.append(short_pos)
# 模板缺省pos属性
# 获取模板缺省pos属性
elif hasattr(strategy, 'pos'):
if strategy.pos > 0:
long_pos = {}
@ -2003,8 +2288,70 @@ class CtaEngine(object):
if short_pos['volume'] > 0:
pos_list.append(short_pos)
# 新增处理SPD结尾得特殊自定义套利合约
try:
if strategy.vtSymbol.endswith('SPD') and len(pos_list) > 0:
old_pos_list = copy.copy(pos_list)
pos_list = []
for pos in old_pos_list:
# SPD合约
spd_symbol = pos.get('vtSymbol', pos.get('symbol', None))
if spd_symbol is not None and spd_symbol.endswith('SPD'):
spd_setting = self.mainEngine.dataEngine.custom_contract_setting.get(spd_symbol,None)
if spd_setting is None:
self.writeCtaError(u'获取不到:{}得设置信息,检查自定义合约配置文件'.format(spd_symbol))
pos_list.append(pos)
continue
leg1_direction = 'long' if pos.get('direction') in [DIRECTION_LONG,'long'] else 'short'
leg2_direction = 'short' if leg1_direction == 'long' else 'long'
spd_volume = pos.get('volume')
leg1_pos = {}
leg1_pos.update({'symbol': spd_setting.get('leg1_symbol')})
leg1_pos.update({'vtSymbol': spd_setting.get('leg1_symbol')})
leg1_pos.update({'direction': leg1_direction})
leg1_pos.update({'volume': spd_setting.get('leg1_ratio',1)*spd_volume})
leg2_pos = {}
leg2_pos.update({'symbol': spd_setting.get('leg2_symbol')})
leg2_pos.update({'vtSymbol': spd_setting.get('leg2_symbol')})
leg2_pos.update({'direction': leg2_direction})
leg2_pos.update({'volume': spd_setting.get('leg2_ratio', 1) * spd_volume})
pos_list.append(leg1_pos)
pos_list.append(leg2_pos)
#pos_list.append(pos)
else:
pos_list.append(pos)
except Exception as ex:
self.writeCtaError(u'分解SPD失败')
# update local pos dict
self.strategy_pos_dict.update({name:pos_list})
return pos_list
def get_pos_open_price(self,vtSymbol,direction):
"""
get the open price from posbufferDict
:param vtSymbol:
:param direction:
:return:
"""
pos = self.posBufferDict.get(vtSymbol,None)
if pos is None:
return 0
if direction in [DIRECTION_LONG, 'long']:
return pos.longPrice
else:
return pos.shortPrice
def updateStrategySetting(self,strategy_name,setting_key,setting_value):
"""
更新策略的某项设置
@ -2065,17 +2412,23 @@ class CtaEngine(object):
func(params)
else:
func()
except Exception:
except Exception as ex:
# 停止策略,修改状态为未初始化
strategy.trading = False
strategy.inited = False
# 发出日志
content =u'策略{}触发异常已停止.{}'.format(strategy.name,traceback.format_exc())
self.writeCtaError(content)
content =u'策略{}触发异常已停止.{},{}'.format(strategy.name,str(ex),traceback.format_exc())
self.writeCtaCritical(content)
self.mainEngine.writeCritical(content)
self.sendAlertToWechat(content=content,target=globalSetting.get('gateway_name',None))
self.sendAlertToWechat(content=content, target=globalSetting.get('gateway_name',None))
if globalSetting.get('activate_wx_ft', False):
try:
from huafu.util.util_wx_ft import sendWxMsg
sendWxMsg(text=u'策略{}触发异常停止', desp=content)
except Exception:
pass
# ----------------------------------------------------------------------
# 仓位持久化相关
@ -2108,38 +2461,6 @@ class CtaEngine(object):
except:
self.writeCtaLog(u'loadPosition Exception from Mongodb')
# ----------------------------------------------------------------------
def saveSyncData(self, strategy):
"""保存策略的持仓情况到数据库"""
flt = {'name': strategy.name,
'vtSymbol': strategy.vtSymbol}
d = copy.copy(flt)
for key in strategy.syncList:
d[key] = strategy.__getattribute__(key)
self.mainEngine.dbUpdate(POSITION_DB_NAME, strategy.className,
d, flt, True)
content = u'策略%s同步数据保存成功,当前持仓%s' % (strategy.name, strategy.pos)
self.writeCtaLog(content)
# ----------------------------------------------------------------------
def loadSyncData(self, strategy):
"""从数据库载入策略的持仓情况"""
flt = {'name': strategy.name,
'vtSymbol': strategy.vtSymbol}
syncData = self.mainEngine.dbQuery(POSITION_DB_NAME, strategy.className, flt)
if not syncData:
return
d = syncData[0]
for key in strategy.syncList:
if key in d:
strategy.__setattr__(key, d[key])
# ----------------------------------------------------------------------
# 公共方法相关
def roundToPriceTick(self, priceTick, price):
@ -2240,6 +2561,9 @@ class CtaEngine(object):
except:
traceback.print_exc()
for kline in self.fund_kline_dict.values():
kline.save()
def clearData(self):
"""清空运行数据"""
self.writeCtaLog(u'ctaEngine.clearData()清空运行数据')
@ -2278,7 +2602,13 @@ class CtaEngine(object):
else:
return c.size
def qryMarginRate(self,vtSymbol):
def setPrice(self,vtSymbol, price):
self.price_dict.update({vtSymbol:price})
def qryPrice(self,vtSymbol):
return self.price_dict.get(vtSymbol, None)
def qryMarginRate(self, vtSymbol):
"""
提供给策略查询品种的保证金比率
:param vtSymbol:
@ -2365,7 +2695,7 @@ class CtaEngine(object):
return False
# 上期RB/HC/RU 日盘夜盘2100~2300
if short_symbol in NIGHT_MARKET_SQ3:
if short_symbol in NIGHT_MARKET_SQ3 or short_symbol in NIGHT_MARKET_DL:
if morning_begin <= dt <= morning_break or \
morning_restart <= dt <= morning_close or \
afternoon_begin <= dt <= afternoon_close or \
@ -2375,7 +2705,7 @@ class CtaEngine(object):
return False
# 郑商、大连 21:00 ~ 23:30
if short_symbol in NIGHT_MARKET_ZZ or short_symbol in NIGHT_MARKET_DL:
if short_symbol in NIGHT_MARKET_ZZ :
if morning_begin <= dt <= morning_break or \
morning_restart <= dt <= morning_close or \
afternoon_begin <= dt <= afternoon_close or \
@ -2385,88 +2715,3 @@ class CtaEngine(object):
return False
return True
########################################################################
class PositionBuffer(object):
"""持仓缓存信息(本地维护的持仓数据)"""
# ----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
self.vtSymbol = EMPTY_STRING
# 多头
self.longPosition = EMPTY_INT
self.longToday = EMPTY_INT
self.longYd = EMPTY_INT
# 空头
self.shortPosition = EMPTY_INT
self.shortToday = EMPTY_INT
self.shortYd = EMPTY_INT
self.frozen = EMPTY_FLOAT
# ----------------------------------------------------------------------
def toStr(self):
"""更新显示信息"""
str = u'long:{},yd:{},td:{}, short:{},yd:{},td:{}, fz:{};' \
.format(self.longPosition, self.longYd, self.longToday,
self.shortPosition, self.shortYd, self.shortToday,self.frozen)
return str
#----------------------------------------------------------------------
def updatePositionData(self, pos):
"""更新持仓数据"""
if pos.direction == DIRECTION_SHORT:
self.shortPosition = pos.position # >=0
self.shortYd = pos.ydPosition # >=0
self.shortToday = self.shortPosition - self.shortYd # >=0
self.frozen = pos.frozen
else:
self.longPosition = pos.position # >=0
self.longYd = pos.ydPosition # >=0
self.longToday = self.longPosition - self.longYd # >=0
self.frozen = pos.frozen
#----------------------------------------------------------------------
def updateTradeData(self, trade):
"""更新成交数据"""
if trade.direction == DIRECTION_SHORT:
# 空头和多头相同
if trade.offset == OFFSET_OPEN:
self.shortPosition += trade.volume
self.shortToday += trade.volume
elif trade.offset == OFFSET_CLOSETODAY:
self.longPosition -= trade.volume
self.longToday -= trade.volume
else:
self.longPosition -= trade.volume
self.longYd -= trade.volume
if self.longPosition <= 0:
self.longPosition = 0
if self.longToday <= 0:
self.longToday = 0
if self.longYd <= 0:
self.longYd = 0
else:
# 多方开仓,则对应多头的持仓和今仓增加
if trade.offset == OFFSET_OPEN:
self.longPosition += trade.volume
self.longToday += trade.volume
# 多方平今,对应空头的持仓和今仓减少
elif trade.offset == OFFSET_CLOSETODAY:
self.shortPosition -= trade.volume
self.shortToday -= trade.volume
else:
self.shortPosition -= trade.volume
self.shortYd -= trade.volume
if self.shortPosition <= 0:
self.shortPosition = 0
if self.shortToday <= 0:
self.shortToday = 0
if self.shortYd <= 0:
self.shortYd = 0
# 多方平昨,对应空头的持仓和昨仓减少

View File

@ -394,12 +394,12 @@ class CtaLineBar(object):
self.lineUpperBandAtan = []
self.lineMiddleBandAtan = []
self.lineLowerBandAtan = []
self._rt_Upper = None
self._rt_Middle = None
self._rt_Lower = None
self._rt_UpperBandAtan = None
self._rt_MiddleBandAtan = None
self._rt_LowerBandAtan = None
self._rt_Upper = 0
self._rt_Middle = 0
self._rt_Lower = 0
self._rt_UpperBandAtan = 0
self._rt_MiddleBandAtan = 0
self._rt_LowerBandAtan = 0
self.lastBollUpper = EMPTY_FLOAT # 最后一根K的Boll上轨数值与MinDiff取整
self.lastBollMiddle = EMPTY_FLOAT # 最后一根K的Boll中轨数值与MinDiff取整
@ -442,6 +442,10 @@ class CtaLineBar(object):
self.lastD = EMPTY_FLOAT # bar内计算时最后一个未关闭的bar的实时值
self.lastJ = EMPTY_FLOAT # bar内计算时最后一个未关闭的bar的实时J值
self.kd_count = 0 # > 0, 金叉, < 0 死叉
self.kd_last_cross = 0 # 最近一次金叉/死叉的点位
self.kd_cross_price = 0 # 最近一次发生金叉/死叉的价格
# K线的MACD计算数据(26,12,9)
self.inputMacdFastPeriodLen = EMPTY_INT
self.inputMacdSlowPeriodLen = EMPTY_INT
@ -747,7 +751,7 @@ class CtaLineBar(object):
根据实时计算得要求执行实时指标计算
:return:
"""
for func in self.rt_funcs:
for func in list(self.rt_funcs):
try:
func()
except Exception as ex:
@ -1032,10 +1036,10 @@ class CtaLineBar(object):
endtick = True
# 夜盘23:00收盘
if self.shortSymbol in NIGHT_MARKET_SQ3 and tick.datetime.hour == 23 and tick.datetime.minute == 00:
if self.shortSymbol in [NIGHT_MARKET_SQ3,NIGHT_MARKET_DL] and tick.datetime.hour == 23 and tick.datetime.minute == 00:
endtick = True
# 夜盘23:30收盘
if self.shortSymbol in NIGHT_MARKET_ZZ or self.shortSymbol in NIGHT_MARKET_DL:
if self.shortSymbol in NIGHT_MARKET_ZZ:
if tick.datetime.hour == 23 and tick.datetime.minute == 30:
endtick = True
@ -1123,7 +1127,7 @@ class CtaLineBar(object):
lastBar.high = max(lastBar.high, tick.lastPrice)
lastBar.low = min(lastBar.low, tick.lastPrice)
lastBar.close = tick.lastPrice
lastBar.openInterest = tick.openInterest
# 更新日内总交易量和bar内交易量
lastBar.dayVolume = tick.volume
if l1 == 1:
@ -1330,10 +1334,10 @@ class CtaLineBar(object):
return
# 1、lineBar满足长度才执行计算
if len(self.lineBar) < max(7, self.inputMa1Len, self.inputMa2Len, self.inputMa3Len) + 2:
if len(self.lineBar) < min(7, self.inputMa1Len, self.inputMa2Len, self.inputMa3Len) + 2:
self.debugCtaLog(u'数据未充分,当前Bar数据数量{0}计算MA需要{1}'.
format(len(self.lineBar),
max(7, self.inputMa1Len, self.inputMa2Len, self.inputMa3Len) + 2))
min(7, self.inputMa1Len, self.inputMa2Len, self.inputMa3Len) + 2))
return
# 计算第一条MA均线
@ -1821,9 +1825,12 @@ class CtaLineBar(object):
if maxAtrLen <= 0: # 不计算
return
if len(self.lineBar) < maxAtrLen + 1:
data_need_len = min(7, maxAtrLen)
line_bar_len = len(self.lineBar)
if line_bar_len < data_need_len:
self.debugCtaLog(u'数据未充分,当前Bar数据数量{0}计算ATR需要{1}'.
format(len(self.lineBar), maxAtrLen + 1))
format(line_bar_len,data_need_len))
return
if self.mode == self.TICK_MODE:
@ -1843,7 +1850,7 @@ class CtaLineBar(object):
j = 0
for i in range(len(self.lineBar) - idx, len(self.lineBar) - idx - maxAtrLen, -1): # 周期 inputP
for i in range(len(self.lineBar) - idx, len(self.lineBar) - idx - data_need_len, -1): # 周期 inputP
# 3.1、计算TR
# 当前周期最高与最低的价差
@ -1880,10 +1887,11 @@ class CtaLineBar(object):
# 计算 ATR
if self.inputAtr1Len > 0:
data_4_atr1 = min(line_bar_len,self.inputAtr1Len)
if len(self.lineAtr1) < 1:
self.barAtr1 = round(barTr1 / self.inputAtr1Len, self.round_n)
self.barAtr1 = round(barTr1 / data_4_atr1, self.round_n)
else:
self.barAtr1 = round((self.lineAtr1[-1] * (self.inputAtr1Len - 1) + barTr1) / self.inputAtr1Len,
self.barAtr1 = round((self.lineAtr1[-1] * (data_4_atr1 - 1) + barTr1) / data_4_atr1,
self.round_n)
if len(self.lineAtr1) > self.inputAtr1Len + 1:
@ -1891,10 +1899,11 @@ class CtaLineBar(object):
self.lineAtr1.append(self.barAtr1)
if self.inputAtr2Len > 0:
data_4_atr2 = min(line_bar_len, self.inputAtr2Len)
if len(self.lineAtr2) < 1:
self.barAtr2 = round(barTr2 / self.inputAtr2Len, self.round_n)
self.barAtr2 = round(barTr2 / data_4_atr2, self.round_n)
else:
self.barAtr2 = round((self.lineAtr2[-1] * (self.inputAtr2Len - 1) + barTr2) / self.inputAtr2Len,
self.barAtr2 = round((self.lineAtr2[-1] * (data_4_atr2 - 1) + barTr2) / data_4_atr2,
self.round_n)
if len(self.lineAtr2) > self.inputAtr2Len + 1:
@ -1902,10 +1911,11 @@ class CtaLineBar(object):
self.lineAtr2.append(self.barAtr2)
if self.inputAtr3Len > 0:
data_4_atr3 = min(line_bar_len, self.inputAtr3Len)
if len(self.lineAtr3) < 1:
self.barAtr3 = round(barTr3 / self.inputAtr3Len, self.round_n)
self.barAtr3 = round(barTr3 / data_4_atr3, self.round_n)
else:
self.barAtr3 = round((self.lineAtr3[-1] * (self.inputAtr3Len - 1) + barTr3) / self.inputAtr3Len,
self.barAtr3 = round((self.lineAtr3[-1] * (data_4_atr3 - 1) + barTr3) / data_4_atr3,
self.round_n)
if len(self.lineAtr3) > self.inputAtr3Len + 1:
@ -2064,12 +2074,12 @@ class CtaLineBar(object):
l = len(self.lineBar)
if self.inputBollLen > EMPTY_INT:
if l < min(14, self.inputBollLen) + 1:
if l < min(7, self.inputBollLen) :
self.debugCtaLog(u'数据未充分,当前Bar数据数量{0}计算Boll需要{1}'.
format(len(self.lineBar), min(14, self.inputBollLen) + 1))
else:
if l < self.inputBollLen + 2:
bollLen = l - 1
if l < self.inputBollLen :
bollLen = l
else:
bollLen = self.inputBollLen
@ -2600,6 +2610,8 @@ class CtaLineBar(object):
self.lineKdjButtom.append(b)
self.lastKdjTopButtom = self.lineKdjButtom[-1]
self.update_kd_cross()
def __recountKdj_TB(self, countInBar=False):
"""KDJ指标"""
"""
@ -2622,7 +2634,7 @@ class CtaLineBar(object):
if self.inputKdjTBLen <= EMPTY_INT: return
if self.inputKdjTBLen + self.inputKdjSmoothLen > self.max_hold_bars:
self.max_hold_bars = self.inputKdjTBLen + self.inputKdjSmoothLen1 + 1
self.max_hold_bars = self.inputKdjTBLen + self.inputKdjSmoothLen + 1
# if len(self.lineBar) < self.inputKdjTBLen + 1:
# if not countInBar:
@ -2742,6 +2754,35 @@ class CtaLineBar(object):
self.lineKdjButtom.append(b)
self.lastKdjTopButtom = self.lineKdjButtom[-1]
self.update_kd_cross()
def update_kd_cross(self):
"""更新KDJ金叉死叉"""
if len(self.lineK) < 2 or len(self.lineD) < 2:
return
# K值大于D值
if self.lineK[-1] > self.lineD[-1]:
if self.lineK[-2] > self.lineD[-2]:
# 延续金叉
self.kd_count = max(1,self.kd_count) + 1
else:
# 发生金叉
self.kd_count = 1
self.kd_last_cross = round((self.lineK[-1] + self.lineK[-2])/2,2)
self.kd_cross_price = self.lineBar[-1].close
# K值小于D值
else:
if self.lineK[-2] < self.lineD[-2]:
# 延续死叉
self.kd_count = min(-1, self.kd_count) - 1
else:
# 发生死叉
self.kd_count = -1
self.kd_last_cross = round((self.lineK[-1] + self.lineK[-2]) / 2, 2)
self.kd_cross_price = self.lineBar[-1].close
def __recountMacd(self):
"""
Macd计算方法
@ -3174,7 +3215,12 @@ class CtaLineBar(object):
if ma5 <= 0 or ma5_ref1 <= 0:
self.writeCtaLog(u'boll中轨计算均线异常')
return
self.atan = math.atan((ma5 / ma5_ref1 - 1) * 100) * 180 / math.pi
if self.inputKF:
self.atan = math.atan((ma5 / ma5_ref1 - 1) * 100) * 180 / math.pi
else:
# 当前均值,与前5均值得价差,除以标准差
self.atan = math.atan((ma5 - ma5_ref1)/self.lineBollStd[-1]) * 180 / math.pi
# atan2 = math.atan((ma5 / ma5_ref1 - 1) * 100) * 180 / math.pi
# atan3 = math.atan(ma5 / ma5_ref1 - 1)* 100
self.atan = round(self.atan, 3)
@ -4340,11 +4386,11 @@ class CtaLineBar(object):
return True
# 夜盘23:00收盘
if self.shortSymbol in NIGHT_MARKET_SQ3 and tick_dt.hour == 23 and tick_dt.minute == 00:
if self.shortSymbol in [NIGHT_MARKET_SQ3,NIGHT_MARKET_DL] and tick_dt.hour == 23 and tick_dt.minute == 00:
return True
# 夜盘23:30收盘
if self.shortSymbol in NIGHT_MARKET_ZZ or self.shortSymbol in NIGHT_MARKET_DL:
if self.shortSymbol in NIGHT_MARKET_ZZ :
if tick_dt.hour == 23 and tick_dt.minute == 30:
return True
@ -4584,10 +4630,10 @@ class CtaMinuteBar(CtaLineBar):
endtick = True
# 夜盘23:00收盘
if self.shortSymbol in NIGHT_MARKET_SQ3 and tick.datetime.hour == 23 and tick.datetime.minute == 00:
if self.shortSymbol in [NIGHT_MARKET_SQ3,NIGHT_MARKET_DL] and tick.datetime.hour == 23 and tick.datetime.minute == 00:
endtick = True
# 夜盘23:30收盘
if self.shortSymbol in NIGHT_MARKET_ZZ or self.shortSymbol in NIGHT_MARKET_DL:
if self.shortSymbol in NIGHT_MARKET_ZZ :
if tick.datetime.hour == 23 and tick.datetime.minute == 30:
endtick = True
@ -4639,7 +4685,7 @@ class CtaMinuteBar(CtaLineBar):
lastBar.high = max(lastBar.high, tick.lastPrice)
lastBar.low = min(lastBar.low, tick.lastPrice)
lastBar.close = tick.lastPrice
lastBar.openInterest = tick.openInterest
# 更新日内总交易量和bar内交易量
lastBar.dayVolume = tick.volume
if l1 == 1:
@ -4848,10 +4894,10 @@ class CtaHourBar(CtaLineBar):
endtick = True
# 夜盘23:00收盘
if self.shortSymbol in NIGHT_MARKET_SQ3 and tick.datetime.hour == 23 and tick.datetime.minute == 00:
if self.shortSymbol in [NIGHT_MARKET_SQ3,NIGHT_MARKET_DL] and tick.datetime.hour == 23 and tick.datetime.minute == 00:
endtick = True
# 夜盘23:30收盘
if self.shortSymbol in NIGHT_MARKET_ZZ or self.shortSymbol in NIGHT_MARKET_DL:
if self.shortSymbol in NIGHT_MARKET_ZZ :
if tick.datetime.hour == 23 and tick.datetime.minute == 30:
endtick = True
@ -4924,7 +4970,7 @@ class CtaHourBar(CtaLineBar):
lastBar.high = max(lastBar.high, tick.lastPrice)
lastBar.low = min(lastBar.low, tick.lastPrice)
lastBar.close = tick.lastPrice
lastBar.openInterest = tick.openInterest
# 更新日内总交易量和bar内交易量
lastBar.dayVolume = tick.volume
if l1 == 1:
@ -5136,7 +5182,7 @@ class CtaDayBar(CtaLineBar):
lastBar.high = max(lastBar.high, tick.lastPrice)
lastBar.low = min(lastBar.low, tick.lastPrice)
lastBar.close = tick.lastPrice
lastBar.openInterest = tick.openInterest
# 更新日内总交易量和bar内交易量
lastBar.dayVolume = tick.volume
if l1 == 1:
@ -5407,7 +5453,7 @@ class CtaWeekBar(CtaLineBar):
lastBar.high = max(lastBar.high, tick.lastPrice)
lastBar.low = min(lastBar.low, tick.lastPrice)
lastBar.close = tick.lastPrice
lastBar.openInterest = tick.openInterest
# 更新日内总交易量和bar内交易量
lastBar.dayVolume = tick.volume
if l1 == 1:

View File

@ -66,14 +66,14 @@ class CtaPolicy(object):
self.create_time = datetime.now()
create_time = json_data.get('create_time',None)
if len(create_time) > 0:
if create_time is not None or len(create_time) > 0:
try:
self.create_time = datetime.strptime(create_time, '%Y-%m-%d %H:%M:%S')
except Exception as ex:
self.writeCtaError(u'解释create_time异常:{}'.format(str(ex)))
self.create_time = datetime.now()
self.create_time = datetime.now()
save_time = json_data.get('save_time',None)
if len(save_time)> 0:
try:
@ -253,13 +253,9 @@ class TurtlePolicy(CtaPolicy):
def __init__(self, strategy):
super(TurtlePolicy, self).__init__(strategy)
self.allow_add_pos = False # 是否加仓
self.add_pos_on_pips = EMPTY_INT # 价格超过开仓价多少点时加仓
self.tns_open_price = 0 # 首次开仓价格
self.last_open_price = 0 # 最后一次加仓价格
self.stop_price = 0 # 止损价
self.exit_on_last_rtn_pips = 0 # 最高价/最低价回撤多少跳动
self.tns_open_price = 0 # 首次开仓价格
self.last_open_price = 0 # 最后一次加仓价格
self.stop_price = 0 # 止损价
self.high_price_in_long = 0 # 多趋势时,最高价
self.low_price_in_short = 0 # 空趋势时,最低价
self.last_under_open_price = 0 # 低于首次开仓价的补仓价格
@ -283,15 +279,12 @@ class TurtlePolicy(CtaPolicy):
j['tns_open_date'] = self.tns_open_date
j['tns_open_price'] = self.tns_open_price if self.tns_open_price is not None else 0
j['allow_add_pos'] = self.allow_add_pos
j['add_pos_on_pips'] = self.add_pos_on_pips
j['exit_on_last_rtn_pips'] = self.exit_on_last_rtn_pips
j['last_open_price'] = self.last_open_price if self.last_open_price is not None else 0
j['stop_price'] = self.stop_price if self.stop_price is not None else 0
j['high_price_in_long'] = self.high_price_in_long if self.high_price_in_long is not None else 0
j['low_price_in_short'] = self.low_price_in_short if self.low_price_in_short is not None else 0
j['add_pos_count_under_first_price'] = self.add_pos_count_under_first_price if self.add_pos_count_under_first_price is not None else 0
j[
'add_pos_count_under_first_price'] = self.add_pos_count_under_first_price if self.add_pos_count_under_first_price is not None else 0
j['last_under_open_price'] = self.last_under_open_price if self.last_under_open_price is not None else 0
j['max_pos'] = self.max_pos if self.max_pos is not None else 0
@ -419,9 +412,6 @@ class TurtlePolicy(CtaPolicy):
self.writeCtaError(u'解释last_risk_level异常:{}'.format(str(ex)))
self.last_risk_level = 0
self.allow_add_pos=json_data.get('allow_add_pos',False)
self.add_pos_on_pips = json_data.get('add_pos_on_pips',1)
self.exit_on_last_rtn_pips = json_data.get('exit_on_last_rtn_pips',0)
def clean(self):
"""
@ -442,9 +432,6 @@ class TurtlePolicy(CtaPolicy):
self.tns_has_opened = False
self.last_risk_level = 0
self.tns_count = 0
self.allow_add_pos = False
self.add_pos_on_pips = 1
self.exit_on_last_rtn_pips = 0
class TrendPolicy(CtaPolicy):
"""

View File

@ -16,8 +16,8 @@ class CtaPosition:
def __init__(self, strategy):
self.strategy = strategy
self.longPos = 0 # 多仓持仓
self.shortPos = 0 # 空仓持仓
self.longPos = 0 # 多仓持仓(正数)
self.shortPos = 0 # 空仓持仓(负数)
self.pos = 0 # 持仓状态 0:空仓/对空平等; >=1 净多仓 <=-1 净空仓
self.maxPos = 1 # 最大持仓量(多仓+空仓总量)
self.step = 1 # 增仓数量
@ -45,7 +45,7 @@ class CtaPosition:
if direction == DIRECTION_LONG: # 加多仓
if (max(self.pos, self.longPos) + vol) > self.maxPos:
self.writeCtaError(u'异常,超出仓位。净:{},多:{},加多:{},最大:{}'
self.writeCtaError(u'异常,超出仓位。净:{0},多:{1},加多:{2},最大:{3}'
.format(self.pos, self.longPos, vol, self.maxPos))
# 只告警
@ -62,7 +62,7 @@ class CtaPosition:
if direction == DIRECTION_SHORT: # 加空仓
if (min(self.pos, self.shortPos) - vol) < (0 - self.maxPos):
self.writeCtaError(u'异常,超出仓位。净:{},空:{},加空:{},最大:{}'
self.writeCtaError(u'异常,超出仓位。净:{0},空:{1},加空:{2},最大:{3}'
.format(self.pos, self.shortPos, vol, self.maxPos))
#return False
@ -91,7 +91,7 @@ class CtaPosition:
if direction == DIRECTION_LONG: # 平空仓 Cover
if self.shortPos + vol > 0:
self.writeCtaError(u'异常,超出仓位。净:{},空:{},平仓:{}'.format(self.pos, self.shortPos, vol))
self.writeCtaError(u'异常,超出仓位。净:{0},空:{1},平仓:{2}'.format(self.pos, self.shortPos, vol))
#self.strategy.pos = self.pos
#return False
@ -105,7 +105,7 @@ class CtaPosition:
if direction == DIRECTION_SHORT: # 平多仓
if self.longPos - vol < 0:
self.writeCtaError(u'异常,超出仓位。净:{},多:{},平仓:{}'.format(self.pos, self.longPos, vol))
self.writeCtaError(u'异常,超出仓位。净:{0},多:{1},平仓:{2}'.format(self.pos, self.longPos, vol))
#self.strategy.pos = self.pos
#return False

View File

@ -268,7 +268,6 @@ class CtaTemplate(object):
content = self.name + ':' + content
self.ctaEngine.writeCtaLog(content, strategy_name=self.name)
except Exception as ex:
self.ctaEngine.writeCtaLog(content)
# ----------------------------------------------------------------------
@ -333,6 +332,8 @@ class CtaTemplate(object):
def getFullSymbol(self, symbol):
"""获取全路径得合约名称"""
if symbol.endswith('SPD'):
return symbol
short_symbol = self.ctaEngine.getShortSymbol(symbol)
if short_symbol == symbol:
return symbol
@ -353,7 +354,7 @@ class CtaTemplate(object):
if dt is None:
dt = datetime.now()
if dt.hour >= 21:
if dt.hour >= 20:
if dt.isoweekday() == 5:
# 星期五=》星期一
return (dt + timedelta(days=3)).strftime('%Y-%m-%d')
@ -456,7 +457,7 @@ class MatrixTemplate(CtaTemplate):
def getPositions(self):
"""
获取策略当前持仓
:return: [{'vtSymbol':symbol,'direction':direction,'volume':volume]
:return: [{'vtSymbol':symbol,'direction':direction,'volume':volume,'price':price]
"""
if not self.position:
return []
@ -515,7 +516,7 @@ class MatrixTemplate(CtaTemplate):
return
if dt.hour == 14:
if dt.minute <= 59:
if dt.minute <= 55:
self.tradeWindow = True
return
@ -556,7 +557,7 @@ class MatrixTemplate(CtaTemplate):
return
# 上期 天然橡胶 23:00
if self.shortSymbol in NIGHT_MARKET_SQ3:
if self.shortSymbol in [NIGHT_MARKET_SQ3,NIGHT_MARKET_DL]:
if dt.hour == 22:
if dt.minute <= 59: # 收市前29分钟
@ -566,8 +567,9 @@ class MatrixTemplate(CtaTemplate):
if dt.minute > 54: # 夜盘平仓
self.closeWindow = True
return
# 郑商、大连 23:30
if self.shortSymbol in NIGHT_MARKET_ZZ or self.shortSymbol in NIGHT_MARKET_DL:
if self.shortSymbol in NIGHT_MARKET_ZZ:
if dt.hour == 22:
self.tradeWindow = True
return

View File

@ -289,12 +289,9 @@ class CtaEngineManager(QtWidgets.QWidget):
#----------------------------------------------------------------------
def updateCtaLog(self, event):
"""更新CTA相关日志"""
try:
log = event.dict_['data']
content = '{}\t{}'.format(log.logTime, log.logContent)
self.ctaLogMonitor.append(content)
except Exception as ex:
print(u'update exception:{},{}'.format(str(ex),traceback.format_exc()))
log = event.dict_['data']
content = '\t'.join([log.logTime, log.logContent])
self.ctaLogMonitor.append(content)
#----------------------------------------------------------------------
def registerEvent(self):