class MaSignal(CtaSignal): """双均线信号""" # ---------------------------------------------------------------------- def __init__(self): """Constructor""" super(MaSignal, self).__init__() self.fastWindow = 5 self.slowWindow = 20 self.bg = BarGenerator(self.onBar, 5, self.onFiveBar) self.am = ArrayManager() # ---------------------------------------------------------------------- def onTick(self, tick): """Tick更新""" self.bg.updateTick(tick) # ---------------------------------------------------------------------- def onBar(self, bar): """K线更新""" self.bg.updateBar(bar) # ---------------------------------------------------------------------- def onFiveBar(self, bar): """5分钟K线更新""" self.am.updateBar(bar) if not self.am.inited: self.setSignalPos(0) fastMa = self.am.sma(self.fastWindow) slowMa = self.am.sma(self.slowWindow) if fastMa > slowMa: self.setSignalPos(1) elif fastMa < slowMa: self.setSignalPos(-1) else: self.setSignalPos(0)
class MaSignal(CtaSignal): """双均线信号""" #---------------------------------------------------------------------- def __init__(self): """Constructor""" super(MaSignal, self).__init__() self.fastWindow = 5 self.slowWindow = 20 self.bg = BarGenerator(self.onBar, 5, self.onFiveBar) self.am = ArrayManager() #---------------------------------------------------------------------- def onTick(self, tick): """Tick更新""" self.bg.updateTick(tick) #---------------------------------------------------------------------- def onBar(self, bar): """K线更新""" self.bg.updateBar(bar) #---------------------------------------------------------------------- def onFiveBar(self, bar): """5分钟K线更新""" self.am.updateBar(bar) if not self.am.inited: self.setSignalPos(0) fastMa = self.am.sma(self.fastWindow) slowMa = self.am.sma(self.slowWindow) if fastMa > slowMa: self.setSignalPos(1) elif fastMa < slowMa: self.setSignalPos(-1) else: self.setSignalPos(0)
class MultiTimeframeStrategy(CtaTemplate): """跨时间周期交易策略""" className = 'MultiTimeframeStrategy' author = u'用Python的交易员' # 策略参数 rsiSignal = 20 # RSI信号阈值 rsiWindow = 14 # RSI窗口 fastWindow = 5 # 快速均线窗口 slowWindow = 20 # 慢速均线窗口 initDays = 10 # 初始化数据所用的天数 fixedSize = 1 # 每次交易的数量 # 策略变量 rsiValue = 0 # RSI指标的数值 rsiLong = 0 # RSI买开阈值 rsiShort = 0 # RSI卖开阈值 fastMa = 0 # 5分钟快速均线 slowMa = 0 # 5分钟慢速均线 maTrend = 0 # 均线趋势,多头1,空头-1 # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'rsiSignal', 'rsiWindow', 'fastWindow', 'slowWindow' ] # 变量列表,保存了变量的名称 varList = [ 'inited', 'trading', 'pos', 'rsiValue', 'rsiLong', 'rsiShort', 'fastMa', 'slowMa', 'maTrend' ] # 同步列表,保存了需要保存到数据库的变量名称 syncList = ['pos'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(MultiTimeframeStrategy, self).__init__(ctaEngine, setting) self.rsiLong = 50 + self.rsiSignal self.rsiShort = 50 - self.rsiSignal # 创建K线合成器对象 self.bg5 = BarGenerator(self.onBar, 5, self.on5MinBar) self.am5 = ArrayManager() self.bg15 = BarGenerator(self.onBar, 15, self.on15MinBar) self.am15 = ArrayManager() #---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.putEvent() #---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略启动' % self.name) self.putEvent() #---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略停止' % self.name) self.putEvent() #---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" # 只需要要在一个BM中合成1分钟K线 self.bg5.updateTick(tick) #---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" # 基于15分钟判断趋势过滤,因此先更新 self.bg15.updateBar(bar) # 基于5分钟判断 self.bg5.updateBar(bar) #---------------------------------------------------------------------- def on5MinBar(self, bar): """5分钟K线""" self.cancelAll() # 保存K线数据 self.am5.updateBar(bar) if not self.am5.inited: return # 如果15分钟数据尚未初始化完毕,则直接返回 if not self.maTrend: return # 计算指标数值 self.rsiValue = self.am5.rsi(self.rsiWindow) # 判断是否要进行交易 # 当前无仓位 if self.pos == 0: if self.maTrend > 0 and self.rsiValue >= self.rsiLong: self.buy(bar.close + 5, self.fixedSize) elif self.maTrend < 0 and self.rsiValue <= self.rsiShort: self.short(bar.close - 5, self.fixedSize) # 持有多头仓位 elif self.pos > 0: if self.maTrend < 0 or self.rsiValue < 50: self.sell(bar.close - 5, abs(self.pos)) # 持有空头仓位 elif self.pos < 0: if self.maTrend > 0 or self.rsiValue > 50: self.cover(bar.close + 5, abs(self.pos)) # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def on15MinBar(self, bar): """15分钟K线推送""" self.am15.updateBar(bar) if not self.am15.inited: return # 计算均线并判断趋势 self.fastMa = self.am15.sma(self.fastWindow) self.slowMa = self.am15.sma(self.slowWindow) if self.fastMa > self.slowMa: self.maTrend = 1 else: self.maTrend = -1 #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass #---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class TripleMAStrategy02(CtaTemplate): """基于三均线的交易策略""" className = 'TripleMAStrategy' author = 'Y.Raul' # 策略参数 # 三均线长度设置 maWindow1 = 10 maWindow2 = 20 maWindow3 = 120 maWindow4 = 5 initDays = 10 # 初始化数据所用的天数 fixedSize = 1 # 每次交易的数量 # 策略变量 # ma次新值 ma10 = 0 ma20 = 0 # ma最新值 ma11 = 0 ma21 = 0 ma31 = 0 longEntry = 0 # 多头开仓 longExit = 0 # 多头平仓 shortEntry = 0 shortExit = 0 orderList = [] # 保存委托代码的列表 # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'maWindow1', 'maWindow2', 'maWindow3', 'maWindow4' 'initDays', 'fixedSize' ] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'ma10', 'ma11', 'ma20', 'ma21'] # 同步列表 syncList = ['pos'] # ---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(TripleMAStrategy02, self).__init__(ctaEngine, setting) self.bm = BarGenerator(self.onBar, 5, self.onFiveBar) # 由于maWindow3的长度是120,所以ArrayManager的size要增加至150 self.am = ArrayManager(size=150) # ---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.putEvent() # ---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略启动' % self.name) self.putEvent() # ---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略停止' % self.name) self.putEvent() # ---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.bm.updateTick(tick) # ---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" self.bm.updateBar(bar) # ---------------------------------------------------------------------- def onFiveBar(self, bar): """收到5分钟K线""" # 保存K线数据 self.am.updateBar(bar) if not self.am.inited: return # 撤销之前发出的尚未成交的委托(包括限价单和停止单) self.cancelAll() import talib # 计算指标数值 ma3Array = self.am.sma(self.maWindow3, True) self.ma30 = ma3Array[-2] self.ma31 = ma3Array[-1] ma3_ma5 = talib.SMA(ma3Array, self.maWindow4)[-1] # ma3_ma5 = ma3Array.rolling(window = self.maWindow4)[-1] ma1Array = self.am.sma(self.maWindow1, True) self.ma10 = ma1Array[-2] self.ma11 = ma1Array[-1] # ma1_ma5 = ma1Array.rolling(window = self.maWindow4)[-1] ma1_ma5 = talib.SMA(ma1Array, self.maWindow4)[-1] ma2Array = self.am.sma(self.maWindow2, True) self.ma20 = ma2Array[-2] self.ma21 = ma2Array[-1] # 判断是否要进行交易 # 当前无仓位,发送OCO开仓委托 if self.pos == 0: # 开多, bar.close > MA120,MA10 > MA120,MA10 上穿MA20,MA10、MA120向上 if bar.close > self.ma31 and self.ma11 > self.ma31 \ and self.ma10 < self.ma20 and self.ma11 > self.ma21\ and self.ma31 > ma3_ma5 and self.ma11 > ma1_ma5: self.longEntry = bar.close self.buy(self.longEntry, self.fixedSize, True) # 开空, bar.close < MA120,MA10 < MA120,MA10 下穿MA20, MA10,MA120向下 elif bar.close < self.ma31 and self.ma11 < self.ma31 \ and self.ma10 > self.ma20 and self.ma11 < self.ma21\ and self.ma31 < ma3_ma5 and self.ma11 < ma1_ma5: self.shortEntry = bar.close self.short(self.shortEntry, self.fixedSize, True) else: # 持有多头仓位 if self.pos > 0: self.longExit = bar.close # 平多,MA10下穿MA20 if self.ma10 > self.ma20 and self.ma11 < self.ma21: self.sell(self.longExit, abs(self.pos), True) # 持有空头仓位 if self.pos < 0: self.shortExit = bar.close # 平空, MA10上穿MA20 if self.ma10 < self.ma20 and self.ma11 > self.ma21: self.cover(self.shortExit, abs(self.pos), True) # 发出状态更新事件 self.putEvent() # ---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass # ---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 self.putEvent() # ---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class MultiTimeframeStrategy(CtaTemplate): """跨时间周期交易策略""" className = 'MultiTimeframeStrategy' author = u'用Python的交易员' # 策略参数 rsiSignal = 20 # RSI信号阈值 rsiWindow = 14 # RSI窗口 fastWindow = 5 # 快速均线窗口 slowWindow = 20 # 慢速均线窗口 initDays = 10 # 初始化数据所用的天数 fixedSize = 1 # 每次交易的数量 # 策略变量 rsiValue = 0 # RSI指标的数值 rsiLong = 0 # RSI买开阈值 rsiShort = 0 # RSI卖开阈值 fastMa = 0 # 5分钟快速均线 slowMa = 0 # 5分钟慢速均线 maTrend = 0 # 均线趋势,多头1,空头-1 # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'author', 'vtSymbol', 'rsiSignal', 'rsiWindow', 'fastWindow', 'slowWindow'] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'rsiValue', 'rsiLong', 'rsiShort', 'fastMa', 'slowMa', 'maTrend'] # 同步列表,保存了需要保存到数据库的变量名称 syncList = ['pos'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(MultiTimeframeStrategy, self).__init__(ctaEngine, setting) self.rsiLong = 50 + self.rsiSignal self.rsiShort = 50 - self.rsiSignal # 创建K线合成器对象 self.bg5 = BarGenerator(self.onBar, 5, self.on5MinBar) self.am5 = ArrayManager() self.bg15 = BarGenerator(self.onBar, 15, self.on15MinBar) self.am15 = ArrayManager() #---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' %self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.putEvent() #---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略启动' %self.name) self.putEvent() #---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略停止' %self.name) self.putEvent() #---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" # 只需要要在一个BarGenerator中合成1分钟K线 self.bg5.updateTick(tick) #---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" # 基于15分钟判断趋势过滤,因此先更新 self.bg15.updateBar(bar) # 基于5分钟判断 self.bg5.updateBar(bar) #---------------------------------------------------------------------- def on5MinBar(self, bar): """5分钟K线""" self.cancelAll() # 保存K线数据 self.am5.updateBar(bar) if not self.am5.inited: return # 如果15分钟数据尚未初始化完毕,则直接返回 if not self.maTrend: return # 计算指标数值 self.rsiValue = self.am5.rsi(self.rsiWindow) # 判断是否要进行交易 # 当前无仓位 if self.pos == 0: if self.maTrend > 0 and self.rsiValue >= self.rsiLong: self.buy(bar.close+5, self.fixedSize) elif self.maTrend < 0 and self.rsiValue <= self.rsiShort: self.short(bar.close-5, self.fixedSize) # 持有多头仓位 elif self.pos > 0: if self.maTrend < 0 or self.rsiValue < 50: self.sell(bar.close-5, abs(self.pos)) # 持有空头仓位 elif self.pos < 0: if self.maTrend > 0 or self.rsiValue > 50: self.cover(bar.close+5, abs(self.pos)) # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def on15MinBar(self, bar): """15分钟K线推送""" self.am15.updateBar(bar) if not self.am15.inited: return # 计算均线并判断趋势 self.fastMa = self.am15.sma(self.fastWindow) self.slowMa = self.am15.sma(self.slowWindow) if self.fastMa > self.slowMa: self.maTrend = 1 else: self.maTrend = -1 #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass #---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class TripleMAStrategy04(CtaTemplate): """基于三均线的交易策略""" className = 'TripleMAStrategy04' author = 'Y.Raul' # 策略参数 initDays = 10 # 初始化数据所用的天数 addPos = True # 加仓开关 windowCheck = True #交易窗口开关 openWindowSize = 5 #开盘观察窗口,单位分钟 closeWindowSize = 10 #收盘平仓窗口,单位分钟 minDiff = 1 #最小变动单位 # 策略变量 # 仓位设置 stepPos = 1 # 每次交易的数量 maxPos = 4 # 仓位上限 addPosRatio = 3 # 均线设置 maWindow1 = 10 maWindow2 = 20 maWindow3 = 120 maWindow4 = 5 atrWindow = 30 # ATR窗口数 # 出场设置 exitOnTrailingStop = 2 # Trailing Stop 距离 exitOnLossStop = 3 # Loss Stop 距离 # 价格相关变量 intraTradeHigh = 0 # 持仓期内的最高点 intraTradeLow = 0 # 持仓期内的最低点 longStop = 0 # 多头止损 shortStop = 0 # 空头止损 longEntry = 0 # 多头开仓 shortEntry = 0 avgEntryPrice = 0 # 指标相关变量 # ma次新值 ma10 = 0 ma20 = 0 ma30 = 0 # ma最新值 ma11 = 0 ma21 = 0 ma31 = 0 atrValue = 0 # ATR指标数值 orderList = [] # 保存委托代码的列表 # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'author', 'vtSymbol', 'maWindow1', 'maWindow2', 'maWindow3', 'maWindow4' 'initDays', 'addPos', 'stepPos', 'maxPos', 'exitOnTrailingStop', 'exitOnLossStop', ] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'ma10', 'ma11', 'ma20', 'ma21', 'ma30', 'ma31', 'atrValue', 'avgPrice'] # 同步列表 syncList = ['pos'] # ---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(TripleMAStrategy04, self).__init__(ctaEngine, setting) self.EntryPriceList = [] self.bm = BarGenerator(self.onBar, 5, self.onFiveBar) self.am = ArrayManager(size= self.maWindow3 + 30) # ---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.putEvent() # ---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略启动' % self.name) self.putEvent() # ---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略停止' % self.name) self.putEvent() # ---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.curDateTime = tick.datetime # 计算交易时间和平仓时间 if self.windowCheck == True: self.__timeWindow(tick.datetime) else: self.tradeWindow = True self.bm.updateTick(tick) # ---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" # 更新策略执行的时间(用于回测时记录发生的时间) # 回测数据传送的bar.datetime,为bar的结束时间 self.curDateTime = bar.datetime # 计算交易时间和平仓时间 if self.windowCheck == True: self.__timeWindow(bar.datetime) else: self.tradeWindow = True self.bm.updateBar(bar) # ---------------------------------------------------------------------- def onFiveBar(self, bar): """收到5分钟K线""" # 保存K线数据 self.am.updateBar(bar) if not self.am.inited: return # print bar.datetime # 撤销之前发出的尚未成交的委托(包括限价单和停止单) self.cancelAll() import talib # 计算指标数值 ma3Array = self.am.sma(self.maWindow3, True) self.ma30 = round(ma3Array[-2]) self.ma31 = round(ma3Array[-1]) ma3_ma5 = round(talib.SMA(ma3Array, self.maWindow4)[-1]) ma1Array = self.am.sma(self.maWindow1, True) self.ma10 = round(ma1Array[-2]) self.ma11 = round(ma1Array[-1]) ma1_ma5 = talib.SMA(ma1Array, self.maWindow4)[-1] ma2Array = self.am.sma(self.maWindow2, True) self.ma20 = round(ma2Array[-2]) self.ma21 = round(ma2Array[-1]) self.atrValue = round(self.am.atr(self.atrWindow)) # 判断是否要进行交易 # 当前无仓位,发送OCO开仓委托 if self.pos == 0 : self.intraTradeHigh = bar.high self.intraTradeLow = bar.low if self.tradeWindow: # 开多, bar.close > MA120,MA10 > MA120,MA10 上穿MA20,MA10、MA120向上 if bar.close > self.ma31 and self.ma11 > self.ma31 \ and self.ma10 < self.ma20 and self.ma11 > self.ma21\ and self.ma31 > ma3_ma5 and self.ma11 > ma1_ma5: self.longEntry = bar.close self.buy(self.longEntry, self.stepPos, True) # lastEntryPrice = self.longEntry self.LossStopPrice = round(self.longEntry * (100.0 -self.exitOnLossStop)/100) self.EntryPriceList.append(self.longEntry) # 记录log log = "\n Trading: {0}\n".format(self.trading)+\ "{0} Buy : bar.close: {1};\n".format(bar.datetime, bar.close) + \ " ma10:{0}; ma11:{1}; ma20:{2}; ma21:{3}; ma30:{4};ma31:{5}\n".format(self.ma10,self.ma11,self.ma20,self.ma21,self.ma30,self.ma31) + \ "ma1_ma5:{0}; ma3_ma5:{1}\n".format(ma1_ma5,ma3_ma5)+\ "LossStopPrice:{0}\n".format(self.LossStopPrice) self.writeCtaLog(log) # 开空, bar.close < MA120,MA10 < MA120,MA10 下穿MA20, MA10,MA120向下 elif bar.close < self.ma31 and self.ma11 < self.ma31 \ and self.ma10 > self.ma20 and self.ma11 < self.ma21\ and self.ma31 < ma3_ma5 and self.ma11 < ma1_ma5: self.shortEntry = bar.close self.short(self.shortEntry, self.stepPos, True) # lastEntryPrice = self.shortEntry self.LossStopPrice = round(self.shortEntry * (100.0 + self.exitOnLossStop)/100) self.EntryPriceList.append(self.shortEntry) # 记录log log = "\n Trading: {0}\n".format(self.trading)+\ "{0} Short : bar.close: {1};\n".format(bar.datetime, bar.close) + \ " ma10:{0}; ma11:{1}; ma20:{2}; ma21:{3}; ma30:{4};ma31:{5}\n".format(self.ma10, self.ma11, self.ma20, self.ma21, self.ma30, self.ma31) + \ "ma1_ma5:{0}; ma3_ma5:{1}\n".format(ma1_ma5, ma3_ma5) + \ "LossStopPrice:{0}\n".format(self.LossStopPrice) self.writeCtaLog(log) # return else: if self.tradeWindow: # Trailing Stop 跟随止损 if self.exitOnTrailingStop: # 持有多头仓位 if self.pos > 0 and self.tradeWindow: self.intraTradeHigh = max(self.intraTradeHigh, bar.high) self.intraTradeLow = bar.low self.longStop = round(self.intraTradeHigh - self.atrValue * self.exitOnTrailingStop) if bar.close < self.longStop: self.sell(bar.close, abs(self.pos), True) # 记录log log = "\n{0} Sell(Trailing Stop) : bar.close: {1};\n".format(bar.datetime, bar.close) + \ "intraTradeHigh:{0}; atrValue:{1}; dev: {2}\n".format(self.intraTradeHigh,self.atrValue,self.exitOnTrailingStop)+\ "LongStop:{0}\n".format(self.longStop) self.writeCtaLog(log) self.putEvent() self.EntryPriceList = [] return # 持有空头仓位 if self.pos < 0 and self.tradeWindow: self.intraTradeHigh = bar.high self.intraTradeLow = min(self.intraTradeLow, bar.low) self.shortStop = round(self.intraTradeLow + self.atrValue * self.exitOnTrailingStop) if bar.close > self.shortStop: self.cover(bar.close, abs(self.pos), True) # 记录log log = "\n{0} Cover(Trailing Stop) : bar.close: {1};\n".format(bar.datetime, bar.close) + \ "intraTradeLow:{0}; atrValue:{1}; dev: {2}\n".format(self.intraTradeLow, self.atrValue, self.exitOnTrailingStop) + \ "LongStop:{0}\n".format(self.longStop) self.writeCtaLog(log) self.putEvent() self.EntryPriceList = [] return # Loss Stop 固定止损 if self.exitOnLossStop: # 持有多头仓位 if self.pos > 0 and bar.close < self.LossStopPrice: # 记录log log = "\n{0} Sell(Stop Loss) : bar.close: {1};\n".format(bar.datetime, bar.close) + \ "LossStopPrice:{0}\n".format(self.LossStopPrice) + \ "Ratio:{0}%\n".format((1 - bar.close/self.LossStopPrice)*100) self.writeCtaLog(log) self.sell(bar.close, abs(self.pos), True) self.putEvent() self.EntryPriceList = [] return # 持有空头仓位 if self.pos < 0 and bar.close > self.LossStopPrice: # 记录log log = "\n{0} Cover(Stop Loss) : bar.close: {1};\n".format(bar.datetime, bar.close) + \ "LossStopPrice:{0}\n".format(self.LossStopPrice) +\ "Ratio:{0}%\n".format((1 - bar.close / self.LossStopPrice) * 100) self.writeCtaLog(log) self.cover(bar.close, abs(self.pos), True) self.putEvent() self.EntryPriceList = [] return # 加仓 if self.addPos and (self.maxPos - abs(self.pos) > 0): print self.pos, (self.maxPos - abs(self.pos) ) print self.EntryPriceList lastEntryPrice = self.EntryPriceList[-1] # 固定百分比加仓 addPosOnPips= round(lastEntryPrice* self.addPosRatio/100) self.writeCtaLog(u'\n 加仓判断:{0},当前仓位:{1}'.format(bar.datetime, self.pos)) # 加多仓 if self.pos > 0 \ and bar.close >= lastEntryPrice + addPosOnPips* self.minDiff: # 记录log self.writeCtaLog(u'\n {0},加仓多单{1}手,价格:{2}'.format(bar.datetime, self.stepPos, bar.close)) self.buy(bar.close, self.stepPos, True) # 更新开仓价格 lastEntryPrice = bar.close self.EntryPriceList.append(lastEntryPrice) self.avgEntryPrice = sum(self.EntryPriceList)/len(self.EntryPriceList) # 更新固定止损价 self.LossStopPrice = round( self.avgEntryPrice* (100.0 - self.exitOnLossStop) / 100) self.writeCtaLog(u'\n 更新固定止损价:{0},最新仓位:{1}'.format(self.LossStopPrice,self.pos)) return # 加空仓 if self.pos < 0 \ and bar.close <= (lastEntryPrice + addPosOnPips*self.minDiff): self.writeCtaLog(u'{0},加仓空单{1}手,价格:{2}'.format(bar.datetime, self.stepPos, bar.close)) self.short(bar.close, self.stepPos, True) # 更新开仓价格 lastEntryPrice = bar.close self.EntryPriceList.append(lastEntryPrice) self.avgEntryPrice = (sum(self.EntryPriceList)) / len(self.EntryPriceList) # 更新固定止损价 self.LossStopPrice = round(self.avgEntryPrice * (100.0 + self.exitOnLossStop) / 100) self.writeCtaLog(u'\n 更新固定止损价:{0},最新仓位:{1}'.format(self.LossStopPrice, self.pos)) return # 执行收盘前平仓检查 # self.__dailyCloseCheck(bar) # 发出状态更新事件 self.putEvent() # ---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" log = u'\n OnOrder()更新,orderID:{0},{1},totalVol:{2},tradedVol:{3},offset:{4},price:{5},direction:{6},status:{7},orderTime: {7}'\ .format(order.orderID, order.vtSymbol, order.totalVolume,order.tradedVolume, order.offset, order.price, order.direction, order.status, order.orderTime) self.writeCtaLog(log) self.putEvent() # ---------------------------------------------------------------------- def onTrade(self, trade): log = u'\n OnTrade()更新,orderID:{0},{1},Vol:{2},price:{3},direction:{4},tradeTime:{5}' \ .format(trade.orderID, trade.vtSymbol, trade.volume,trade.price, trade.direction,trade.tradeTime) self.writeCtaLog(log) # 发出状态更新事件 self.putEvent() # ---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" log = u'\n OnStopOrder()停止单更新,stopOrderID:{0},Vol:{1},price:{2},direction:{3},status:{4}' \ .format(so.stopOrderID, so.volume,so.price, so.direction,so.status) self.writeCtaLog(log) def __timeWindow(self, dt): """交易与平仓窗口""" # 螺纹钢交易窗口 避开早盘和夜盘的前5分钟,防止隔夜跳空。 # 日内平仓窗口 self.closeWindow = False # 交易窗口 self.tradeWindow = False # 开盘窗口 self.openWindow = False # 开市期头5分钟波动较大 if (dt.hour == 9 or dt.hour == 21) and dt.minute < self.openWindowSize: self.openWindow = False return # 日盘 if dt.hour == 9 and dt.minute >= 0: self.tradeWindow = True return if dt.hour == 10: if dt.minute <= 15 or dt.minute >= 30: self.tradeWindow = True return if dt.hour == 11 and dt.minute <= 30: self.tradeWindow = True return if dt.hour == 13 and dt.minute >= 30: self.tradeWindow = True return if dt.hour == 14: if dt.minute < 60 - self.closeWindowSize: self.tradeWindow = True return else: self.closeWindow = True return # 夜盘 if dt.hour == 21 and dt.minute >= 0: self.tradeWindow = True return if dt.hour == 22 and dt.minute < 60 - self.closeWindowSize: self.tradeWindow = True return else: self.closeWindow = True return def __dailyCloseCheck(self, bar): """每天收盘前检查,如果是亏损单,则平掉""" if self.pos == 0 : return False if not self.closeWindow: return False # 撤销未成交的订单 self.cancelAll() log = u'{0},收盘前{1}分钟,撤单及平仓'.format(bar.datetime,self.closeWindowSize) self.writeCtaLog(log) self.avgEntryPrice = (sum(self.EntryPriceList)) / len(self.EntryPriceList) # 记录log log = "\n{0} __dailyCloseCheck : bar.close: {1};\n".format(bar.datetime, bar.close) + \ "avgPrice:{0}\n".format(self.avgEntryPrice)+\ "pos:{0}\n".format(self.pos) self.writeCtaLog(log) # 强制平仓 if self.pos > 0 and bar.close < self.avgEntryPrice: self.writeCtaLog(u'强制日内平亏损多仓') # 降低两个滑点 self.sell(bar.close-2*self.minDiff, abs(self.pos),True ) # 记录log log = "\n{0} Sell(Force) : bar.close: {1};\n".format(bar.datetime, bar.close) + \ "entryPrice:{0}\n".format(bar.close - 2 * self.minDiff) self.writeCtaLog(log) return True if self.pos < 0 and bar.close > self.avgEntryPrice: self.writeCtaLog(u'强制日内平亏损空仓') self.cover(bar.close+2*self.minDiff, abs(self.pos),True ) # 记录log log = "\n{0} Cover(Force) : bar.close: {1};\n".format(bar.datetime, bar.close) + \ "forcePrice:{0}\n".format(bar.close - 2 * self.minDiff) self.writeCtaLog(log) return True return True
class TestStrategy(CtaTemplate): """Test策略""" className = 'TestStrategy' author = u'ZC' # 策略参数 entryWindow = 20 # 入场通道窗口 exitWindow = 7 # 出场通道窗口 atrWindow = 20 # 计算ATR波动率的窗口 initDays = 1 # 初始化数据所用的天数 fixedSize = 100 # 每次交易的数量 # 策略变量 entryUp = 0 # 入场通道上轨 entryDown = 0 # 入场通道下轨 exitUp = 0 # 出场通道上轨 exitDown = 0 # 出场通道下轨 atrVolatility = 0 # ATR波动率 longEntry = 0 # 多头入场价格 shortEntry = 0 # 空头入场价格 longStop = 0 # 多头止损价格 shortStop = 0 # 空头止损价格 # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'entryWindow', 'exitWindow', 'atrWindow', 'initDays', 'fixedSize' ] # 变量列表,保存了变量的名称 varList = [ 'inited', 'trading', 'pos', 'entryUp', 'entryDown', 'exitUp', 'exitDown', 'longEntry', 'shortEntry', 'longStop', 'shortStop' ] # 同步列表,保存了需要保存到数据库的变量名称 syncList = ['pos'] # ---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(TestStrategy, self).__init__(ctaEngine, setting) self.bg = BarGenerator(self.onBar, 5, self.onFiveBar) self.am = ArrayManager() # ---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.putEvent() # ---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略启动' % self.name) self.putEvent() # ---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略停止' % self.name) self.putEvent() # ---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.bg.updateTick(tick) # ---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" self.bg.updateBar(bar) def onFiveBar(self, bar): """收到5分钟K线""" print("onFiveBar-----------------------------------------------") # 撤销之前发出的尚未成交的委托(包括限价单和停止单) self.cancelAll() # 保存K线数据 self.am.updateBar(bar) if not self.am.inited: return # 计算指标数值 self.entryUp, self.entryDown = self.am.donchian(self.entryWindow) print( f"self.entryUp = {self.entryUp} self.entryDown = {self.entryDown}") ma = self.am.sma(self.exitWindow) self.exitUp = ma self.exitDown = ma print(self.pos) if not self.pos: self.atrVolatility = self.am.atr(self.atrWindow) # 判断是否要进行交易 if self.pos == 0: self.longEntry = 0 self.shortEntry = 0 self.longStop = 0 self.shortStop = 0 self.sendBuyOrders(self.entryUp) self.sendShortOrders(self.entryDown) elif self.pos > 0: # 加仓逻辑 self.sendBuyOrders(self.longEntry) # 止损逻辑 sellPrice = max(self.longStop, self.exitDown) self.sell(sellPrice, abs(self.pos), True) elif self.pos < 0: # 加仓逻辑 self.sendShortOrders(self.shortEntry) # 止损逻辑 coverPrice = min(self.shortStop, self.exitUp) self.cover(coverPrice, abs(self.pos), True) # 同步数据到数据库 self.saveSyncData() # 发出状态更新事件 self.putEvent() # ---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass # ---------------------------------------------------------------------- def onTrade(self, trade): """成交推送""" if trade.direction == DIRECTION_LONG: self.longEntry = trade.price self.longStop = self.longEntry - self.atrVolatility * 2 else: self.shortEntry = trade.price self.shortStop = self.shortEntry + self.atrVolatility * 2 # 发出状态更新事件 self.putEvent() # ---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass # ---------------------------------------------------------------------- def sendBuyOrders(self, price): """发出一系列的买入停止单""" t = self.pos / self.fixedSize if t < 1: self.buy(price, self.fixedSize, True) if t < 2: self.buy(price + self.atrVolatility * 0.5, self.fixedSize, True) if t < 3: self.buy(price + self.atrVolatility, self.fixedSize, True) if t < 4: self.buy(price + self.atrVolatility * 1.5, self.fixedSize, True) # ---------------------------------------------------------------------- def sendShortOrders(self, price): """""" t = self.pos / self.fixedSize if t > -1: self.short(price, self.fixedSize, True) if t > -2: self.short(price - self.atrVolatility * 0.5, self.fixedSize, True) if t > -3: self.short(price - self.atrVolatility, self.fixedSize, True) if t > -4: self.short(price - self.atrVolatility * 1.5, self.fixedSize, True)
class BollingerBotStrategy(CtaTemplate): """基于布林通道的交易策略""" className = 'BollingerBotStrategy' author = u'ForwardCapital' # 策略参数 bollWindow = 28 # 通道窗口数 entryDev = 3.2 # 开仓偏差 exitDev = 1.2 # 平仓偏差 trailingPrcnt = 0.4 # 移动止损百分比 maWindow = 10 # 过滤用均线窗口 initDays = 10 # 初始化数据所用的天数 fixedSize = 1 # 每次交易的数量 # 策略变量 bollMid = 0 # 布林带中轨 bollStd = 0 # 布林带宽度 entryUp = 0 # 开仓上轨 exitUp = 0 # 平仓上轨 maFilter = 0 # 均线过滤 maFilter1 = 0 # 上一期均线 intraTradeHigh = 0 # 持仓期内的最高点 longEntry = 0 # 多头开仓 longExit = 0 # 多头平仓 orderList = [] # 保存委托代码的列表 buyOrderID = None sellOrderID = None # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'bollWindow', 'entryDev', 'exitDev', 'trailingPrcnt', 'maWindow', 'initDays', 'fixedSize' ] # 变量列表,保存了变量的名称 varList = [ 'inited', 'trading', 'pos', 'bollMid', 'bollStd', 'entryUp', 'exitUp', 'intraTradeHigh', 'longEntry', 'longExit' ] # 同步列表 syncList = ['pos', 'intraTradeHigh'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(BollingerBotStrategy, self).__init__(ctaEngine, setting) self.bm = MyBarGenerator(self.onBar, 15, self.onFiveBar) self.am = ArrayManager() #---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.putEvent() #---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略启动' % self.name) self.putEvent() #---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略停止' % self.name) self.putEvent() #---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.bm.updateTick(tick) #---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" self.bm.updateBar(bar) #---------------------------------------------------------------------- def orderIDConvert(self, orderList): if not orderList: return [] else: return orderList[0] #---------------------------------------------------------------------- def onFiveBar(self, bar): """收到5分钟K线""" # 保存K线数据 self.am.updateBar(bar) if not self.am.inited or not self.trading: return # 撤销之前发出的尚未成交的委托(包括限价单和停止单) print u'onFiveBar↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓,datetime:%s' % bar.datetime # 计算指标数值 self.bollMid = self.am.sma(self.bollWindow) self.bollStd = self.am.std(self.bollWindow) self.entryUp = self.bollMid + self.bollStd * self.entryDev self.exitUp = self.bollMid + self.bollStd * self.exitDev maArray = self.am.sma(self.maWindow, True) self.maFilter = maArray[-1] self.maFilter1 = maArray[-2] # 判断是否要进行交易 if not self.buyOrderID: if self.pos == 0: self.intraTradeHigh = bar.high # 下开仓单 if bar.close > self.maFilter and self.maFilter > self.maFilter1: self.longEntry = self.entryUp self.buyOrderID = self.buy(self.longEntry, self.fixedSize, True) self.buyOrderID = self.orderIDConvert(self.buyOrderID) print 'order None!!!buyOrderID is : %s ' % self.buyOrderID self.orderList.append(self.buyOrderID) # 下平仓单 self.longExit = self.intraTradeHigh * ( 1 - self.trailingPrcnt / 100) self.longExit = min(self.longExit, self.exitUp) self.sellOrderID = self.sell(self.longExit, abs(self.pos), True) self.sellOrderID = self.orderIDConvert(self.sellOrderID) print 'order None!!!ellOrderID is : %s ' % self.sellOrderID self.orderList.append(self.sellOrderID) elif self.pos > 0: self.intraTradeHigh = max(self.intraTradeHigh, bar.high) # 下平仓单 self.longExit = self.intraTradeHigh * ( 1 - self.trailingPrcnt / 100) self.longExit = min(self.longExit, self.exitUp) self.sellOrderID = self.sell(self.longExit, abs(self.pos), True) self.sellOrderID = self.orderIDConvert(self.sellOrderID) print 'order None!!!sellOrderID is : %s ' % self.sellOrderID self.orderList.append(self.sellOrderID) else: if self.buyOrderID in self.orderList: self.intraTradeHigh = bar.high self.cancelAll() # 下开仓单 if bar.close > self.maFilter and self.maFilter > self.maFilter1: self.longEntry = self.entryUp self.buyOrderID = self.buy(self.longEntry, self.fixedSize, True) print 'buyOrderID is : %s ' % self.buyOrderID self.buyOrderID = self.orderIDConvert(self.buyOrderID) self.orderList.append(self.buyOrderID) # 下平仓单 self.longExit = self.intraTradeHigh * ( 1 - self.trailingPrcnt / 100) self.longExit = min(self.longExit, self.exitUp) self.sellOrderID = self.sell(self.longExit, abs(self.pos), True) self.sellOrderID = self.orderIDConvert(self.sellOrderID) print 'sellOrderID is : %s ' % self.sellOrderID self.orderList.append(self.sellOrderID) else: if self.sellOrderID in self.orderList: self.intraTradeHigh = max(self.intraTradeHigh, bar.high) self.cancelOrder(self.sellOrderID) # 下平仓单 self.longExit = self.intraTradeHigh * ( 1 - self.trailingPrcnt / 100) self.longExit = min(self.longExit, self.exitUp) self.sellOrderID = self.sell(self.longExit, abs(self.pos), True) self.sellOrderID = self.orderIDConvert(self.sellOrderID) print 'sellOrderID is : %s ' % self.sellOrderID self.orderList.append(self.sellOrderID) else: self.intraTradeHigh = bar.high # 下开仓单 if bar.close > self.maFilter and self.maFilter > self.maFilter1: self.longEntry = self.entryUp self.buyOrderID = self.buy(self.longEntry, self.fixedSize, True) self.buyOrderID = self.orderIDConvert(self.buyOrderID) print 'buyOrderID is : %s ' % self.buyOrderID self.orderList.append(self.buyOrderID) # 下平仓单 self.longExit = self.intraTradeHigh * ( 1 - self.trailingPrcnt / 100) self.longExit = min(self.longExit, self.exitUp) self.sellOrderID = self.sell(self.longExit, abs(self.pos), True) self.sellOrderID = self.orderIDConvert( self.sellOrderID) print 'sellOrderID is : %s ' % self.sellOrderID self.orderList.append(self.sellOrderID) # 发出状态更新事件 # self.putEvent() #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass #---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" print u'StopOrder回报,stopOrderID:%s, status:%s' % (so.stopOrderID, so.status) if so.status == STOPORDER_CANCELLED or so.status == STOPORDER_TRIGGERED: self.orderList.remove(so.stopOrderID) pass
class TripleMAStrategy05(CtaTemplate): """基于三均线的交易策略""" className = 'TripleMAStrategy05' author = 'Y.Raul' # 策略参数 initDays = 10 # 初始化数据所用的天数 windowCheck = True #交易窗口开关 openWindowSize = 5 #开盘观察窗口,单位分钟 closeWindowSize = 10 #收盘平仓窗口,单位分钟 minDiff = 1 #最小变动单位 # 策略变量 # 仓位设置 stepPos = 1 # 每次交易的数量 maxPos = 4 # 仓位上限 addPosRatio = 3 # 均线设置 maWindow1 = 10 maWindow2 = 20 maWindow3 = 120 maWindow4 = 5 atrWindow = 30 # ATR窗口数 # 分级出场设置 trailingStart1 = 50 trailingStart2 = 80 exitOnTrailingStop1 = 30 # Trailing Stop 距离 exitOnTrailingStop2 = 20 # Trailing Stop 距离 exitOnLossStop = 5 # Loss Stop 距离 # 价格相关变量 intraTradeHigh = 0 # 持仓期内的最高点 intraTradeLow = 0 # 持仓期内的最低点 longExit = 0 # 多头止损 shortExit = 0 # 空头止损 longEntry = 0 # 多头开仓 shortEntry = 0 avgEntryPrice = 0 # 指标相关变量 # ma次新值 ma10 = 0 ma20 = 0 ma30 = 0 # ma最新值 ma11 = 0 ma21 = 0 ma31 = 0 atrValue = 0 # ATR指标数值 orderList = [] # 保存委托代码的列表 # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'maWindow1', 'maWindow2', 'maWindow3', 'maWindow4', 'initDays', 'addPos', 'stepPos', 'maxPos', 'exitOnTrailingStop', 'exitOnLossStop' ] # 变量列表,保存了变量的名称 varList = [ 'inited', 'trading', 'pos', 'ma10', 'ma11', 'ma20', 'ma21', 'ma30', 'ma31', 'atrValue', 'avgEntryPrice' ] # 同步列表 syncList = ['pos'] # ---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(TripleMAStrategy05, self).__init__(ctaEngine, setting) self.entryPriceList = [] self.bm = BarGenerator(self.onBar, 5, self.onFiveBar) self.am = ArrayManager(size=150) self.backTesting = True # 策略信号 self.buySig = False self.shortSig = False self.sellSig = False self.coverSig = False # ---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) if self.backTesting: # 载入历史数据,并采用回放计算的方式初始化策略数值 self.writeCtaLog(u"回测模式,载入历史数据,并采用回放计算的方式初始化策略数值") initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) else: # self.trading = True self.inited = True self.writeCtaLog(u"实盘模式") self.putEvent() # ---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略启动' % self.name) self.putEvent() # ---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略停止' % self.name) self.putEvent() # ---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.curDateTime = tick.datetime # 计算交易时间和平仓时间 if self.windowCheck == True: self.__timeWindow(tick.datetime) else: self.tradeWindow = True self.bm.updateTick(tick) # ---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" # 回测数据传送的bar.datetime,为bar的开始时间 self.curDateTime = bar.datetime # 计算交易时间和平仓时间 if self.windowCheck == True: self.__timeWindow(bar.datetime) else: self.tradeWindow = True self.bm.updateBar(bar) if self.pos == 0: self.intraTradeLow = bar.low self.intraTradeHigh = bar.high else: self.intraTradeHigh = max(bar.high, self.intraTradeHigh) self.intraTradeLow = min(bar.low, self.intraTradeLow) print "-----" * 10 print "@onBar" print "bar.datetime: {0}; pos: {1} ".format(bar.datetime, self.pos) print "buySig: {0}; shortSig: {1}".format(self.buySig, self.shortSig) print "sellSig: {0}; coverSig: {1}".format(self.sellSig, self.coverSig) print "intraTradeHigh: {0}".format(self.intraTradeHigh) print "intraTradeLow: {0}".format(self.intraTradeLow) #检查交易信号 if self.buySig: self.longEntry = max(self.longEntry, bar.close) self.buy(self.longEntry, self.stepPos, True) # self.LossStopPrice = round(self.longEntry * (100.0 - self.exitOnLossStop) / 100) self.entryPriceList.append(self.longEntry) self.avgEntryPrice = sum(self.entryPriceList) / len( self.entryPriceList) self.LossStopPrice = round(self.avgEntryPrice * (100.0 + self.exitOnLossStop) / 100) self.intraTradeHigh = max(bar.high, self.avgEntryPrice) self.intraTradeLow = min(bar.low, self.avgEntryPrice) # 记录log log = "\n Trading: {0}\n".format(self.trading) + \ "{0} Buy : longEntry: {1};\n".format(bar.datetime, self.longEntry) + \ " ma10:{0}; ma11:{1}; ma20:{2}; ma21:{3}; ma30:{4};ma31:{5}\n".format(self.ma10, self.ma11, self.ma20, self.ma21, self.ma30, self.ma31) + \ "ma1_ma5:{0}; ma3_ma5:{1}\n".format(self.ma1_ma5, self.ma3_ma5) # "LossStopPrice:{0}\n".format(self.LossStopPrice) self.writeCtaLog(log) self.buySig = False return if self.shortSig: self.shortEntry = min(self.shortEntry, bar.close) self.short(self.shortEntry, self.stepPos, True) # self.LossStopPrice = round(self.shortEntry * (100.0 + self.exitOnLossStop) / 100) self.entryPriceList.append(self.shortEntry) self.avgEntryPrice = sum(self.entryPriceList) / len( self.entryPriceList) self.LossStopPrice = round(self.avgEntryPrice * (100.0 + self.exitOnLossStop) / 100) self.intraTradeHigh = max(bar.high, self.avgEntryPrice) self.intraTradeLow = min(bar.low, self.avgEntryPrice) # 记录log log = "\n Trading: {0}\n".format(self.trading) + \ "{0} Short : shortEntry: {1};\n".format(bar.datetime, self.shortEntry) + \ " ma10:{0}; ma11:{1}; ma20:{2}; ma21:{3}; ma30:{4};ma31:{5}\n".format(self.ma10, self.ma11, self.ma20, self.ma21, self.ma30, self.ma31) + \ "ma1_ma5:{0}; ma3_ma5:{1}\n".format(self.ma1_ma5, self.ma3_ma5) # "LossStopPrice:{0}\n".format(self.LossStopPrice) self.writeCtaLog(log) self.shortSig = False return if self.sellSig: self.longExit = min(bar.close, self.longExit) self.sell(self.longExit, abs(self.pos), True) # 记录log # log = "\n{0} Sell(Trailing Stop) : longExit: {1};\n".format(bar.datetime, self.longExit) + \ # "intraTradeHigh:{0}; atrValue:{1}; \n".format(self.intraTradeHigh, self.atrValue) + \ # "LongExit:{0}\n".format(self.longExit) # self.writeCtaLog(log) self.entryPriceList = [] self.sellSig = False return if self.coverSig: self.shortExit = max(bar.close, self.shortExit) self.cover(self.shortExit, abs(self.pos), True) # 记录log # log = "\n{0} Cover(Trailing Stop) : bar.close: {1};\n".format(bar.datetime, bar.close) + \ # "intraTradeLow:{0}; atrValue:{1};\n".format(self.intraTradeLow, self.atrValue) + \ # "shortExit:{0}\n".format(self.shortExit) # self.writeCtaLog(log) self.entryPriceList = [] self.coverSig = False return # ---------------------------------------------------------------------- def onFiveBar(self, bar): """收到5分钟K线""" print "-----" * 10 print "@onFiveBar" print "bar.datetime: ", bar.datetime print "ma11: %f, ma10 %f" % (self.ma11, self.ma10) print "ma21: %f, ma20 %f" % (self.ma21, self.ma20) print "ma31: %f, ma30 %f" % (self.ma31, self.ma30) # 保存K线数据 self.am.updateBar(bar) print "bar count: ", self.am.count print "am.inited: ", self.am.inited if not self.am.inited: return # 撤销之前发出的尚未成交的委托(包括限价单和停止单) # 等于策略信号的生存期只有5分钟 self.cancelAll() import talib # 计算指标数值 ma3Array = self.am.sma(self.maWindow3, True) self.ma30 = round(ma3Array[-2]) self.ma31 = round(ma3Array[-1]) self.ma3_ma5 = round(talib.SMA(ma3Array, self.maWindow4)[-1]) ma1Array = self.am.sma(self.maWindow1, True) self.ma10 = round(ma1Array[-2]) self.ma11 = round(ma1Array[-1]) self.ma1_ma5 = talib.SMA(ma1Array, self.maWindow4)[-1] ma2Array = self.am.sma(self.maWindow2, True) self.ma20 = round(ma2Array[-2]) self.ma21 = round(ma2Array[-1]) self.atrValue = round(self.am.atr(self.atrWindow)) # 当前为空仓 if self.pos == 0: self.intraTradeHigh = bar.high self.intraTradeLow = bar.low self.avgEntryPrice = 0 self.entryPriceList = [] if self.tradeWindow: # 开多, bar.close > MA120,MA10 > MA120,MA10 上穿MA20,MA10、MA120向上 if bar.close > self.ma31 and self.ma11 > self.ma31 \ and self.ma10 < self.ma20 and self.ma11 > self.ma21\ and self.ma31 > self.ma3_ma5 and self.ma11 > self.ma1_ma5: self.buySig = True self.longEntry = bar.close # 开空, bar.close < MA120,MA10 < MA120,MA10 下穿MA20, MA10,MA120向下 elif bar.close < self.ma31 and self.ma11 < self.ma31 \ and self.ma10 > self.ma20 and self.ma11 < self.ma21\ and self.ma31 < self.ma3_ma5 and self.ma11 < self.ma1_ma5: self.shortSig = True self.shortEntry = bar.close if self.pos != 0: self.intraTradeHigh = max(self.intraTradeHigh, bar.high) self.intraTradeLow = min(self.intraTradeLow, bar.low) if self.tradeWindow: if self.pos > 0: # 二级止赢判断 盈利80跳 if self.intraTradeHigh >= self.avgEntryPrice + self.trailingStart2 * self.minDiff: # 回撤20跳 if (bar.close <= self.intraTradeHigh - self.exitOnTrailingStop2 * self.minDiff): self.longExit = self.intraTradeHigh - self.exitOnTrailingStop2 * self.minDiff self.sellSig = True if bar.close < self.longExit: self.longExit = bar.close # 记录log log = "\n{0} Sell(Trailing Stop2)\n".format(bar.datetime) + \ 'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close,bar.low, self.longExit)+ \ 'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh,self.avgEntryPrice, bar.open) self.writeCtaLog(log) # 一级止赢判断,盈利50跳 elif self.intraTradeHigh >= self.avgEntryPrice + self.trailingStart1 * self.minDiff: # 回撤20跳 if (bar.close <= self.intraTradeHigh - self.exitOnTrailingStop1 * self.minDiff): self.longExit = self.intraTradeHigh - self.exitOnTrailingStop1 * self.minDiff self.sellSig = True if bar.close < self.longExit: self.longExit = bar.close # 记录log log = "\n{0} Sell(Trailing Stop1)\n".format(bar.datetime) + \ 'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close, bar.low, self.longExit)+ \ 'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh,self.avgEntryPrice, bar.open) self.writeCtaLog(log) # 止损,回撤20跳 elif (bar.close <= self.avgEntryPrice - self.exitOnLossStop * self.minDiff): self.longExit = self.avgEntryPrice - self.exitOnLossStop * self.minDiff self.sellSig = True if bar.close < self.longExit: self.longExit = bar.close # 记录log log = "\n{0} Sell(Loss Stop)\n".format(bar.datetime) + \ 'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close, bar.low, self.longExit)+ \ 'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh, self.avgEntryPrice, bar.open) self.writeCtaLog(log) elif self.pos < 0: # 二级止赢判断 盈利80跳 if self.intraTradeLow <= self.avgEntryPrice - self.trailingStart2 * self.minDiff: # 回撤20跳 if (bar.close >= self.intraTradeLow + self.exitOnTrailingStop2 * self.minDiff): self.shortExit = self.intraTradeLow + self.exitOnTrailingStop2 * self.minDiff self.coverSig = True if bar.close > self.shortExit: self.shortExit = bar.close # 记录log log = "\n{0} Cover(Trailing Stop1)\n".format(bar.datetime) + \ 'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low, self.shortExit)+ \ 'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow, self.avgEntryPrice, bar.open) self.writeCtaLog(log) # 一级止赢判断,盈利50跳 elif self.intraTradeLow <= self.avgEntryPrice - self.trailingStart1 * self.minDiff: # 回撤20跳 if (bar.close >= self.intraTradeLow + self.exitOnTrailingStop1 * self.minDiff): self.shortExit = self.intraTradeLow + self.exitOnTrailingStop1 * self.minDiff self.coverSig = True if bar.close > self.shortExit: self.shortExit = bar.close # 记录log log = "\n{0} Cover(Trailing Stop2)\n".format(bar.datetime) + \ 'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low, self.shortExit)+ \ 'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow, self.avgEntryPrice, bar.open) self.writeCtaLog(log) # 止损,回撤20跳 elif (bar.close >= self.avgEntryPrice + self.exitOnLossStop * self.minDiff): self.shortExit = self.avgEntryPrice + self.exitOnLossStop * self.minDiff self.coverSig = True if bar.close > self.shortExit: self.shortExit = bar.close # 记录log log = "\n{0} Cover(Loss Stop)\n".format(bar.datetime) + \ 'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low, self.shortExit)+ \ 'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow, self.avgEntryPrice, bar.open) self.writeCtaLog(log) # # 加仓 # if self.addPos and (self.maxPos - abs(self.pos) > 0): # # print self.pos, (self.maxPos - abs(self.pos) ) # # print self.entryPriceList # # lastEntryPrice = self.entryPriceList[-1] # # 固定百分比加仓 # addPosOnPips= round(lastEntryPrice* self.addPosRatio/100) # # self.writeCtaLog(u'\n 加仓判断:{0},当前仓位:{1}'.format(bar.datetime, self.pos)) # # 加多仓 # if self.pos > 0 \ # and bar.close >= (lastEntryPrice + addPosOnPips* self.minDiff): # # self.buySig = True # self.longEntry = bar.close # # # 记录log # self.writeCtaLog(u'\n {0},加仓多单{1}手,价格:{2}'.format(bar.datetime, self.stepPos, self.longEntry)) # # return # # # 加空仓 # if self.pos < 0 \ # and bar.close <= (lastEntryPrice + addPosOnPips*self.minDiff): # # self.shortSig = True # self.shortEntry = bar.close # # 记录log # self.writeCtaLog(u'{0},加仓空单{1}手,价格:{2}'.format(bar.datetime, self.stepPos, self.shortEntry)) # 执行收盘前平仓检查 # self.__dailyCloseCheck(bar) # 发出状态更新事件 self.putEvent() # ---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" log = u'\n OnOrder()更新,orderID:{0},{1},totalVol:{2},tradedVol:{3},offset:{4},price:{5},direction:{6},status:{7},orderTime: {7}'\ .format(order.orderID, order.vtSymbol, order.totalVolume,order.tradedVolume, order.offset, order.price, order.direction, order.status, order.orderTime) # self.writeCtaLog(log) self.putEvent() # ---------------------------------------------------------------------- def onTrade(self, trade): log = u'\n OnTrade()更新,orderID:{0},{1},Vol:{2},price:{3},direction:{4},tradeTime:{5}' \ .format(trade.orderID, trade.vtSymbol, trade.volume,trade.price, trade.direction,trade.tradeTime) # self.writeCtaLog(log) # 发出状态更新事件 self.putEvent() # ---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" log = u'\n OnStopOrder()停止单更新,stopOrderID:{0},Vol:{1},price:{2},direction:{3},status:{4}' \ .format(so.stopOrderID, so.volume,so.price, so.direction,so.status) # self.writeCtaLog(log) def __timeWindow(self, dt): """交易与平仓窗口""" # 螺纹钢交易窗口 避开早盘和夜盘的前5分钟,防止隔夜跳空。 # 日内平仓窗口 self.closeWindow = False # 交易窗口 self.tradeWindow = False # 开盘窗口 self.openWindow = False # 开市期头5分钟波动较大 if (dt.hour == 9 or dt.hour == 21) and dt.minute < self.openWindowSize: self.openWindow = False return # 日盘 if dt.hour == 9 and dt.minute >= 0: self.tradeWindow = True return if dt.hour == 10: if dt.minute <= 15 or dt.minute >= 30: self.tradeWindow = True return if dt.hour == 11 and dt.minute <= 30: self.tradeWindow = True return if dt.hour == 13 and dt.minute >= 30: self.tradeWindow = True return if dt.hour == 14: if dt.minute < 60 - self.closeWindowSize: self.tradeWindow = True return else: self.closeWindow = True return # 夜盘 if dt.hour == 21 and dt.minute >= 0: self.tradeWindow = True return if dt.hour == 22 and dt.minute < 60 - self.closeWindowSize: self.tradeWindow = True return else: self.closeWindow = True return def __dailyCloseCheck(self, bar): """每天收盘前检查,如果是亏损单,则平掉""" if self.pos == 0: return False if not self.closeWindow: return False # 撤销未成交的订单 self.cancelAll() log = u'{0},收盘前{1}分钟,撤单及平仓'.format(bar.datetime, self.closeWindowSize) self.writeCtaLog(log) self.avgEntryPrice = (sum(self.entryPriceList)) / len( self.entryPriceList) # 记录log log = "\n{0} __dailyCloseCheck : bar.close: {1};\n".format(bar.datetime, bar.close) + \ "avgPrice:{0}\n".format(self.avgEntryPrice)+\ "pos:{0}\n".format(self.pos) self.writeCtaLog(log) # 强制平仓 if self.pos > 0 and bar.close < self.avgEntryPrice: self.writeCtaLog(u'强制日内平亏损多仓') # 降低两个滑点 self.sell(bar.close - 2 * self.minDiff, abs(self.pos), True) # 记录log log = "\n{0} Sell(Force) : bar.close: {1};\n".format(bar.datetime, bar.close) + \ "entryPrice:{0}\n".format(bar.close - 2 * self.minDiff) self.writeCtaLog(log) return True if self.pos < 0 and bar.close > self.avgEntryPrice: self.writeCtaLog(u'强制日内平亏损空仓') self.cover(bar.close + 2 * self.minDiff, abs(self.pos), True) # 记录log log = "\n{0} Cover(Force) : bar.close: {1};\n".format(bar.datetime, bar.close) + \ "forcePrice:{0}\n".format(bar.close - 2 * self.minDiff) self.writeCtaLog(log) return True return True
class GridStrategy(CtaTemplate): className = 'GridStrategy' author = u'BillyZhang' # 策略参数 historyBars = 200 # 历史数据大小,用来确定网格基准线 initDays = 20 # 初始化数据所用的天数,随着历史数据大小要改变 gridlines = 10 # 网格线数量,单边数量 ordersize = 10 # 最大持仓数量 order = 1 # 每次下单手数 barMins = 30 #bar的时间 frozenBars = 1 #平仓后,frozenBars个bar不再开反向单 atrWindow = 30 # ATR窗口数 slMultiplier = 5.0 # 计算止损距离的乘数 # 基本变量 upline = 0 #当前上线 bottomline = 0 #当前下线 frozen = 0 #当前是否冻结开反向单 intraTradeHigh = 0 intraTradeLow = 0 atrValue = 0 # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'historyBars', 'initDays', 'gridlines', 'barMins', 'order', 'ordersize', 'atrWindow', 'slMultiplier' ] # 变量列表,保存了变量的名称 varList = [ 'inited', 'trading', 'pos', 'frozen', 'upline', 'bottomline' 'atrValue' ] # 同步列表,保存了需要保存到数据库的变量名称 syncList = ['pos', 'frozen'] # ---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(GridStrategy, self).__init__(ctaEngine, setting) self.bg = BarGenerator(self.onBar, self.barMins, self.onXminBar) # 创建K线合成器对象 self.am = ArrayManager(self.historyBars + 50) # ---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.putEvent() def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略启动' % self.name) self.putEvent() def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略停止' % self.name) self.putEvent() # ----------------------------------------------------------------------- def onXminBar(self, bar): """收到X分钟K线""" # 全撤之前发出的委托 self.cancelAll() # 保存K线数据 am = self.am am.updateBar(bar) if not am.inited: return # 这里采用了均量交易法,就是每笔。 # 空仓时候,每次突破上线是开多单,突破下线是开空单; # 有多单时候,突破上线加多单,突破下线情况清空所有多单, # 有空单时候,突破下线加空单,突破上线清空所有空单, # 为防止在一个线上下波动,造成重复开平仓情况,如果突破平仓,比如平多单,后面n个bar不能再开多单,只能开空单;反之平空单后, # 后面n个bar只能开多单。 # 计算网格,返回通道队列, 再算出当前点位所在通道,0为最下通道,2*self.gridlines - 1为最上通道 baseline = self.am.sma(self.historyBars) # 过去300的标准差,按照顶一个gridlines取整做出一个队列 intervallist = baseline + np.array([ n * 1.00 / self.gridlines for n in range(-1 * self.gridlines, self.gridlines + 1) ]) * self.am.std(self.historyBars) griploc = pd.cut([bar.close], intervallist, labels=[nx for nx in range(0, 2 * self.gridlines)])[0] # 如果返回为nan,说明现在bar.close在标准差范围以外,如果没有仓位,先不处理;如果有,按照ATR波动移动止盈 if isnan(griploc): # 持有多头仓位 if self.pos > 0: self.intraTradeHigh = max(self.intraTradeHigh, bar.high) self.intraTradeLow = bar.low self.longStop = self.intraTradeHigh - self.atrValue * self.slMultiplier self.sell(self.longStop, abs(self.pos), True) # 持有空头仓位 elif self.pos < 0: self.intraTradeHigh = bar.high self.intraTradeLow = min(self.intraTradeLow, bar.low) self.shortStop = self.intraTradeLow + self.atrValue * self.slMultiplier self.cover(self.shortStop, abs(self.pos), True) return #返回上下线: self.upline = intervallist[griploc + 1] self.bottomline = intervallist[griploc] # 空仓时候,每次突破上线是开多单,突破下线是开空单; # 如果此时在最下一个通道,此时只挂往上的多单, 如果在最上面通道,此时只挂往下空单;如果在中间的,则同时开上下单 if self.pos == 0: if griploc == 0: self.buy(self.upline, self.order, True) elif griploc == 2 * self.gridlines - 1: self.short(self.bottomline, self.order, True) else: #此时如果frozen 为0, 直接开上下单: if self.frozen == 0: self.buy(self.upline, self.order, True) self.short(self.bottomline, self.order, True) #此时如果大于0,只能开空单,如果小于0,只能开多单 elif self.frozen > 0: self.frozen = self.frozen - 1 self.short(self.bottomline, self.order, True) elif self.frozen < 0: self.frozen = self.frozen + 1 self.buy(self.upline, self.order, True) #如果持有多仓时候,如果在中间通道,同时开上下单;如果最高点位不再开单,突破最大标准差高点, elif self.pos > 0: # 在最下通道不可能有多单,只用考量在中间段,pos 小于ordersize可以增多仓,否则只能向下平仓;和最高段情况,最高段设置往下平仓, if griploc == 2 * self.gridlines - 1: self.intraTradeHigh = bar.high self.sell(self.bottomline, abs(self.pos), True) else: if abs(self.pos) < self.ordersize: self.buy(self.upline, self.order, True) self.sell(self.bottomline, abs(self.pos), True) else: self.sell(self.bottomline, abs(self.pos), True) elif self.pos < 0: # 最上通道通道不可能有空单,只用考虑中间段,和最低档情况 if griploc == 0: self.intraTradeLow = bar.low self.cover(self.upline, abs(self.pos), True) else: if abs(self.pos) < self.ordersize: self.cover(self.upline, abs(self.pos), True) self.sell(self.bottomline, self.order, True) else: self.cover(self.upline, abs(self.pos), True) # ---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.bg.updateTick(tick) # ---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" self.bg.updateBar(bar) # ---------------------------------------------------------------------- def onOrder(self, order): """收到委托推送""" pass # ---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 # 如果收到成交,清空所有挂单 self.cancelAll() # 如果交易多头方向,且现在仓位为0,则应该是空头平仓,不再开空单 if trade.direction == DIRECTION_LONG and self.pos == 0: self.frozen = -1 * self.frozen # 如果交易空头方向,且现在仓位为0,则应该是多平仓,不再开多单 elif trade.direction == DIRECTION_SHORT and self.pos == 0: self.frozen = self.frozen self.putEvent() # ---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class BollingerBotStrategy01(CtaTemplate): """基于布林通道的交易策略""" className = 'BollingerBotStrategy01' author = 'Y.Raul' # 策略参数 bollWindow = 28 # 通道窗口数 entryDevUp = 4 # 开仓偏差 entryDevDown = 3.2 # exitDev = 1.2 # 平仓偏差 # trailingPrcnt = 0.4 # 移动止损百分比 maWindow = 10 # 过滤用均线窗口 initDays = 10 # 初始化数据所用的天数 fixedSize = 1 # 每次交易的数量 # 策略变量 bollMid = 0 # 布林带中轨 bollStd = 0 # 布林带宽度 entryUp = 0 # 开仓上轨 # exitUp = 0 # 平仓上轨 entryDown = 0 #开仓下轨 # exitDown = 0 #平仓下轨 dispacedLen = 0 #均线平移长度 maFilter = 0 # 均线过滤 maFilter1 = 0 # 上一期均线 # 分级出场设置 trailingStart1 = 20 trailingStart2 = 30 exitOnTrailingStop1 = 5 # Trailing Stop 距离 exitOnTrailingStop2 = 10 # Trailing Stop 距离 exitOnLossStop = 20 # Loss Stop 距离 # 价格相关变量 intraTradeHigh = 0 # 持仓期内的最高点 intraTradeLow = 0 # 持仓期内的最低点 avgEntryPrice = 0 minDiff = 1 trailingExit = 0 # stopExit = 0 # 空头止损 # longEntry = 0 # 多头开仓 # shortEntry = 0 # 信号相关变量 buySig = False shortSig = False sellSig = False coverSig = False # entrusted = False #是否已有委托 orderList = [] # 保存委托代码的列表 # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'bollWindow', 'entryDevUp', 'entryDevDown', 'trailingStart1', 'trailingStart2', 'exitOnTrailingStop1', 'exitOnTrailingStop2', 'maWindow', 'initDays', 'fixedSize' ] # 变量列表,保存了变量的名称 varList = [ 'inited', 'trading', 'pos', 'buySig', 'shortSig', 'sellSig', 'coverSig', 'entryUp', 'entryDown', 'trailingExit', 'stopExit', 'intraTradeHigh', 'intraTradeLow', 'avgEntryPrice' ] # 同步列表 syncList = ['pos', 'intraTradeHigh'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(BollingerBotStrategy01, self).__init__(ctaEngine, setting) self.bm = BarGenerator(self.onBar, 5, self.onFiveBar) self.am = ArrayManager(30) self.orderList = [] self.entryPriceList = [] #---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.putEvent() #---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略启动' % self.name) self.putEvent() #---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略停止' % self.name) self.putEvent() #---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.bm.updateTick(tick) #---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" # 观察周期1 Min,根据信号进行交易 # 回测数据传送的bar.datetime,为bar的开始时间 self.bm.updateBar(bar) if not self.trading: return self.date = bar.date self.time = bar.time # 检查交易信号 if self.buySig: res = self.buy(bar.close, self.fixedSize, True) self.orderList.extend([x.split('.')[1] for x in res]) # self.orderList.extend(res.split('.')[1]) # self.entryPriceList.append(self.longEntry) # self.avgEntryPrice = sum(self.entryPriceList) / len(self.entryPriceList) # self.LossStopPrice = round(self.avgEntryPrice * (100.0 + self.exitOnLossStop) / 100) # self.intraTradeHigh = max(bar.high, self.avgEntryPrice) # self.intraTradeLow = min(bar.low, self.avgEntryPrice) log = "-----" * 10 + "\n@onBar\n" + \ "bar.datetime: {0}; pos: {1} \n".format(bar.datetime, self.pos) + \ "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig) + \ "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \ "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \ "intraTradeLow: {0}\n".format(self.intraTradeLow) self.writeCtaLog(log) # 记录log log = "\n Trading: {0}\n".format(self.trading) + \ "{0} Buy : longEntry: {1};\n".format(bar.datetime, bar.close) + \ " entryUp:{0}; maFilter:{1}; maFilter1:{2}; \n".format(self.entryUp, self.maFilter, self.maFilter1) self.writeCtaLog(log) self.buySig = False # return if self.shortSig: self.res = self.short(bar.close, self.fixedSize, True) self.orderList.extend([x.split('.')[1] for x in self.res]) # self.orderList.extend(res.split('.')[1]) # self.LossStopPrice = round(self.shortEntry * (100.0 + self.exitOnLossStop) / 100) # self.entryPriceList.append(self.shortEntry) # self.avgEntryPrice = sum(self.entryPriceList) / len(self.entryPriceList) # self.LossStopPrice = round(self.avgEntryPrice * (100.0 + self.exitOnLossStop) / 100) # # self.intraTradeHigh = max(bar.high, self.avgEntryPrice) # self.intraTradeLow = min(bar.low, self.avgEntryPrice) log = "-----" * 10 + "\n@onBar\n" + \ "bar.datetime: {0}; pos: {1} \n".format(bar.datetime, self.pos) + \ "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig) + \ "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \ "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \ "intraTradeLow: {0}\n".format(self.intraTradeLow) self.writeCtaLog(log) # 记录log log = "\n Trading: {0}\n".format(self.trading) + \ "{0} Short : shortEntry: {1};\n".format(bar.datetime, bar.close) + \ " entryDown:{0}; maFilter:{1}; maFilter1:{2}; \n".format(self.entryDown, self.maFilter, self.maFilter1) self.writeCtaLog(log) self.shortSig = False # return if self.sellSig: if bar.close > self.stopExit: price = self.trailingExit else: price = bar.close res = self.sell(price, abs(self.pos), True) # self.orderList.extend(res) log = "-----" * 10 + "\n@onBar\n" + \ "bar.datetime: {0}; pos: {1} \n".format(bar.datetime, self.pos) + \ "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig) + \ "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \ "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \ "intraTradeLow: {0}\n".format(self.intraTradeLow) self.writeCtaLog(log) # 记录log log = "\n Trading: {0}\n".format(self.trading) + \ "{0} Sell : {1};\n".format(bar.datetime, bar.close) + \ " price:{0}; stopExit: {1}\n".format(price,self.stopExit) self.writeCtaLog(log) # self.entryPriceList = [] # self.avgEntryPrice = 0 # self.stopExit = 0 self.sellSig = False # return if self.coverSig: if bar.close < self.stopExit: price = self.trailingExit else: price = bar.close res = self.cover(price, abs(self.pos), True) # self.orderList.extend(res) log = "-----" * 10 + "\n@onBar\n" + \ "bar.datetime: {0}; pos: {1} \n".format(bar.datetime, self.pos) + \ "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig) + \ "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \ "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \ "intraTradeLow: {0}\n".format(self.intraTradeLow) self.writeCtaLog(log) # 记录log log = "\n Trading: {0}\n".format(self.trading) + \ "{0} Cover : {1};\n".format(bar.datetime, bar.close) + \ " price:{0}; stopExit: {1}\n".format(price,self.stopExit) self.writeCtaLog(log) # self.entryPriceList = [] # self.avgEntryPrice = 0 # self.stopExit = 0 self.coverSig = False # return self.putEvent() #---------------------------------------------------------------------- def onFiveBar(self, bar): """收到5分钟K线""" # 策略周期5Min,生成交易信号 # 保存K线数据 if not self.trading: return self.am.updateBar(bar) if not self.am.inited: return # 撤销之前发出的尚未成交的委托(包括限价单和停止单) self.cancelAll() # 计算指标数值 self.bollMid = self.am.sma(self.bollWindow, True)[-1 * (self.dispacedLen + 1)] self.bollStd = self.am.std(self.bollWindow) self.entryUp = round(self.bollMid + self.bollStd * self.entryDevUp) self.entryDown = round(self.bollMid - self.bollStd * self.entryDevDown) maArray = self.am.sma(self.maWindow, True) self.maFilter = round(maArray[-1]) self.maFilter1 = round(maArray[-2]) # 判断是否要进行交易 # 当前无仓位 if self.pos == 0: self.intraTradeHigh = bar.high self.intraTradeLow = bar.low self.entryPriceList = [] self.orderList = [] self.avgEntryPrice = 0 if bar.close > self.maFilter and self.maFilter > self.maFilter1: # 均线多头过滤 if bar.close >= self.entryUp: # 上轨突破 self.buySig = True if bar.close < self.maFilter and self.maFilter < self.maFilter1: # 均线空头过滤 if bar.close <= self.entryDown: # 下轨突破 self.shortSig = True log = "-----" * 10 + "\n@onFiveBar\n" + \ "bar.datetime: {0}; pos: {1} ; close: {2}\n".format(bar.datetime, self.pos,bar.close) + \ "buySig: {0}; shortSig: {1}\n".format(self.buySig, self.shortSig) + \ "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \ "intraTradeLow: {0}\n".format(self.intraTradeLow) self.writeCtaLog(log) # 当前有仓位 else: self.intraTradeHigh = max(self.intraTradeHigh, bar.high) self.intraTradeLow = min(self.intraTradeLow, bar.low) if self.pos > 0: # self.stopExit = self.avgEntryPrice - self.exitOnLossStop * self.minDiff #固定止损价位 if self.intraTradeHigh >= self.avgEntryPrice + self.trailingStart2 * self.minDiff: # 二级止赢判断 盈利80跳 if (bar.close <= self.intraTradeHigh - self.exitOnTrailingStop2 * self.minDiff): # 回撤20跳 self.trailingExit = self.intraTradeHigh - self.exitOnTrailingStop2 * self.minDiff self.sellSig = True # if bar.close < self.longExit: # self.longExit = bar.close # 记录log # log = "\n{0} Sell(Trailing Stop2)\n".format(bar.datetime) + \ # 'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close,bar.low, self.longExit)+ \ # 'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh,self.avgEntryPrice, bar.open) # self.writeCtaLog(log) elif self.intraTradeHigh >= self.avgEntryPrice + self.trailingStart1 * self.minDiff: # 一级止赢判断,盈利50跳 if (bar.close <= self.intraTradeHigh - self.exitOnTrailingStop1 * self.minDiff): # 回撤20跳 self.trailingExit = self.intraTradeHigh - self.exitOnTrailingStop1 * self.minDiff self.sellSig = True # if bar.close < self.longExit: # self.longExit = bar.close # 记录log # log = "\n{0} Sell(Trailing Stop1)\n".format(bar.datetime) + \ # 'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close, bar.low, # self.longExit)+ \ # 'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh,self.avgEntryPrice, bar.open) # self.writeCtaLog(log) elif self.stopExit != 0: if (bar.close <= self.stopExit): # 固定止损,回撤20跳 self.sellSig = True log = "-----" * 10 + "\n@onFiveBar\n" + \ "bar.datetime: {0}; pos: {1} ; close:{2}\n".format(bar.datetime, self.pos, bar.close) + \ "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \ "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \ "intraTradeLow: {0}\n".format(self.intraTradeLow) + \ "trailingStart1: {0}\n".format(self.avgEntryPrice + self.trailingStart1 * self.minDiff) + \ "trailingStart2: {0}\n".format(self.avgEntryPrice + self.trailingStart2 * self.minDiff) + \ "avgEntryPrice: {0}\n".format(self.avgEntryPrice) + \ "trailingStop: {0}\n".format(self.trailingExit) + \ "stopExit: {0}\n".format(self.stopExit) self.writeCtaLog(log) # if bar.close < self.longExit: # self.longExit = bar.close # 记录log # log = "\n{0} Sell(Loss Stop)\n".format(bar.datetime) + \ # 'bar.close: {0}; bar.low: {1}; longExit: {2}'.format(bar.close, bar.low, # self.longExit)+ \ # 'intraTradeHigh: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeHigh, # self.avgEntryPrice, # bar.open) # self.writeCtaLog(log) elif self.pos < 0: # self.stopExit = self.avgEntryPrice + self.exitOnLossStop * self.minDiff #固定止损价 if self.intraTradeLow <= self.avgEntryPrice - self.trailingStart2 * self.minDiff: # 二级止赢判断 盈利80跳 if (bar.close >= self.intraTradeLow + self.exitOnTrailingStop2 * self.minDiff): # 回撤20跳 self.trailingExit = self.intraTradeLow + self.exitOnTrailingStop2 * self.minDiff self.coverSig = True # if bar.close > self.shortExit: # self.shortExit = bar.close # 记录log # log = "\n{0} Cover(Trailing Stop1)\n".format(bar.datetime) + \ # 'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low, # self.shortExit)+ \ # 'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow, # self.avgEntryPrice, # bar.open) # self.writeCtaLog(log) elif self.intraTradeLow <= self.avgEntryPrice - self.trailingStart1 * self.minDiff: # 一级止赢判断,盈利50跳 if (bar.close >= self.intraTradeLow + self.exitOnTrailingStop1 * self.minDiff): # 回撤20跳 self.trailingExit = self.intraTradeLow + self.exitOnTrailingStop1 * self.minDiff self.coverSig = True # if bar.close > self.shortExit: # self.shortExit = bar.close # 记录log # log = "\n{0} Cover(Trailing Stop2)\n".format(bar.datetime) + \ # 'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low, # self.shortExit)+ \ # 'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow, # self.avgEntryPrice, # bar.open) # self.writeCtaLog(log) elif self.stopExit != 0: if (bar.close >= self.stopExit): # 固定止损,回撤20跳 # self.shortExit = self.avgEntryPrice + self.exitOnLossStop * self.minDiff self.coverSig = True # if bar.close > self.shortExit: # self.shortExit = bar.close # 记录log # log = "\n{0} Cover(Loss Stop)\n".format(bar.datetime) + \ # 'bar.close: {0}; bar.low: {1}; shortExit: {2}'.format(bar.close, bar.low, # self.shortExit)+ \ # 'intraTradeLow: {0}; avgEntryPrice: {1}; bar.open: {2}'.format(self.intraTradeLow, # self.avgEntryPrice, # bar.open) # self.writeCtaLog(log) log = "-----" * 10 + "\n@onFiveBar\n" + \ "bar.datetime: {0}; pos: {1} ; close:{2}\n".format(bar.datetime, self.pos, bar.close) + \ "sellSig: {0}; coverSig: {1}\n".format(self.sellSig, self.coverSig) + \ "intraTradeHigh: {0}\n".format(self.intraTradeHigh) + \ "intraTradeLow: {0}\n".format(self.intraTradeLow) + \ "trailingStart1: {0}\n".format(self.avgEntryPrice - self.trailingStart1 * self.minDiff)+\ "trailingStart2: {0}\n".format(self.avgEntryPrice - self.trailingStart2 * self.minDiff)+\ "avgEntryPrice: {0}\n".format(self.avgEntryPrice)+\ "trailingStop: {0}\n".format(self.trailingExit)+\ "stopExit: {0}\n".format(self.stopExit) self.writeCtaLog(log) # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" # CTA引擎中涉及到的交易方向类型 # CTAORDER_BUY = u'买开' # CTAORDER_SELL = u'卖平' # CTAORDER_SHORT = u'卖开' # CTAORDER_COVER = u'买平' log = "-----" * 10 + "\n@onOrder\n" + \ "orderTime: {0}; pos: {1} \n".format(order.orderTime, order.totalVolume) + \ u"status {0}; vtOrderID: {1}\n".format(order.status, order.vtOrderID) self.writeCtaLog(log) # 对于开仓,记录相关价格 # if order.vtOrderID in self.orderList: if order.direction == DIRECTION_LONG and order.offset == OFFSET_OPEN: if order.totalVolume == order.tradedVolume: # 更新入场价列表,更新平均入场价 self.entryPriceList.append(order.price) self.avgEntryPrice = sum(self.entryPriceList) / len( self.entryPriceList) self.stopExit = self.avgEntryPrice - self.exitOnLossStop * self.minDiff # 固定止损价 # self.orderList.remove(order.vtOrderID) elif order.direction == DIRECTION_SHORT and order.offset == OFFSET_OPEN: # 更新入场价列表,更新平均入场价 if order.totalVolume == order.tradedVolume: # 更新入场价列表,更新平均入场价 self.entryPriceList.append(order.price) self.avgEntryPrice = sum(self.entryPriceList) / len( self.entryPriceList) self.stopExit = self.avgEntryPrice + self.exitOnLossStop * self.minDiff # 固定止损价 # self.orderList.remove(order.vtOrderID) self.putEvent() #---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 data = trade.__dict__ self.putEvent() #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" data = so.__dict__ self.putEvent()