更新
This commit is contained in:
parent
c2c8690763
commit
ec89edebe5
@ -74,6 +74,7 @@ QQ/Wechat:28888502
|
||||
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/
|
||||
|
@ -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:
|
||||
|
@ -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_RED,COLOR_BLUE,COLOR_EQUAL
|
||||
self.color = COLOR_EQUAL # k 线颜色,COLOR_RED,COLOR_BLUE,COLOR_EQUAL
|
||||
|
||||
self.traded = False
|
||||
self.tradeStatus = EMPTY_STRING # 当前bar的交易情况: CTAORDER_BUY 、CTAORDER_SELL、
|
||||
|
@ -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/False,errMsg
|
||||
"""
|
||||
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):
|
||||
|
@ -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
@ -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()
|
||||
|
@ -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
|
||||
|
||||
|
@ -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):
|
||||
"""交易与平仓窗口"""
|
||||
|
@ -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__))
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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
72
vnpy/trader/util_wx_ft.py
Normal 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: 发送内容格式(普通文本,Markdown,html
|
||||
: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)
|
@ -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 # 使用常规代码(不包括交易所)可能导致重复
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
@ -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()
|
Loading…
Reference in New Issue
Block a user