This commit is contained in:
msincenselee 2019-01-11 22:30:23 +08:00
parent c2c8690763
commit ec89edebe5
18 changed files with 2172 additions and 895 deletions

View File

@ -74,6 +74,7 @@ QQ/Wechat28888502
wget -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-4.3.1-Linux-x86_64.sh
chmod a+x Anaconda3-4.3.1-Linux-x86_64.sh
./Anaconda3-4.3.1-Linux-x86_64.sh
.
# 配置为国内的镜像
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/

View File

@ -1920,7 +1920,7 @@ class BacktestingEngine(object):
self.writeCtaLog(u'请指定回测数据文件')
return
if not self.dataStartDate:
if not self.strategyStartDate:
self.writeCtaLog(u'回测开始日期未设置。')
return
@ -1942,8 +1942,8 @@ class BacktestingEngine(object):
#self.output(u'开始回测')
#self.strategy.inited = True
self.strategy.onInit()
self.strategy.trading = False
self.output(u'策略初始化完成')
self.output(u'开始回放数据')
@ -2013,18 +2013,24 @@ class BacktestingEngine(object):
else:
bar.tradingDay = bar.date
if self.dataStartDate <= bar.datetime <= self.dataEndDate:
if self.strategyStartDate <= bar.datetime <= self.dataEndDate:
if last_tradingDay != bar.tradingDay:
if last_tradingDay is not None:
self.savingDailyData(datetime.strptime(last_tradingDay, '%Y-%m-%d'), self.capital,
self.maxCapital,self.totalCommission,benchmark=bar.close)
last_tradingDay = bar.tradingDay
# Check the order triggers and deliver the bar to the Strategy
if self.useBreakoutMode is False:
self.newBar(bar)
else:
self.newBarForBreakout(bar)
if self.dataStartDate >= bar.datetime:
continue
if bar.datetime > self.dataEndDate:
continue
# Check the order triggers and deliver the bar to the Strategy
if self.useBreakoutMode is False:
self.newBar(bar)
else:
self.newBarForBreakout(bar)
if not self.strategy.trading and self.strategyStartDate < bar.datetime:
self.strategy.trading = True
@ -2046,7 +2052,7 @@ class BacktestingEngine(object):
added by IncenseLee
"""
self.capital = self.initCapital # 更新设置期初资金
if not self.dataStartDate:
if not self.strategyStartDate:
self.writeCtaLog(u'回测开始日期未设置。')
return
@ -2068,9 +2074,9 @@ class BacktestingEngine(object):
self.strategy.onInit()
self.output(u'策略初始化完成')
self.strategy.trading = True
self.strategy.onStart()
self.output(u'策略启动完成')
#self.strategy.trading = True
#self.strategy.onStart()
#self.output(u'策略启动完成')
self.output(u'开始载入数据')
@ -2140,8 +2146,7 @@ class BacktestingEngine(object):
# .format(bar.date+' '+bar.time, bar.open, bar.high,
# bar.low, bar.close, bar.volume, bar.tradingDay, self.lineH2.m1_bars_count))
# if not (bar.datetime < self.dataStartDate or bar.datetime >= self.dataEndDate):
if True:
if self.strategyStartDate <= bar.datetime <= self.dataEndDate:
if last_tradingDay == 0:
last_tradingDay = bar.tradingDay
elif last_tradingDay != bar.tradingDay:
@ -2149,16 +2154,21 @@ class BacktestingEngine(object):
self.savingDailyData(last_tradingDay, self.capital, self.maxCapital, self.totalCommission)
last_tradingDay = bar.tradingDay
# Simulate latest tick and send it to Strategy
simTick = self.__barToTick(bar)
# self.tick = simTick
self.strategy.curTick = simTick
# Simulate latest tick and send it to Strategy
#simTick = self.__barToTick(bar)
# self.tick = simTick
#self.strategy.curTick = simTick
# Check the order triggers and deliver the bar to the Strategy
if self.useBreakoutMode is False:
self.newBar(bar)
else:
self.newBarForBreakout(bar)
# Check the order triggers and deliver the bar to the Strategy
if self.useBreakoutMode is False:
self.newBar(bar)
else:
self.newBarForBreakout(bar)
if not self.strategy.trading and self.strategyStartDate < bar.datetime:
self.strategy.trading = True
self.strategy.onStart()
self.output(u'策略启动完成')
if self.netCapital < 0:
self.writeCtaError(u'净值低于0回测停止')
@ -2378,8 +2388,10 @@ class BacktestingEngine(object):
if not self.strategy.name:
self.strategy.name = self.strategy.className
self.strategy.onInit()
self.strategy.onStart()
if setting.get('auto_init',False):
self.strategy.onInit()
if setting.get('auto_start',False):
self.strategy.onStart()
# ---------------------------------------------------------------------
def saveStrategyData(self):
@ -3851,7 +3863,7 @@ class BacktestingEngine(object):
return d, capitalNetList, capitalList
#----------------------------------------------------------------------
# ----------------------------------------------------------------------
def showBacktestingResult(self):
"""显示回测结果"""
if self.calculateMode != self.REALTIME_MODE:

View File

@ -33,15 +33,25 @@ ATRRATE_JUMP = 1
STOPORDERPREFIX = 'CtaStopOrder.'
# 各类商品所在市场
NIGHT_MARKET_SQ1 = {'AU': 0, 'AG': 0}
NIGHT_MARKET_SQ2 = {'CU': 0, 'PB': 0, 'AL': 0, 'ZN': 0, 'FU': 0, 'BU': 0, 'WR': 0}
NIGHT_MARKET_SQ3 = {'RU': 0, 'RB': 0, 'HC': 0}
# 上期所夜盘9:00~10:15, 10:30~11:30, 13:30~15:00, 21:00 ~2:30
NIGHT_MARKET_SQ1 = {'AU': 0, 'AG': 0,'SC':0}
# 上期所夜盘9:00~10:15, 10:30~11:30, 13:30~15:00, 21:00 ~1:00
NIGHT_MARKET_SQ2 = {'CU': 0, 'PB': 0, 'AL': 0, 'ZN': 0, 'FU': 0, 'BU': 0, 'WR': 0,'NI':0}
# 上期所夜盘9:00~10:15, 10:30~11:30, 13:30~15:00, 21:00 ~23:00
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}
'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
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}
# 中金日盘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}
# 数据库名称
SETTING_DB_NAME = 'VnTrader_Setting_Db'
POSITION_DB_NAME = 'VnTrader_Position_Db'
@ -76,7 +86,6 @@ class StopOrder(object):
self.stopOrderID = EMPTY_STRING # 停止单的本地编号
self.status = EMPTY_STRING # 停止单状态
########################################################################
class CtaBarData(object):
"""K线数据"""
@ -101,7 +110,7 @@ class CtaBarData(object):
self.volume = EMPTY_INT # 成交量
self.dayVolume = EMPTY_INT # 当日累计成交量ctp是提供这个的
self.openInterest = EMPTY_INT # 持仓量
self.color = COLOR_EQUAL # k 线颜色,COLOR_REDCOLOR_BLUE,COLOR_EQUAL
self.color = COLOR_EQUAL # k 线颜色,COLOR_REDCOLOR_BLUE,COLOR_EQUAL
self.traded = False
self.tradeStatus = EMPTY_STRING # 当前bar的交易情况: CTAORDER_BUY 、CTAORDER_SELL、

View File

@ -38,8 +38,9 @@ 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.util_mail import sendmail
from vnpy.trader.vtGlobal import globalSetting
# 加载 strategy目录下所有的策略
from vnpy.trader.app.ctaStrategy.strategy import STRATEGY_CLASS
from vnpy.trader.app.ctaStrategy.strategy import STRATEGY_CLASS,reloadStrategyModule
try:
from vnpy.trader.util_wechat import *
except:
@ -463,7 +464,15 @@ class CtaEngine(object):
tick = event.dict_['data']
tick = copy.copy(tick)
# 移除待订阅的合约清单
if tick.vtSymbol in self.pendingSubcribeSymbols:
if '.' in tick.vtSymbol:
symbol = tick.vtSymbol.split('.')[0]
else:
symbol = tick.vtSymbol
if symbol in self.pendingSubcribeSymbols :
self.writeCtaLog(u'已成功订阅{0},从待订阅清单中移除'.format(symbol))
del self.pendingSubcribeSymbols[symbol]
if tick.vtSymbol in self.pendingSubcribeSymbols :
self.writeCtaLog(u'已成功订阅{0},从待订阅清单中移除'.format(tick.vtSymbol))
del self.pendingSubcribeSymbols[tick.vtSymbol]
@ -500,6 +509,10 @@ class CtaEngine(object):
order = event.dict_['data']
# order.vtOrderID 在gateway中已经格式化为 gatewayName.vtOrderID
self.writeCtaLog(u'{}vt报单,orderID:{}'.format(order.vtOrderID,order.orderID))
self.writeCtaLog(u'symbol{},totalVol:{},tradedVol:{},offset:{},price:{},direction:{},status:{}'
.format( order.vtSymbol, order.totalVolume, order.tradedVolume,
order.offset, order.price, order.direction, order.status))
# 2.判断order是否在策略的映射字典中
if order.vtOrderID in self.orderStrategyDict:
@ -534,6 +547,24 @@ class CtaEngine(object):
# else:
# strategy.pos -= trade.volume
# 根据策略名称,写入 data\straetgy_name_trade.csv文件
strategy_name = getattr(strategy,'name',None)
trade_fields = ['symbol','exchange','vtSymbol','tradeID','vtTradeID','orderID','vtOrderID','direction','offset','price','volume','tradeTime']
trade_dict = OrderedDict()
try:
for k in trade_fields:
if k == 'tradeTime':
trade_dict[k] = datetime.now().strftime('%Y-%m-%d')+' '+ getattr(trade, k, EMPTY_STRING)
else:
trade_dict[k] = getattr(trade,k,EMPTY_STRING)
if strategy_name is not None:
trade_file = os.path.abspath(os.path.join(self.get_data_path(),'{}_trade.csv'.format(strategy_name)))
self.append_data(file_name=trade_file,dict_data=trade_dict)
except Exception as ex:
self.writeCtaError(u'写入交易记录csv出错{},{}'.format(str(ex),traceback.format_exc()))
# 推送到策略onTrade事件
self.callStrategyFunc(strategy, strategy.onTrade, trade)
# 更新持仓缓存数据
@ -686,7 +717,38 @@ class CtaEngine(object):
return l
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# 保存记录相关
def append_data(self, file_name, dict_data, field_names=None):
"""
添加数据到csv文件中
:param file_name: csv的文件全路径
:param dict_data: OrderedDict
:return:
"""
if not isinstance(dict_data, dict):
self.writeCtaError(u'append_data输入数据不是dict')
return
dict_fieldnames = list(dict_data.keys()) if field_names is None else field_names
if not isinstance(dict_fieldnames, list):
self.writeCtaError(u'append_data输入字段不是list')
return
try:
if not os.path.exists(file_name):
self.writeCtaLog(u'create csv file:{}'.format(file_name))
with open(file_name, 'a', encoding='utf8', newline='') as csvWriteFile:
writer = csv.DictWriter(f=csvWriteFile, fieldnames=dict_fieldnames, dialect='excel')
self.writeCtaLog(u'write csv header:{}'.format(dict_fieldnames))
writer.writeheader()
writer.writerow(dict_data)
else:
with open(file_name, 'a', encoding='utf8', newline='') as csvWriteFile:
writer = csv.DictWriter(f=csvWriteFile, fieldnames=dict_fieldnames, dialect='excel',extrasaction='ignore')
writer.writerow(dict_data)
except Exception as ex:
self.writeCtaError(u'append_data exception:{}'.format(str(ex)))
# 日志相关
def writeCtaLog(self, content, strategy_name=None):
@ -741,8 +803,11 @@ class CtaEngine(object):
self.createLogger(strategy_name=strategy_name)
try:
self.strategy_loggers[strategy_name].error(content)
except Exception as ex:
pass
print('{}'.format(datetime.now()), file=sys.stderr)
print('could not create cta logger for {},excption:{},trace:{}'.format(strategy_name,str(ex),traceback.format_exc()))
print(content, file=sys.stderr)
self.mainEngine.writeError(content)
@ -832,6 +897,24 @@ 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
self.mainEngine.subscribe(req,None)
except Exception as ex:
self.writeCtaError(u'重新订阅{}异常:{},{}'.format(symbol, str(ex), traceback.format_exc()))
return
if strategy is not None:
if symbol not in self.tickStrategyDict:
self.tickStrategyDict.update({symbol:[strategy]})
else:
strategies = self.tickStrategyDict.get(symbol,[])
if strategy not in strategies:
strategies.append(strategy)
self.tickStrategyDict.update({symbol: strategies})
def checkUnsubscribedSymbols(self, event):
"""持仓更新信息时,检查未提交的合约"""
@ -844,12 +927,21 @@ class CtaEngine(object):
# continue
dt = datetime.now()
# 若为中金所的合约,白天才提交订阅请求
if s in MARKET_ZJ and not (9 < dt.hour < 16):
if s in MARKET_DAY_ONLY and not (9 < dt.hour < 16):
continue
self.writeCtaLog(u'重新提交合约{0}订阅请求'.format(symbol))
strategy = self.pendingSubcribeSymbols[symbol]
self.subscribe(strategy=strategy, symbol=symbol)
else:
try:
req = VtSubscribeReq()
req.symbol = symbol
self.mainEngine.subscribe(req, None)
except Exception as ex:
self.writeCtaError(u'重新订阅{}异常:{},{}'.format(symbol, str(ex), traceback.format_exc()))
return
# ----------------------------------------------------------------------
# 策略相关(加载/初始化/启动/停止)
@ -874,7 +966,7 @@ class CtaEngine(object):
return RUNING
def loadStrategy(self, setting, is_dispatch=False):
def loadStrategy(self, setting, is_dispatch=False,reload_module_name=EMPTY_STRING):
"""
载入策略
:param setting: 策略设置参数
@ -889,6 +981,11 @@ class CtaEngine(object):
self.mainEngine.writeCritical(u'载入策略出错:%s' % e)
return False
# 运行时强制重新加载策略class
if len(reload_module_name)>0:
moduleName = 'vnpy.trader.app.ctaStrategy.strategy.' + reload_module_name
reloadStrategyModule(moduleName)
# 获取策略类
strategyClass = STRATEGY_CLASS.get(className, None)
if not strategyClass:
@ -1016,25 +1113,35 @@ class CtaEngine(object):
# strategy.inited = True
else:
self.writeCtaLog(u'请勿重复初始化策略实例:%s' % name)
return True
else:
self.writeCtaError(u'策略实例不存在:%s' % name)
return False
def startStrategy(self, name):
"""启动策略"""
# 1.判断策略名称是否存在字典中
if name in self.strategyDict:
# 2.提取策略
strategy = self.strategyDict[name]
try:
# 2.提取策略
strategy = self.strategyDict[name]
# 3.判断策略是否运行
if strategy.inited and not strategy.trading:
# 4.设置运行状态
strategy.trading = True
# 5.启动策略
self.callStrategyFunc(strategy, strategy.onStart)
except Exception as ex:
self.writeCtaError(u'start Strategy:{} Exception:{},{}'.format(name,str(ex),traceback.format_exc()))
return False
return True
# 3.判断策略是否运行
if strategy.inited and not strategy.trading:
# 4.设置运行状态
strategy.trading = True
# 5.启动策略
self.callStrategyFunc(strategy, strategy.onStart)
else:
self.writeCtaError(u'策略实例不存在:%s' % name)
return False
def stopStrategy(self, name):
"""停止策略运行"""
@ -1059,8 +1166,85 @@ class CtaEngine(object):
for stopOrderID, so in self.workingStopOrderDict.items():
if so.strategy is strategy:
self.cancelStopOrder(stopOrderID)
return True
else:
self.writeCtaError(u'策略实例不存在:%s' % name)
return False
def reloadStrategy(self,strategy_name,strategy_setting=None):
"""
重新加载策略
:param strategy_name:策略实例名
:param strategy_setting: 新的策略设置
:return:
"""
if strategy_setting:
if strategy_name != strategy_setting.get('name',None):
msg = u'重新加载策略配置参数name:{}{}不一致'.format(strategy_setting.get('name',None),strategy_name)
self.writeCtaError(msg)
return False,msg
# 更新配置
self.writeCtaLog(u'使用新的配置:{}'.format(strategy_setting))
self.settingDict.update({strategy_name:strategy_setting})
self.saveSetting()
else:
self.writeCtaLog(u'重新加载{}中的{}配置'.format(self.settingfilePath,strategy_name))
with open(self.settingfilePath,'r',encoding='UTF-8') as f:
settings = json.load(f)
for setting in settings:
if strategy_name == setting.get('name', None):
strategy_setting = copy.copy(setting)
self.writeCtaLog(u'配置:{}'.format(strategy_setting))
self.settingDict.update({strategy_name: strategy_setting})
if strategy_setting is None:
msg = u'{}文件没有{}的配置'.format(self.settingfilePath,strategy_name)
self.writeCtaError(msg)
return False,msg
self.writeCtaLog(u'开始移除运行中的策略{}'.format(strategy_name))
try:
strategy = self.strategyDict.get(strategy_name,None)
if strategy:
# 1、将运行dict的策略移除.
self.strategyDict[strategy_name] = None
self.writeCtaLog(u'将运行dict的策略{}关联移除'.format(strategy_name))
self.strategyDict.pop(strategy_name, None)
strategy.trading = False
# 2、撤销所有委托单
if hasattr(strategy, 'cancelAllOrders'):
self.writeCtaLog(u'撤销所有委托单')
strategy.cancelAllOrders()
# 3、移除行情订阅信息
self.writeCtaLog(u'将策略{}从合约-策略列表中移除'.format(strategy.name))
for vtSymbol in list(self.tickStrategyDict.keys()):
symbol_strategy_list = self.tickStrategyDict.get(vtSymbol,[])
if strategy in symbol_strategy_list:
self.writeCtaLog(u'移除策略{}{}订阅'.format(strategy_name, vtSymbol))
symbol_strategy_list.remove(strategy)
strategy = None
except Exception as ex:
errMsg = u'移除策略异常:{},{}'.format(str(ex), traceback.format_exc())
self.writeCtaCritical(errMsg)
traceback.print_exc()
return False, errMsg
try:
self.writeCtaLog(u'重新加载策略:{}'.format(strategy_name))
self.loadStrategy(setting=strategy_setting,reload_module_name=strategy_setting.get('strategy_module',EMPTY_STRING))
return True,u'重新加载策略:{}成功'.format(strategy_name)
except Exception as ex:
errMsg = u'加载策略{}异常:{},{}'.format(strategy_name,str(ex), traceback.format_exc())
self.writeCtaCritical(errMsg)
return False, errMsg
def removeStrategy(self, strategy_name):
"""
@ -1068,8 +1252,10 @@ class CtaEngine(object):
:param strategy_name: 策略实例名
:return: True/FalseerrMsg
"""
self.writeCtaLog(u'开始移除策略{}'.format(strategy_name))
# 移除策略设置,下次启动不再执行该设置
if strategy_name in self.settingDict:
self.writeCtaLog(u'移除CTA_Setting中策略{}配置'.format(strategy_name))
self.settingDict.pop(strategy_name, None)
try:
@ -1089,15 +1275,15 @@ class CtaEngine(object):
# 3、将策略的持仓登记在dispatch_long_pos/dispatch_short_pos,移除json文件
if strategy.inited and strategy.position is not None and (
strategy.position.longPos != 0 or strategy.position.shortPos != 0):
pos_list = self.getStategyPos(name=strategy.name,strategy=strategy)
strategy.inited = False
pos_list = strategy.getPositions()
self.writeCtaLog(u'被移除策略{}的持仓情况:{}'.format(strategy.name, pos_list))
if len(pos_list) > 0:
for pos in pos_list:
# 添加多头持仓
if pos['direction'] == DIRECTION_LONG and pos['volume'] > 0:
symbol = pos['vtSymbol']
if pos['direction'] in [DIRECTION_LONG,'long'] and pos['volume'] > 0:
symbol = pos['symbol']
# 这里有bug盘前调度超时时间一定要设置到开盘时间
d = {
'strategy_group': self.strategy_group,
'strategy': strategy.name,
@ -1119,9 +1305,9 @@ class CtaEngine(object):
self.mainEngine.dbInsert(MATRIX_DB_NAME, POSITION_DISPATCH_HISTORY_COLL_NAME, h)
# 添加空头持仓
if pos['direction'] == DIRECTION_SHORT and pos['volume'] > 0:
symbol = pos['vtSymbol']
if pos['direction'] in [DIRECTION_SHORT,'short'] and pos['volume'] > 0:
symbol = pos['symbol']
# 这里有bug盘前调度超时时间一定要设置到开盘时间
d = {
'strategy_group': self.strategy_group,
'strategy': strategy.name,
@ -1181,6 +1367,10 @@ class CtaEngine(object):
traceback.print_exc()
return False, errMsg
def getStrategyNames(self):
"""返回策略实例名称"""
return list(self.strategyDict.keys())
def get_data_path(self):
"""
获取CTA策略的对应数据目录
@ -1502,6 +1692,7 @@ class CtaEngine(object):
'result': False, 'datetime': datetime.now()}
self.mainEngine.dbInsert(MATRIX_DB_NAME, POSITION_DISPATCH_HISTORY_COLL_NAME, h)
# 这里有bug盘前调度超时时间一定要设置到开盘时间
d = {
'strategy_group': self.strategy_group,
'strategy': 'onOrder_dispatch_close_pos',
@ -1526,6 +1717,7 @@ class CtaEngine(object):
'retry': old_order['retry']+1}
else:
# 这里有bug盘前调度超时时间一定要设置到开盘时间
d = {
'strategy_group': self.strategy_group,
'strategy': 'onOrder_dispatch_close_pos',
@ -1655,9 +1847,42 @@ class CtaEngine(object):
"""保存策略配置"""
try:
with open(self.settingfilePath, 'w') as f:
l = list(self.settingDict.values())
jsonL = json.dumps(l, indent=4)
# 策略名称,排序
keys = list(self.settingDict.keys())
sorted_keys = sorted(keys)
# 保存列表
save_list = []
for strategy_name in sorted_keys:
# 策略配置
setting_dict = self.settingDict.get(strategy_name,None)
if setting_dict is None:
self.writeCtaError(u'保存策略配置时找不到配置dict中name={}的策略配置'.format(strategy_name))
continue
sorted_setting_dict = OrderedDict()
# 配置参数排序
setting_keys = list(setting_dict.keys())
sorted_setting_keys = sorted(setting_keys)
# 先保存name,comment
sorted_setting_dict['name'] = strategy_name
if 'comment' in setting_dict:
sorted_setting_dict['comment'] = setting_dict['comment']
# 其他参数,逐一
for setting_key in sorted_setting_keys:
if setting_key in ['name','comment']:
continue
sorted_setting_dict[setting_key] = setting_dict[setting_key]
save_list.append(sorted_setting_dict)
# 导出json格式的string保存文件
jsonL = json.dumps(save_list, indent=4,ensure_ascii=False)
f.write(jsonL)
except Exception as ex:
self.writeCtaCritical(u'保存策略配置异常:{},{}'.format(str(ex),traceback.format_exc()))
@ -1715,59 +1940,66 @@ class CtaEngine(object):
self.writeCtaLog(u'策略实例不存在:' + name)
return None
def getStategyPos(self, name):
def getStategyPos(self, name,strategy=None):
"""
获取策略的持仓字典
:param name:策略名
:return:
"""
if name in self.strategyDict:
# 兼容处理如果strategy是None通过name获取
if strategy is None:
if name not in self.strategyDict:
self.writeCtaLog(u'getStategyPos 策略实例不存在:' + name)
return []
# 获取策略实例
strategy = self.strategyDict[name]
pos_list = []
if strategy.inited:
# 有 ctaPosition属性
if hasattr(strategy, 'position'):
# 多仓
pos_list = []
if strategy.inited:
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'):
# 多仓
long_pos = {}
long_pos['symbol'] = strategy.vtSymbol
long_pos['direction'] = 'long'
long_pos['volume'] = strategy.position.longPos
if long_pos['volume'] > 0:
pos_list.append(long_pos)
# 空仓
short_pos = {}
short_pos['symbol'] = strategy.vtSymbol
short_pos['direction'] = 'short'
short_pos['volume'] = abs(strategy.position.shortPos)
if short_pos['volume'] > 0:
pos_list.append(short_pos)
# 模板缺省pos属性
elif hasattr(strategy, 'pos'):
if strategy.pos > 0:
long_pos = {}
long_pos['symbol'] = strategy.vtSymbol
long_pos['direction'] = 'long'
long_pos['volume'] = strategy.position.longPos
long_pos['volume'] = strategy.pos
#long_pos['datetime'] = datetime.now()
if long_pos['volume'] > 0:
pos_list.append(long_pos)
# 空仓
elif strategy.pos < 0:
short_pos = {}
short_pos['symbol'] = strategy.vtSymbol
short_pos['direction'] = 'short'
short_pos['volume'] = abs(strategy.position.shortPos)
short_pos['volume'] = abs(strategy.pos)
#short_pos['datetime'] = datetime.now()
if short_pos['volume'] > 0:
pos_list.append(short_pos)
# 模板缺省pos属性
elif hasattr(strategy, 'pos'):
if strategy.pos > 0:
long_pos = {}
long_pos['symbol'] = strategy.vtSymbol
long_pos['direction'] = 'long'
long_pos['volume'] = strategy.pos
#long_pos['datetime'] = datetime.now()
if long_pos['volume'] > 0:
pos_list.append(long_pos)
elif strategy.pos < 0:
short_pos = {}
short_pos['symbol'] = strategy.vtSymbol
short_pos['direction'] = 'short'
short_pos['volume'] = abs(strategy.pos)
#short_pos['datetime'] = datetime.now()
if short_pos['volume'] > 0:
pos_list.append(short_pos)
return pos_list
else:
self.writeCtaLog(u'getStategyPos 策略实例不存在:' + name)
return []
return pos_list
def updateStrategySetting(self,strategy_name,setting_key,setting_value):
"""
@ -1839,9 +2071,7 @@ class CtaEngine(object):
self.writeCtaError(content)
self.mainEngine.writeCritical(content)
if hasattr(strategy,'backtesting') and hasattr(strategy,'wechat_source'):
if not strategy.backtesting and len(strategy.wechat_source)>0:
self.sendAlertToWechat(content=content,target=strategy.wechat_source)
self.sendAlertToWechat(content=content,target=globalSetting.get('gateway_name',None))
# ----------------------------------------------------------------------
# 仓位持久化相关
@ -1881,20 +2111,32 @@ class CtaEngine(object):
if not priceTick:
return price
newPrice = round(price / priceTick, 0) * priceTick
if price > 0:
# 根据最小跳动取整
newPrice = price - price % priceTick
else:
# 兼容套利品种的负数价格
newPrice = round(price / priceTick, 0) * priceTick
# 数字货币,对浮点的长度有要求,需要砍除多余
if isinstance(priceTick,float):
price_exponent = decimal.Decimal(str(newPrice))
tick_exponent = decimal.Decimal(str(priceTick))
if abs(price_exponent.as_tuple().exponent) > abs(tick_exponent.as_tuple().exponent):
newPrice = round(newPrice, ndigits=abs(tick_exponent.as_tuple().exponent))
newPrice = float(str(newPrice))
if price!=newPrice:
self.writeCtaLog(u'roundToPriceTick:{}=>{} by {}'.format(price,newPrice,priceTick))
return newPrice
def roundToVolumeTick(self,volumeTick,volume):
if volumeTick == 0:
return volume
newVolume = round(volume / volumeTick, 0) * volumeTick
# 取整
newVolume = volume - volume % volumeTick
if isinstance(volumeTick,float):
v_exponent = decimal.Decimal(str(newVolume))
vt_exponent = decimal.Decimal(str(volumeTick))
@ -1902,6 +2144,8 @@ class CtaEngine(object):
newVolume = round(newVolume, ndigits=abs(vt_exponent.as_tuple().exponent))
newVolume = float(str(newVolume))
if volume !=newVolume:
self.writeCtaLog(u'roundToVolumeTick:{}=>{} by {}'.format(volume,newVolume,volumeTick))
return newVolume
def getShortSymbol(self, symbol):

View File

@ -942,6 +942,9 @@ class CtaGridTrade(object):
:param direction:
:return:
"""""
# 回测模式不保存
if self.strategy and getattr(self.strategy,'backtesting',False):
return
# 更新开仓均价
self.recount_avg_open_price()
@ -2260,6 +2263,9 @@ class CtaLegacyGridTrade(object):
:param direction:
:return:
"""""
# 回测模式不保存
if self.strategy and getattr(self.strategy, 'backtesting', False):
return
# 更新开仓均价
self.recount_avg_open_price()
@ -2758,6 +2764,10 @@ class ArbitrageTrade(object):
self.writeCtaError(u'策略对象为空,不能保存')
return
# 回测模式不保存
if self.strategy and getattr(self.strategy, 'backtesting', False):
return
json_file = os.path.abspath(
os.path.join(self.get_data_folder(), u'{}_AGrids.json'.format(self.strategy.name)))

File diff suppressed because it is too large Load Diff

View File

@ -63,16 +63,21 @@ class CtaPolicy(object):
"""
self.writeCtaLog(u'将数据从json_data中恢复')
if 'create_time' in json_data:
self.create_time = datetime.now()
create_time = json_data.get('create_time',None)
if len(create_time) > 0:
try:
self.create_time = datetime.strptime(json_data['create_time'], '%Y-%m-%d %H:%M:%S')
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()
if 'save_time' in json_data:
self.create_time = datetime.now()
save_time = json_data.get('save_time',None)
if len(save_time)> 0:
try:
self.save_time = datetime.strptime(json_data['save_time'], '%Y-%m-%d %H:%M:%S')
self.save_time = datetime.strptime(save_time, '%Y-%m-%d %H:%M:%S')
except Exception as ex:
self.writeCtaError(u'解释save_time异常:{}'.format(str(ex)))
self.save_time = datetime.now()
@ -90,12 +95,12 @@ class CtaPolicy(object):
with open(json_file, 'r', encoding='utf8') as f:
# 解析json文件
json_data = json.load(f)
except IOError as ex:
except Exception as ex:
self.writeCtaError(u'读取Policy文件{}出错,ex:{}'.format(json_file,str(ex)))
json_data = {}
# 从持久化文件恢复数据
self.fromJson(json_data)
# 从持久化文件恢复数据
self.fromJson(json_data)
def save(self):
"""
@ -106,13 +111,22 @@ class CtaPolicy(object):
os.path.join(self.get_data_folder(), u'{}_Policy.json'.format(self.strategy.name)))
try:
json_data = self.toJson()
# 修改为:回测时不保存
if self.strategy and self.strategy.backtesting:
json_data['save_time'] = self.strategy.curDateTime.strftime('%Y-%m-%d %H:%M:%S')
else:
json_data['save_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
return
#json_data = self.toJson()
#if self.strategy and self.strategy.backtesting:
# dt = getattr(self.strategy,'curDateTime')
# if dt is not None:
# json_data['save_time'] = self.strategy.curDateTime.strftime('%Y-%m-%d %H:%M:%S')
# else:
# json_data['save_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
#else:
# json_data['save_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
json_data = self.toJson()
json_data['save_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
with open(json_file, 'w') as f:
data = json.dumps(json_data, indent=4)
f.write(data)
@ -125,6 +139,9 @@ class CtaPolicy(object):
导出历史
:return:
"""
if getattr(self.strategy,'curDateTime') is None:
return
export_dir = os.path.abspath(os.path.join(
self.get_data_folder(),
'export_csv',
@ -285,16 +302,21 @@ class TurtlePolicy(CtaPolicy):
:param json_data:
:return:
"""
if 'create_time' in json_data:
self.create_time = datetime.now()
create_time = json_data.get('create_time', None)
if len(create_time) > 0:
try:
self.create_time = datetime.strptime(json_data['create_time'], '%Y-%m-%d %H:%M:%S')
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()
if 'save_time' in json_data:
self.create_time = datetime.now()
save_time = json_data.get('save_time', None)
if len(save_time) > 0:
try:
self.save_time = datetime.strptime(json_data['save_time'], '%Y-%m-%d %H:%M:%S')
self.save_time = datetime.strptime(save_time, '%Y-%m-%d %H:%M:%S')
except Exception as ex:
self.writeCtaError(u'解释save_time异常:{}'.format(str(ex)))
self.save_time = datetime.now()
@ -485,16 +507,21 @@ class TrendPolicy(CtaPolicy):
:param json_data:
:return:
"""
if 'create_time' in json_data:
self.create_time = datetime.now()
create_time = json_data.get('create_time', None)
if len(create_time) > 0:
try:
self.create_time = datetime.strptime(json_data['create_time'], '%Y-%m-%d %H:%M:%S')
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()
if 'save_time' in json_data:
self.create_time = datetime.now()
save_time = json_data.get('save_time', None)
if len(save_time) > 0:
try:
self.save_time = datetime.strptime(json_data['save_time'], '%Y-%m-%d %H:%M:%S')
self.save_time = datetime.strptime(save_time, '%Y-%m-%d %H:%M:%S')
except Exception as ex:
self.writeCtaError(u'解释save_time异常:{}'.format(str(ex)))
self.save_time = datetime.now()

View File

@ -45,7 +45,7 @@ class CtaPosition:
if direction == DIRECTION_LONG: # 加多仓
if (max(self.pos, self.longPos) + vol) > self.maxPos:
self.writeCtaError(u'异常,超出仓位。净:{0},多:{1},加多:{2},最大:{3}'
self.writeCtaError(u'异常,超出仓位。净:{},多:{},加多:{},最大:{}'
.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'异常,超出仓位。净:{0},空:{1},加空:{2},最大:{3}'
self.writeCtaError(u'异常,超出仓位。净:{},空:{},加空:{},最大:{}'
.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'异常,超出仓位。净:{0},空:{1},平仓:{2}'.format(self.pos, self.shortPos, vol))
self.writeCtaError(u'异常,超出仓位。净:{},空:{},平仓:{}'.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'异常,超出仓位。净:{0},多:{1},平仓:{2}'.format(self.pos, self.longPos, vol))
self.writeCtaError(u'异常,超出仓位。净:{},多:{},平仓:{}'.format(self.pos, self.longPos, vol))
#self.strategy.pos = self.pos
#return False

View File

@ -96,7 +96,12 @@ class CtaTemplate(object):
def onOrder(self, order):
"""收到委托变化推送(必须由用户继承实现)"""
raise NotImplementedError
# ----------------------------------------------------------------------
def onStopOrder(self, orderRef):
"""停止单更新"""
self.writeCtaLog(u'停止单触发orderRef:{}'.format(orderRef))
# ----------------------------------------------------------------------
def onTrade(self, trade):
"""收到成交推送(必须由用户继承实现)"""
@ -302,7 +307,6 @@ class CtaTemplate(object):
try:
self.ctaEngine.writeCtaCritical(content,strategy_name=self.name)
except Exception as ex:
self.ctaEngine.writeCtaCritical(content)
else:
@ -380,6 +384,7 @@ class CtaTemplate(object):
return
try:
if not os.path.exists(file_name):
# 写入表头
self.writeCtaLog(u'create csv file:{}'.format(file_name))
with open(file_name, 'a', encoding='utf8', newline='') as csvWriteFile:
writer = csv.DictWriter(f=csvWriteFile, fieldnames=dict_fieldnames, dialect='excel')
@ -387,9 +392,11 @@ class CtaTemplate(object):
writer.writeheader()
writer.writerow(dict_data)
else:
# 写入数据
with open(file_name, 'a', encoding='utf8', newline='') as csvWriteFile:
writer = csv.DictWriter(f=csvWriteFile, fieldnames=dict_fieldnames, dialect='excel')
writer = csv.DictWriter(f=csvWriteFile, fieldnames=dict_fieldnames, dialect='excel',extrasaction='ignore')
writer.writerow(dict_data)
except Exception as ex:
self.writeCtaError(u'append_data exception:{}'.format(str(ex)))
@ -453,15 +460,16 @@ class MatrixTemplate(CtaTemplate):
"""
if not self.position:
return []
l = []
pos_list = []
if self.position.longPos > 0:
l.append({'vtSymbol': self.vtSymbol, 'direction': DIRECTION_LONG, 'volume': self.position.longPos})
pos_list.append({'vtSymbol': self.vtSymbol, 'direction': 'long', 'volume': self.position.longPos})
if abs(self.position.shortPos) > 0:
l.append({'vtSymbol': self.vtSymbol, 'direction': DIRECTION_SHORT, 'volume': abs(self.position.shortPos)})
pos_list.append({'vtSymbol': self.vtSymbol, 'direction': 'short', 'volume': abs(self.position.shortPos)})
self.writeCtaLog(u'当前持仓:{}'.format(l))
return l
if len(pos_list)>0:
self.writeCtaLog(u'当前持仓:{}'.format(pos_list))
return pos_list
def timeWindow(self, dt):
"""交易与平仓窗口"""

View File

@ -5,7 +5,7 @@
如果重复工作目录的strategy优先
'''
import os
import os,sys
import importlib
import traceback
@ -33,6 +33,27 @@ def loadStrategyModule(moduleName):
print('Failed to import strategy file %s:' % moduleName)
print('Exception:{},{}'.format(str(ex),traceback.format_exc()))
# ----------------------------------------------------------------------
def reloadStrategyModule(moduleName):
"""使用importlib动态重新载入模块"""
try:
print('reloading {}'.format(moduleName))
module = importlib.import_module(moduleName)
module = importlib.reload(module)
# 遍历模块下的对象,只有名称中包含'Strategy'的才是策略类
for k in dir(module):
if 'Strategy' in k:
print('reloading: add {} into STRATEGY_CLASS'.format(k))
v = module.__getattribute__(k)
if k in STRATEGY_CLASS:
print('Replace strategy {} with {}'.format(k, moduleName))
STRATEGY_CLASS[k] = v
except Exception as ex:
print('-' * 20)
print('Failed to reload strategy file %s:' % moduleName,file=sys.stderr)
print('Exception:{},{}'.format(str(ex), traceback.format_exc()), file=sys.stderr)
# 获取目录路径
path = os.path.abspath(os.path.dirname(__file__))

View File

@ -49,7 +49,11 @@ class CtaValueMonitor(QtWidgets.QTableWidget):
# 新增数据
col = 0
for k, v in data.items():
cell = QtWidgets.QTableWidgetItem(v)
#if isinstance(v,dict):
# item = u'{}'.format(v)
#else:
# item = v
cell = QtWidgets.QTableWidgetItem(str(v))
self.keyCellDict[k] = cell
self.setItem(0, col, cell)
col += 1
@ -285,9 +289,12 @@ class CtaEngineManager(QtWidgets.QWidget):
#----------------------------------------------------------------------
def updateCtaLog(self, event):
"""更新CTA相关日志"""
log = event.dict_['data']
content = '\t'.join([log.logTime, log.logContent])
self.ctaLogMonitor.append(content)
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()))
#----------------------------------------------------------------------
def registerEvent(self):

View File

@ -77,7 +77,7 @@ class BasicMonitor(object):
# v = v.decode('gbk')
# except:
# v = v.decode('utf8')
s.append('%s: %s' % (value['chinese'], v))
s.append('%s: %s' % (value['chinese'], str(v)))
if self.logger is not None:
self.logger.info(' '.join(s))

72
vnpy/trader/util_wx_ft.py Normal file
View File

@ -0,0 +1,72 @@
# -*- coding:utf-8 -*-
'''
通过FTQQ发送Weixin的消息
http://sc.ftqq.com/3.version
'''
from threading import Lock,Thread
import requests
import json
import sys
import traceback
from urllib.parse import urlencode
from datetime import datetime
global wxft_lock
wxft_lock = Lock()
# 这里可以设置多个微信接受者的Token,列表方式添加就好
SEC_TOKENS = ['SCU3803xxxxcc2e70f64d']
class wxft_thread(Thread):
def __init__(self,token, text, desp):
# text消息标题最长为256必填。
# desp消息内容最长64Kb可空支持MarkDown。
super(wxft_thread, self).__init__(name="wxft_thread")
self.url = "https://sc.ftqq.com/{}.send".format(token)
self.token = token
self.text = text
self.desp = desp
self.lock = wxft_lock
def run(self):
if self.text is None or len(self.text)==0:
return
params = {}
params['text'] = self.text
params['desp'] = self.desp
# 发送请求
try:
response = requests.get(self.url,params=urlencode(params))
except Exception as e:
print("{} wx_ft sent failed! ex:{},trace:{}".format(datetime.now(),str(e),traceback.format_exc()),file=sys.stderr)
return
print("wx_ft sent successful!")
def sendWxMsg(text = '',desp = ''):
"""
发送微信Msg
:param chat_id: 接收者ID,空值时直接发发送给i-quant群组列表时就逐一发送
:param parse_mode: 发送内容格式(普通文本Markdownhtml
:param text: 发送内容
:return:
"""
if len(text) == 0:
return
for token in SEC_TOKENS:
t = wxft_thread(token=token,text=text,desp=desp)
t.daemon = False
# t.run()
t.start()
if __name__ == '__main__':
text = u'测试标题!!!!\n第二行'
desp = u'测试备注\n第二行备注'
sendWxMsg(text,desp)

View File

@ -293,6 +293,7 @@ class MainEngine(object):
"""退出程序前调用,保证正常退出"""
# 安全关闭所有接口
for gateway in list(self.gatewayDict.values()):
self.writeLog(u'vtEngine退出,关闭接口')
gateway.close()
# 停止事件引擎
@ -323,6 +324,7 @@ class MainEngine(object):
# 断开所有的gateway
for gateway in list(self.gatewayDict.values()):
self.writeLog(u'vtEngine.disconnect()断开所有的gateway')
gateway.close()
return True
@ -376,10 +378,7 @@ class MainEngine(object):
# 写入本地log日志
if self.logger is not None:
self.logger.error(content)
print('{}'.format(datetime.now()),file=sys.stderr)
print(content, file=sys.stderr)
else:
print(content, file=sys.stderr)
self.createLogger()
# 发出邮件/微信
@ -401,6 +400,9 @@ class MainEngine(object):
event.dict_['data'] = log
self.eventEngine.put(event)
print('{}'.format(datetime.now()), file=sys.stderr)
print(content, file=sys.stderr)
# 写入本地log日志
if self.logger is not None:
self.logger.warning(content)
@ -459,13 +461,13 @@ class MainEngine(object):
event.dict_['data'] = log
self.eventEngine.put(event)
print('{}'.format(datetime.now()), file=sys.stderr)
print(content, file=sys.stderr)
# 写入本地log日志
if self.logger:
self.logger.critical(content)
print('{}'.format(datetime.now()), file=sys.stderr)
print(content, file=sys.stderr)
else:
print(content, file=sys.stderr)
self.createLogger()
# 发出邮件
@ -693,9 +695,6 @@ class MainEngine(object):
if self.db_has_connected:
self.writeLog(u'重新尝试连接数据库')
self.dbConnect()
except AutoReconnect as ex:
self.writeError(u'数据库连接断开重连:{}'.format(str(ex)))
time.sleep(1)
except Exception as ex:
self.writeError(u'dbDelete exception:{}'.format(str(ex)))
@ -773,16 +772,18 @@ class MainEngine(object):
def startStrategy(self,name):
if not self.ctaEngine:
self.writeError(u'Cta Engine not started')
return
return False
self.ctaEngine.startStrategy(name=name)
self.qryStatus()
return True
def stopStrategy(self,name):
if not self.ctaEngine:
self.writeError(u'Cta Engine not started')
return
return False
self.ctaEngine.stopStrategy(name=name)
self.qryStatus()
return True
########################################################################
class DataEngine(object):
@ -818,6 +819,13 @@ class DataEngine(object):
def updateContract(self, event):
"""更新合约数据"""
contract = event.dict_['data']
if contract.vtSymbol.endswith('99'):
old_contract = self.contractDict.get(contract.vtSymbol,None)
if old_contract is not None:
contract.size = max(contract.size, old_contract.size)
contract.longMarginRatio = max(contract.longMarginRatio,old_contract.longMarginRatio)
contract.shortMarginRatio = max(contract.shortMarginRatio, old_contract.shortMarginRatio)
self.contractDict[contract.vtSymbol] = contract
self.contractDict[contract.symbol] = contract # 使用常规代码(不包括交易所)可能导致重复

View File

@ -9,6 +9,7 @@ import decimal
import json
from datetime import datetime
import importlib
import re
MAX_NUMBER = 10000000000000
MAX_DECIMAL = 8
@ -29,6 +30,43 @@ def floatToStr(float_str):
else:
return float_str
def getShortSymbol(symbol):
"""取得合约的短号"""
# 套利合约
if symbol.find(' ') != -1:
# 排除SP SPC SPD
s = symbol.split(' ')
if len(s) < 2:
return symbol
symbol = s[1]
# 只提取leg1合约
if symbol.find('&') != -1:
s = symbol.split('&')
if len(s) < 2:
return symbol
symbol = s[0]
p = re.compile(r"([A-Z]+)[0-9]+", re.I)
shortSymbol = p.match(symbol)
if shortSymbol is None:
return symbol
return shortSymbol.group(1)
def getFullSymbol(symbol):
"""获取全路径得合约名称"""
short_symbol = getShortSymbol(symbol)
if short_symbol == symbol:
return symbol
symbol_month = symbol.replace(short_symbol, '')
if len(symbol_month) == 3:
return '{0}1{1}'.format(short_symbol, symbol_month)
else:
return symbol
# -----------------------------------------
def systemSymbolToVnSymbol(symbol):
"""
@ -252,7 +290,6 @@ def save_text_to_excel(file_name, sheet_name, text):
print(u'save_text_to_excel exception:{}'.format(str(ex)), traceback.format_exc(),file=sys.stderr)
return False
def save_images_to_excel(file_name, sheet_name, image_names):
"""
# 保存图形文件到excel

View File

@ -212,3 +212,16 @@ class VtGateway(object):
if self.logger:
self.logger.error(content)
# ----------------------------------------------------------------------
def printDict(self,d):
"""返回dict的字符串类型"""
if not isinstance(d,dict):
return EMPTY_STRING
l = d.keys()
l = sorted(l)
str = EMPTY_STRING
for k in l:
str +=u'{}:{}\n'.format(k, d[k])
return str

View File

@ -1,74 +0,0 @@
# encoding: UTF-8
# 重载sys模块设置默认字符串编码方式为utf8
import sys
#reload(sys)
#sys.setdefaultencoding('utf8')
import sys
import os
import ctypes
import platform
system = platform.system()
# 将repostory的目录作为根目录添加到系统环境中。
ROOT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..' , '..'))
sys.path.append(ROOT_PATH)
from vnpy.trader.vtEngine import MainEngine
from vnpy.trader.uiQt import createQApp
from vnpy.trader.uiMainWindow import *
# 加载底层接口
from vnpy.trader.gateway import ctpGateway
# 初始化的接口模块,以及其指定的名称,CTP是模块value是该模块下的多个连接配置文件,如 CTP_JR_connect.json 'CTP_Prod', 'CTP_JR', , 'CTP_JK', 'CTP_02'
init_gateway_names = {'CTP': ['CTP','CTP_YH01', 'CTP_YH02', 'CTP_YH03','CTP_JK','CTP_Huafu001','CTP_Huafu002']}
from vnpy.trader.app import (ctaStrategy, riskManager, spreadTrading)
# 文件路径名
path = os.path.abspath(os.path.dirname(__file__))
ICON_FILENAME = 'vnpy.ico'
ICON_FILENAME = os.path.join(path, ICON_FILENAME)
from vnpy.trader.setup_logger import setup_logger
# ----------------------------------------------------------------------
def main():
"""主程序入口"""
logger = setup_logger(filename='logs/vnpy.log', debug=False)
# 创建Qt应用对象
qApp = createQApp()
# 创建事件引擎
ee = EventEngine2()
# 初始化主引擎和主窗口对象
mainEngine = MainEngine(ee)
mainEngine.logger = logger
# 添加Gatway
for gw_name in init_gateway_names['CTP']:
print('add {0}'.format(gw_name))
mainEngine.addGateway(ctpGateway, gw_name)
# 添加应用
mainEngine.addApp(ctaStrategy)
mainEngine.addApp(riskManager)
mainEngine.addApp(spreadTrading)
mainWindow = MainWindow(mainEngine, ee)
mainWindow.showMaximized()
# 在主线程中启动Qt事件循环
sys.exit(qApp.exec_())
if __name__ == '__main__':
try:
main()
except Exception as ex:
print(str(ex))
traceback.print_exc()

View File

@ -1,116 +0,0 @@
# encoding: utf-8
import os
import sys
import ctypes
from datetime import datetime, timedelta, date
from time import sleep
from threading import Thread
# 将repostory的目录i作为根目录添加到系统环境中。
ROOT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..','..'))
sys.path.append(ROOT_PATH)
from datetime import datetime
from time import sleep
from threading import Thread
import vtEvent
from vnpy.rpc import RpcServer
from vnpy.trader.vtEngine import MainEngine
from vnpy.trader.gateway import ctpGateway
init_gateway_names = {'CTP': ['CTP', 'CTP_Prod', 'CTP_Post', 'CTP_EBF', 'CTP_JR', 'CTP_JR2']}
########################################################################
class VtServer(RpcServer):
"""vn.trader服务器"""
#----------------------------------------------------------------------
def __init__(self, repAddress, pubAddress):
"""Constructor"""
super(VtServer, self).__init__(repAddress, pubAddress)
self.usePickle()
# 创建主引擎对象
self.engine = MainEngine()
for gw_name in init_gateway_names['CTP']:
print( 'add {0}'.format(gw_name))
self.engine.addGateway(ctpGateway, gw_name)
# 注册主引擎的方法到服务器的RPC函数
self.register(self.engine.connect)
self.register(self.engine.disconnect)
self.register(self.engine.subscribe)
self.register(self.engine.sendOrder)
self.register(self.engine.cancelOrder)
self.register(self.engine.qryAccount)
self.register(self.engine.qryPosition)
self.register(self.engine.checkGatewayStatus) # 检测gateway的连接状态
self.register(self.engine.qryStatus) # 检测ctaEngine的状态
self.register(self.engine.exit)
self.register(self.engine.writeLog)
self.register(self.engine.dbConnect)
self.register(self.engine.dbInsert)
self.register(self.engine.dbQuery)
self.register(self.engine.dbUpdate)
self.register(self.engine.getContract)
self.register(self.engine.getAllContracts)
self.register(self.engine.getOrder)
self.register(self.engine.getAllWorkingOrders)
self.register(self.engine.getAllGatewayNames)
self.register(self.engine.saveData)
# 注册事件引擎发送的事件处理监听
self.engine.eventEngine.registerGeneralHandler(self.eventHandler)
#----------------------------------------------------------------------
def eventHandler(self, event):
"""事件处理"""
self.publish(event.type_, event)
#----------------------------------------------------------------------
def stopServer(self):
"""停止服务器"""
# 关闭引擎
self.engine.exit()
# 停止服务器线程
self.stop()
#----------------------------------------------------------------------
def printLog(content):
"""打印日志"""
print( datetime.now().strftime("%H:%M:%S"), '\t', content)
#----------------------------------------------------------------------
def runServer():
"""运行服务器"""
repAddress = 'tcp://*:2014'
pubAddress = 'tcp://*:2016'
# 创建并启动服务器
server = VtServer(repAddress, pubAddress)
server.start()
printLog('-'*50)
printLog(u'vn.trader服务器已启动')
# 进入主循环
while True:
printLog(u'请输入exit来关闭服务器')
if raw_input() != 'exit':
continue
printLog(u'确认关闭服务器yes|no')
if raw_input() == 'yes':
break
server.stopServer()
if __name__ == '__main__':
runServer()