diff --git a/vn.trader/ctaAlgo/ctaBacktesting.py b/vn.trader/ctaAlgo/ctaBacktesting.py index f22977b9..b21ef1cf 100644 --- a/vn.trader/ctaAlgo/ctaBacktesting.py +++ b/vn.trader/ctaAlgo/ctaBacktesting.py @@ -1032,7 +1032,7 @@ class BacktestingEngine(object): self.output(u'最大回撤: \t%s' % formatNumber(min(d['drawdownList']))) self.output(u'平均每笔盈利:\t%s' %formatNumber(d['capital']/d['totalResult'])) - self.output(u'平均每笔滑点:\t%s' %formatNumber(d['totalSlippage']/d['totalResult'])) + self.output(u'平均每笔滑点成本:\t%s' %formatNumber(d['totalSlippage']/d['totalResult'])) self.output(u'平均每笔佣金:\t%s' %formatNumber(d['totalCommission']/d['totalResult'])) # 绘图 @@ -1070,7 +1070,7 @@ class BacktestingEngine(object): #---------------------------------------------------------------------- def setRate(self, rate): """设置佣金比例""" - self.rate = rate + self.rate = float(rate) #---------------------------------------------------------------------- def runOptimization(self, strategyClass, optimizationSetting): @@ -1135,7 +1135,7 @@ class TradingResult(object): self.volume = volume # 交易数量(+/-代表方向) self.turnover = (self.entry+self.exit)*size # 成交金额 - self.commission = self.turnover*rate # 手续费成本 + self.commission =round(float(self.turnover*rate),4) # 手续费成本 self.slippage = slippage*2*size # 滑点成本 self.pnl = ((self.exit - self.entry) * volume * size - self.commission - self.slippage) # 净盈亏 diff --git a/vn.trader/ctaAlgo/ctaBase.py b/vn.trader/ctaAlgo/ctaBase.py index 7b9681ef..b28d7695 100644 --- a/vn.trader/ctaAlgo/ctaBase.py +++ b/vn.trader/ctaAlgo/ctaBase.py @@ -90,7 +90,7 @@ class CtaBarData(object): self.low = EMPTY_FLOAT self.close = EMPTY_FLOAT - self.date = EMPTY_STRING # bar开始的时间,日期 + self.date = EMPTY_STRING # bar开始的时间,日期(通过tick生成的bar时间,为开始时间,其他为结束时间) self.time = EMPTY_STRING # 时间 self.datetime = None # python的datetime时间对象 @@ -103,6 +103,9 @@ class CtaBarData(object): # CTAORDER_SHORT 、CTAORDER_COVER 、 CTAORDER_OPEN_REJECT 、 # CTAORDER_OPEN_FAIL 、CTAORDER_CLOSE_FAIL + self.mid4 = EMPTY_FLOAT # (2*CLOSE+HIGH+LOW)/4; + self.mid5 = EMPTY_FLOAT # (2*CLOSE+HIGH+LOW+OPEN)/5 + self.seconds = EMPTY_INT # 当前Bar的秒数(针对RenkoBar) self.highSeconds = -1 # 当前Bar的上限秒数 self.lowSeconds = -1 # 当前bar的下限秒数 diff --git a/vn.trader/ctaAlgo/ctaLineBar.py b/vn.trader/ctaAlgo/ctaLineBar.py index e4a414e4..a9451d6e 100644 --- a/vn.trader/ctaAlgo/ctaLineBar.py +++ b/vn.trader/ctaAlgo/ctaLineBar.py @@ -254,7 +254,7 @@ class CtaLineBar(object): # 与最后一个BAR的时间比对,判断是否超过K线的周期 lastBar = self.lineBar[-1] - if (bar.datetime - lastBar.datetime).seconds >= self.barTimeInterval: + if abs((bar.datetime - lastBar.datetime).seconds) >= self.barTimeInterval: self.lineBar.append(bar) self.onBar(bar) return @@ -265,9 +265,15 @@ class CtaLineBar(object): lastBar.low = min(lastBar.low, bar.low) lastBar.volume = lastBar.volume + bar.volume + lastBar.mid4 = round((2*lastBar.close + lastBar.high+lastBar.low)/4,2) + lastBar.mid5 = round((2*lastBar.close + lastBar.open+ lastBar.high+lastBar.low)/5,2) + def onBar(self, bar): """OnBar事件""" # 计算相关数据 + bar.mid4 = round((2*bar.close + bar.high+bar.low)/4,2) + bar.mid5 = round((2*bar.close + bar.open+ bar.high+bar.low)/5,2) + self.__recountPreHighLow() self.__recountMa() self.__recountEma() @@ -355,6 +361,10 @@ class CtaLineBar(object): self.bar.low = tick.lastPrice self.bar.close = tick.lastPrice + self.bar.mid4 = tick.lastPrice # 四价均价 + self.bar.mid5 = tick.lastPrice # 四价均价 + + # K线的日期时间 self.bar.date = tick.date # K线的日期时间(去除秒)设为第一个Tick的时间 self.bar.time = tick.time # K线的日期时间(去除秒)设为第一个Tick的时间 @@ -379,7 +389,7 @@ class CtaLineBar(object): self.onBar(self.bar) return - # 清除8交易小时前的数据, + # 清除480周期前的数据, if l1 > 60 * 8: del self.lineBar[0] diff --git a/vn.trader/ctaAlgo/ctaPosition.py b/vn.trader/ctaAlgo/ctaPosition.py new file mode 100644 index 00000000..2627b99a --- /dev/null +++ b/vn.trader/ctaAlgo/ctaPosition.py @@ -0,0 +1,117 @@ +# encoding: UTF-8 + +from vtConstant import * +from ctaBase import * +import talib as ta + +from datetime import datetime + +DEBUGCTALOG = True + +class CtaPosition: + """策略的仓位管理类 + v 0.1 简单的数值,代表多仓数量和空仓数量 + + """ + + def __init__(self, strategy): + self.strategy = strategy + + self.pos = 0 # 持仓状态 0:空仓 >=1 多仓 <=-1 空仓 + + self.maxPos = 1 # 最大持仓量 + + self.step = 1 # 增仓数量 + + self.posList = [] + + self.avgPrice = EMPTY_FLOAT + + def avaliablePos2Add(self): + """剩余可加的仓位数量""" + + return self.maxPos - abs(self.pos) + + def openPos(self, direction, vol, price = EMPTY_FLOAT): + """开、加仓""" + + if self.pos == 0: + self.posList = [] + + if direction == DIRECTION_LONG: # 加多仓 + + if self.pos + vol > self.maxPos: + self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},加仓:{1},最大仓位:{2}'.format(self.pos,vol,self.maxPos)) + return False + + self.writeCtaLog(u'仓位:{0}->{1}'.format(self.pos, self.pos+vol)) + self.pos = self.pos + vol + self.strategy.pos = self.pos + + + if direction == DIRECTION_SHORT: # 加空仓 + + if self.pos - vol < 0 - self.maxPos: + self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},加仓:{1},最大仓位:{2}'.format(self.pos, vol, self.maxPos)) + return False + self.writeCtaLog(u'仓位:{0}->{1}'.format(self.pos, self.pos-vol)) + self.pos = self.pos - vol + self.strategy.pos = self.pos + + if price > EMPTY_FLOAT: + self.posList.append(price) + + # 计算持仓均价 + if len(self.posList) > 0: + self.avgPrice = sum(self.posList)/len(self.posList) + self.avgPrice = round(self.avgPrice, 3) + + return True + + def closePos(self, direction, vol): + """平、减仓""" + + if direction == DIRECTION_LONG: # 平空仓 Cover + + if self.pos + vol > 0: + self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},平仓:{1}'.format(self.pos,vol)) + self.strategy.pos = self.pos + return False + + self.writeCtaLog(u'仓位:{0}->{1}'.format(self.pos, self.pos+vol)) + self.pos = self.pos + vol + self.strategy.pos = self.pos + + if direction == DIRECTION_SHORT: # 平多仓 + + if self.pos - vol < 0 : + self.writeCtaLog(u'异常,超出仓位,当前仓位:{0},加仓:{1}'.format(self.pos, vol)) + self.strategy.pos = self.pos + return False + + self.writeCtaLog(u'仓位:{0}->{1}'.format(self.pos, self.pos-vol)) + self.pos = self.pos - vol + self.strategy.pos = self.pos + + if abs(self.pos) > 0: + self.posList = self.posList[:-vol] + else: + self.posList = [] + + # 计算持仓均价 + if len(self.posList) > 0: + self.avgPrice = sum(self.posList)/len(self.posList) + self.avgPrice = round(self.avgPrice, 3) + + return True + + # ---------------------------------------------------------------------- + def writeCtaLog(self, content): + """记录CTA日志""" + self.strategy.writeCtaLog(content) + + def debugCtaLog(self,content): + """记录CTA日志""" + if DEBUGCTALOG: + self.strategy.writeCtaLog('[DEBUG]'+content) + diff --git a/vn.trader/ctaAlgo/ctaSetting.py b/vn.trader/ctaAlgo/ctaSetting.py index ba42f634..196f2a75 100644 --- a/vn.trader/ctaAlgo/ctaSetting.py +++ b/vn.trader/ctaAlgo/ctaSetting.py @@ -11,8 +11,10 @@ from ctaTemplate import DataRecorder from ctaDemo import DoubleEmaDemo from strategy22_ArbitrageGrid import Strategy22 +from strategy24_M15RB import Strategy24 STRATEGY_CLASS = {} STRATEGY_CLASS['DataRecorder'] = DataRecorder STRATEGY_CLASS['DoubleEmaDemo'] = DoubleEmaDemo -STRATEGY_CLASS['Strategy22'] = Strategy22 \ No newline at end of file +STRATEGY_CLASS['Strategy22'] = Strategy22 +STRATEGY_CLASS['Strategy24'] = Strategy24 \ No newline at end of file diff --git a/vn.trader/uiBasicWidget.py b/vn.trader/uiBasicWidget.py index dfb0ceb7..55e63955 100644 --- a/vn.trader/uiBasicWidget.py +++ b/vn.trader/uiBasicWidget.py @@ -1027,7 +1027,8 @@ class TradingWidget(QtGui.QFrame): contract = self.mainEngine.getContract(symbol) if contract: - gatewayName = contract.gatewayName + if not gatewayName: + gatewayName = contract.gatewayName exchange = contract.exchange # 保证有交易所代码 req = VtOrderReq()