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.bm5 = BarManager(self.onBar, 5, self.on5MinBar) self.am5 = ArrayManager() self.bm15 = BarManager(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.bm5.updateTick(tick) #---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" # 基于15分钟判断趋势过滤,因此先更新 self.bm15.updateBar(bar) # 基于5分钟判断 self.bm5.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 RBreakStrategy5(CtaTemplate): """改进型RBreak策略""" className = "RBreakStrategy5" autor = "张英杰" # 策略参数 initDays = 10 # 数据初始化天数 N2 = 8.5 N3 = 5.0 N4 = 6.0 N5 = 7.5 N6 = 4.5 fixedSize = 1 # 每次交易数量 # 策略变量 intraTradeHigh = 0.0 # 移动止损用的持仓期内最高价 intraTradeLow = 0.0 # 移动止损用的持仓期内最低价 open_price = None # 最新开仓价格 order_list = [] # 下单列表 # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'autor', 'vtSymbol', ] # 变量列表,保存了变量的名称 varList = [ 'inited', 'trading', 'pos', ] def __init__(self, ctaEngine, setting): """Constructor""" super(RBreakStrategy5, self).__init__(ctaEngine, setting) # 创建bar管理器(K线合成对象),用于合成bar和处理自定义周期的bar回调函数 self.bm = BarManager(onBar=self.onBar, xmin=5, onXminBar=self.onFifteenBar) # 创建k线序列管理工具 self.am = ArrayManager2() self.dam = DailyArrayManager() # 策略变量 self.date = None # 日期 self.pre_date = None # 上个交易日日期 # 基础数据获取 self.HH1 = 0. # 上个交易日收盘bar最高价 self.LL1 = 0. # 上个交易日收盘bar最低价 self.CC1 = 0. # 上个交易日收盘价 self.HH2 = 0. # 前个交易日收盘bar最高价 self.LL2 = 0. # 前个交易日收盘bar最低价 self.C1 = 0. # 当日开盘价 self.MN1 = 0. # MN1=当日开盘价/2 + (昨日最高+昨日最低+昨日收盘)/6 self.RANGE1 = 0. # RANGE1 = (昨日最高-昨日最低)*0.65 + (前日最高-前日最低)*0.35 self.SIZECK1 = 0. # SIZECK1 = (当前BAR收盘价 - 当前BAR开盘价)的绝对值/当前BAR收盘价 < 0.5% 振幅不超过0.5% self.SIZECK2 = 0. # self.U2 = 0. # 追买中轴线 self.U3 = 0. # 追买止损线 self.U4 = 0. # 卖出止损线 self.U5 = 0. # 卖出中轴线 self.U6 = 0. # 突破做空 self.D6 = 0. # 突破做多 self.D5 = 0. # 做多中轴线 self.D4 = 0. # 做多止损线 self.D3 = 0. # 追卖止损线 self.D2 = 0. # 追卖中轴线 def onInit(self): """初始化策略,必须由用户继承实现""" self.writeCtaLog("%s初始化策略" % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 initData = self.loadBar(days=self.initDays) # 预处理初始化的bar for bar in initData: self.onBar(bar) # 发出策略状态变化事件 self.putEvent() def onStart(self): '''启动策略(必须由用户继承实现)''' self.writeCtaLog("%s策略启动" % self.name) # 发出策略状态变化事件 self.putEvent() # 目前的结论是回测时候该方法为pass,实盘通常用于通知界面更新 def onStop(self): '''停止策略(必须由用户继承实现)''' self.writeCtaLog("%s策略停止" % self.name) # 发出策略状态变化事件 self.putEvent() def onTick(self, tick): '''收到TICK推送,必须由用户继承实现''' # 更新tick,合成k线 self.bm.updateTick(tick) def onBar(self, bar): """收到bar推送(必须由用户继承实现)""" self.bm.updateBar( bar) # 一分钟一个bar,执行周期大于1分钟的策略在自定义的执行方法里,到时间了由bm.updataBar回调执行 def onFifteenBar(self, bar): '''收到15分钟K线推送的回调函数''' # if bar.date == "20171222": # print(111) # 保存K线数据 am = self.am am.updateBar(bar) # 保存日K数据 dam = self.dam dam.updateBar(bar) # 日期更换 # 第一天 if self.date is None: self.date = bar.date # 更换日期 elif self.date != bar.date: self.pre_date = self.date self.date = bar.date self.CC1 = dam.close[-2] # 上个交易日收盘价 self.HH2 = self.HH1 # 前个交易日收盘bar最高价 self.LL2 = self.LL1 # 前个交易日收盘bar最低价 self.HH1 = am.close[-2] # 重置昨日每个bar收盘最高价 self.LL1 = am.close[-2] # 重置昨日每个bar收盘最低价 for i in range(-3, -100, -1): if str(am.date[i]) != self.pre_date: break # 基础数据计算 self.HH1 = max(am.close[i], self.HH1) # 上个交易日收盘bar最高价 self.LL1 = min(am.close[i], self.LL1) # 上个交易日收盘bar最低价 self.C1 = dam.open[-1] # 当日开盘价 self.MN1 = self.C1 / 2 + (self.HH1 + self.LL1 + self.CC1 ) / 6 # MN1=当日开票价/2 + (昨日最高+昨日最低+昨日收盘)/6 self.RANGE1 = (self.HH1 - self.LL1) * 0.65 + ( self.HH2 - self.LL2 ) * 0.35 # RANGE1 = (昨日最高-昨日最低)*0.65 + (前日最高-前日最低)*0.35 # 参数计算 self.U2 = self.MN1 + self.RANGE1 * self.N2 / 10 # 追买中轴线 self.U3 = self.MN1 + self.RANGE1 * self.N3 / 10 # 追买止损线 self.U4 = self.MN1 + self.RANGE1 * self.N4 / 10 # 卖出止损线 self.U5 = self.MN1 + self.RANGE1 * self.N5 / 10 # 卖出中轴线 self.U6 = self.MN1 + self.RANGE1 * self.N6 / 10 # 突破做空 self.D6 = self.MN1 - self.RANGE1 * self.N6 / 10 # 突破做多 self.D5 = self.MN1 - self.RANGE1 * self.N5 / 10 # 做多中轴线 self.D4 = self.MN1 - self.RANGE1 * self.N4 / 10 # 做多止损线 self.D3 = self.MN1 - self.RANGE1 * self.N3 / 10 # 追卖止损线 self.D2 = self.MN1 - self.RANGE1 * self.N2 / 10 # 追卖中轴线 # 如果k线还没有初始化完成,就不执行 if not am.inited: return # 如果日k线还没有初始化完成,就不执行 if not dam.inited: return # 当前bar上下开仓的振幅是否符合条件 self.SIZECK1 = abs( bar.close - bar.open ) / bar.close < 5 / 1000 # SIZECK1 = (当前BAR收盘价 - 当前BAR开盘价)的绝对值/当前BAR收盘价 < 0.5% 振幅不超过0.5% self.SIZECK2 = abs(bar.close - bar.open) / bar.close < 5 / 1000 # 交易决策 # 1.观察区突破开仓 time_now = bar.datetime.time() time_0915 = time_now.replace(hour=9, minute=15, second=0) time_1429 = time_now.replace(hour=14, minute=29, second=0) time_1500 = time_now.replace(hour=15, minute=0, second=0) time_last = time_now.replace(hour=15, minute=9, second=0) # 空仓 if self.pos == 0: # 持有期内最高最低价 self.intraTradeHigh = bar.close self.intraTradeLow = bar.close # self.open_price = None # 9:15 -- 14:29 之间 if time_now >= time_0915 and time_now <= time_1429: # 价格下穿U6,股价前30个BAR(不包括当前)的收盘最高值大于U5,当前BAR振幅小于0.5%,开空头 if am.close[-1] < self.U6 and am.close[ -2] >= self.U6 and am.close[-3] > self.U6 and am.close[ -31:-1].max() > self.U5 and self.SIZECK2: self.cancelAll() self.short(price=bar.close - 0.01, volume=self.fixedSize) # self.open_price = bar.close # 价格上穿D6,最近30个BAR收盘价(不包括当前)的最小值小于D5,当前BAR振幅小于0.5%,开多头 if am.close[-1] > self.D6 and am.close[ -2] <= self.D6 and am.close[-3] < self.D6 and am.close[ -31:-1].min() < self.D5 and self.SIZECK1: self.cancelAll() self.buy(price=bar.close + 0.01, volume=self.fixedSize) self.open_price = bar.close # 时间在9:50和14:29之间 TIME>0915 && TIME<1500 if time_now >= time_0915 and time_now <= time_1500: # && CROSSUP(C,U2) && SIZECK1,BK 突破开仓 if am.close[-1] > self.U2 and am.close[ -2] <= self.U2 and am.close[ -3] < self.U2 and self.SIZECK1: self.cancelAll() self.buy(price=bar.close + 0.01, volume=self.fixedSize) # self.open_price = bar.close # CROSSDOWN(C,D2) && SIZECK2,SK; elif am.close[-1] < self.D2 and am.close[ -2] >= self.D2 and am.close[ -3] > self.D2 and self.SIZECK2: self.cancelAll() self.short(price=bar.close - 0.01, volume=self.fixedSize) # self.open_price = bar.close # 持有多头: elif self.pos > 0: self.intraTradeHigh = max(self.intraTradeHigh, bar.close) self.intraTradeLow = min(self.intraTradeLow, bar.close) # 价格上穿U6,止盈 if am.close[-1] > self.U6 and am.close[-2] <= self.U6: self.cancelAll() self.sell(price=bar.close - 0.01, volume=self.fixedSize) # 价格下穿D4,止损 elif am.close[-1] < self.D4 and am.close[-2] >= self.U6: self.cancelAll() self.sell(price=bar.close - 0.01, volume=self.fixedSize) # 价格下穿U3,平仓 elif am.close[-1] < self.U3 and am.close[-2] >= self.U3: self.cancelAll() self.sell(price=bar.close - 0.01, volume=self.fixedSize) # 上一次买入到现在(不含当前bar)的最高价 > 买入价格 * (1 + 0.002), 并且 (当前收盘价 - 成本)<= (到目前为止收盘最高价 - 成本)* 0.5 elif self.intraTradeHigh > self.open_price * (1 + 0.002) and ( am.close[-1] - self.open_price) <= (self.intraTradeHigh - self.open_price) * 0.5: self.cancelAll() self.sell(price=bar.close - 0.01, volume=self.fixedSize) # 价格下穿 开仓价格 * (1 - 0.9/1000) 止损 elif am.close[-1] < self.open_price * ( 1 - 0.9 / 1000) and am.close[-2] >= self.open_price * ( 1 - 0.9 / 1000): self.cancelAll() self.sell(price=bar.close - 0.01, volume=self.fixedSize) # 持有空头; elif self.pos < 0: self.intraTradeHigh = max(self.intraTradeHigh, bar.close) self.intraTradeLow = min(self.intraTradeLow, bar.close) # 价格下穿D6,平掉空头,止盈 if am.close[-1] < self.D6 and am.close[-2] >= self.D6: self.cancelAll() self.cover(price=bar.close + 0.01, volume=self.fixedSize) # 价格上穿U4,平掉空头(止损) elif am.close[-1] > self.U4 and am.close[-2] <= self.U4: self.cancelAll() self.cover(price=bar.close + 0.01, volume=self.fixedSize) # 价格上穿D3,平仓 elif am.close[-1] > self.D3 and am.close[-2] <= self.D3: self.cancelAll() self.cover(price=bar.close + 0.01, volume=self.fixedSize) # 上一次买入到现在(不含当前bar)的最低价 < 买入价格 * (1 + 0.002), 并且 (成本 - 当前收盘价)<= (成本 - 到目前为止收盘最低价)* 0.5 止盈 elif self.intraTradeLow < self.open_price * ( 1 - 0.002) and self.open_price - bar.close <= ( self.open_price - self.intraTradeLow) * 0.5: self.cancelAll() self.cover(price=bar.close + 0.01, volume=self.fixedSize) # 价格上 开仓价格 * (1 + 0.9 / 1000) 止损 elif am.close[-1] > self.open_price * ( 1 + 0.9 / 1000) and am.close[-2] <= self.open_price * ( 1 + 0.9 / 1000): self.cancelAll() self.cover(price=bar.close + 0.01, volume=self.fixedSize) # 当天收盘则平仓所有 if time_now >= time_last and bar.datetime.weekday() == 5 - 1: self.closeAllPosition(bar) self.putEvent() def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass def onTrade(self, trade): """收到交易发生事件推送""" if trade.offset == "平仓": self.open_price = None if trade.offset == "开仓": self.open_price = trade.price self.putEvent() def onStopOrder(self, so): """收到停止单事件推送""" self.putEvent() def closeAllPosition(self, bar): self.cancelAll() if self.pos > 0: self.sell(price=bar.close - 0.01, volume=self.fixedSize) elif self.pos < 0: self.cover(price=bar.close + 0.01, volume=self.fixedSize)
class DoubleMaStrategy(CtaTemplate): """双指数均线策略Demo""" className = 'DoubleMaStrategy' author = '用Python的交易员' # 策略参数 fastWindow = 10 # 快速均线参数 slowWindow = 60 # 慢速均线参数 initDays = 10 # 初始化数据所用的天数 # 策略变量 fastMa0 = EMPTY_FLOAT # 当前最新的快速EMA fastMa1 = EMPTY_FLOAT # 上一根的快速EMA slowMa0 = EMPTY_FLOAT slowMa1 = EMPTY_FLOAT # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'fastWindow', 'slowWindow' ] # 变量列表,保存了变量的名称 varList = [ 'inited', 'trading', 'pos', 'fastMa0', 'fastMa1', 'slowMa0', 'slowMa1' ] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(DoubleMaStrategy, self).__init__(ctaEngine, setting) self.bm = BarManager(self.onBar) self.am = ArrayManager() # 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建, # 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险, # 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读 # 策略时方便(更多是个编程习惯的选择) #---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog('双EMA演示策略初始化') initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.putEvent() #---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog('双EMA演示策略启动') self.putEvent() #---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog('双EMA演示策略停止') self.putEvent() #---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.bm.updateTick(tick) #---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" am = self.am am.updateBar(bar) if not am.inited: return # 计算快慢均线 fastMa = am.sma(self.fastWindow, array=True) self.fastMa0 = fastMa[-1] self.fastMa1 = fastMa[-2] slowMa = am.sma(self.slowWindow, array=True) self.slowMa0 = slowMa[-1] self.slowMa1 = slowMa[-2] # 判断买卖 crossOver = self.fastMa0 > self.slowMa0 and self.fastMa1 < self.slowMa1 # 金叉上穿 crossBelow = self.fastMa0 < self.slowMa0 and self.fastMa1 > self.slowMa1 # 死叉下穿 # 金叉和死叉的条件是互斥 # 所有的委托均以K线收盘价委托(这里有一个实盘中无法成交的风险,考虑添加对模拟市价单类型的支持) if crossOver: # 如果金叉时手头没有持仓,则直接做多 if self.pos == 0: self.buy(bar.close, 1) # 如果有空头持仓,则先平空,再做多 elif self.pos < 0: self.cover(bar.close, 1) self.buy(bar.close, 1) # 死叉和金叉相反 elif crossBelow: if self.pos == 0: self.short(bar.close, 1) elif self.pos > 0: self.sell(bar.close, 1) self.short(bar.close, 1) # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" # 对于无需做细粒度委托控制的策略,可以忽略onOrder pass #---------------------------------------------------------------------- def onTrade(self, trade): """收到成交推送(必须由用户继承实现)""" # 对于无需做细粒度委托控制的策略,可以忽略onOrder pass #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class DualThrustStrategy(CtaTemplate): """DualThrust交易策略""" className = 'DualThrustStrategy' author = u'用Python的交易员' # 策略参数 fixedSize = 100 k1 = 0.4 k2 = 0.6 initDays = 10 # 策略变量 barList = [] # K线对象的列表 dayOpen = 0 dayHigh = 0 dayLow = 0 range = 0 longEntry = 0 shortEntry = 0 exitTime = time(hour=14, minute=55) longEntered = False shortEntered = False # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'author', 'vtSymbol', 'k1', 'k2'] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'range', 'longEntry', 'shortEntry', 'exitTime'] # 同步列表,保存了需要保存到数据库的变量名称 syncList = ['pos'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(DualThrustStrategy, self).__init__(ctaEngine, setting) self.bm = BarManager(self.onBar) self.barList = [] #---------------------------------------------------------------------- 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.cancelAll() # 计算指标数值 self.barList.append(bar) if len(self.barList) <= 2: return else: self.barList.pop(0) lastBar = self.barList[-2] # 新的一天 if lastBar.datetime.date() != bar.datetime.date(): # 如果已经初始化 if self.dayHigh: self.range = self.dayHigh - self.dayLow self.longEntry = bar.open + self.k1 * self.range self.shortEntry = bar.open - self.k2 * self.range self.dayOpen = bar.open self.dayHigh = bar.high self.dayLow = bar.low self.longEntered = False self.shortEntered = False else: self.dayHigh = max(self.dayHigh, bar.high) self.dayLow = min(self.dayLow, bar.low) # 尚未到收盘 if not self.range: return if bar.datetime.time() < self.exitTime: if self.pos == 0: if bar.close > self.dayOpen: if not self.longEntered: self.buy(self.longEntry, self.fixedSize, stop=True) else: if not self.shortEntered: self.short(self.shortEntry, self.fixedSize, stop=True) # 持有多头仓位 elif self.pos > 0: self.longEntered = True # 多头止损单 self.sell(self.shortEntry, self.fixedSize, stop=True) # 空头开仓单 if not self.shortEntered: self.short(self.shortEntry, self.fixedSize, stop=True) # 持有空头仓位 elif self.pos < 0: self.shortEntered = True # 空头止损单 self.cover(self.longEntry, self.fixedSize, stop=True) # 多头开仓单 if not self.longEntered: self.buy(self.longEntry, self.fixedSize, stop=True) # 收盘平仓 else: if self.pos > 0: self.sell(bar.close * 0.99, abs(self.pos)) elif self.pos < 0: self.cover(bar.close * 1.01, abs(self.pos)) # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass #---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class AtrRsiStrategy(CtaTemplate): """结合ATR和RSI指标的一个分钟线交易策略""" className = 'AtrRsiStrategy' author = u'用Python的交易员' # 策略参数 atrLength = 22 # 计算ATR指标的窗口数 atrMaLength = 10 # 计算ATR均线的窗口数 rsiLength = 5 # 计算RSI的窗口数 rsiEntry = 16 # RSI的开仓信号 trailingPercent = 0.8 # 百分比移动止损 initDays = 10 # 初始化数据所用的天数 fixedSize = 1 # 每次交易的数量 # 策略变量 atrValue = 0 # 最新的ATR指标数值 atrMa = 0 # ATR移动平均的数值 rsiValue = 0 # RSI指标的数值 rsiBuy = 0 # RSI买开阈值 rsiSell = 0 # RSI卖开阈值 intraTradeHigh = 0 # 移动止损用的持仓期内最高价 intraTradeLow = 0 # 移动止损用的持仓期内最低价 # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'author', 'vtSymbol', 'atrLength', 'atrMaLength', 'rsiLength', 'rsiEntry', 'trailingPercent'] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'atrValue', 'atrMa', 'rsiValue', 'rsiBuy', 'rsiSell'] # 同步列表,保存了需要保存到数据库的变量名称 syncList = ['pos', 'intraTradeHigh', 'intraTradeLow'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(AtrRsiStrategy, self).__init__(ctaEngine, setting) # 创建K线合成器对象 self.bm = BarManager(self.onBar) self.am = ArrayManager() # 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建, # 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险, # 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读 # 策略时方便(更多是个编程习惯的选择) #---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' %self.name) # 初始化RSI入场阈值 self.rsiBuy = 50 + self.rsiEntry self.rsiSell = 50 - self.rsiEntry # 载入历史数据,并采用回放计算的方式初始化策略数值 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.cancelAll() # 保存K线数据 am = self.am am.updateBar(bar) if not am.inited: return # 计算指标数值 atrArray = am.atr(self.atrLength, array=True) self.atrValue = atrArray[-1] self.atrMa = atrArray[-self.atrMaLength:].mean() self.rsiValue = am.rsi(self.rsiLength) # 判断是否要进行交易 # 当前无仓位 if self.pos == 0: self.intraTradeHigh = bar.high self.intraTradeLow = bar.low # ATR数值上穿其移动平均线,说明行情短期内波动加大 # 即处于趋势的概率较大,适合CTA开仓 if self.atrValue > self.atrMa: # 使用RSI指标的趋势行情时,会在超买超卖区钝化特征,作为开仓信号 if self.rsiValue > self.rsiBuy: # 这里为了保证成交,选择超价5个整指数点下单 self.buy(bar.close+5, self.fixedSize) elif self.rsiValue < self.rsiSell: self.short(bar.close-5, self.fixedSize) # 持有多头仓位 elif self.pos > 0: # 计算多头持有期内的最高价,以及重置最低价 self.intraTradeHigh = max(self.intraTradeHigh, bar.high) self.intraTradeLow = bar.low # 计算多头移动止损 longStop = self.intraTradeHigh * (1-self.trailingPercent/100) # 发出本地止损委托 self.sell(longStop, abs(self.pos), stop=True) # 持有空头仓位 elif self.pos < 0: self.intraTradeLow = min(self.intraTradeLow, bar.low) self.intraTradeHigh = bar.high shortStop = self.intraTradeLow * (1+self.trailingPercent/100) self.cover(shortStop, abs(self.pos), stop=True) # 同步数据到数据库 self.saveSyncData() # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass #---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class turtleStrategy(CtaTemplate): className = 'turtleStrategy' #策略参数 shortInDate = 20 longInDate = 55 shortOutDate = 10 longOutDate = 20 loss = 0.1 adjust = 0.8 numberDays =20 unitLimit = 4 ratio = 0.8 #策略变量 unit = 10 N = [] days = 0 breakPrice1 = 0 breakPrice2 = 0 sys1 = 0 sys2 = 0 system1 = True # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'author', 'vtSymbol', 'shortInDate', 'longInDate', 'shortOutDate', 'longOutDate', 'loss', 'adjust', 'numberDays', 'unitLimit', 'ratio'] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'unit', 'N', 'days', 'breakPrice1', 'breakPrice2', 'sys1', 'sys2', 'system1'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(turtleStrategy, self).__init__(ctaEngine, setting) self.bm = BarManager(self.onBar) self.am = ArrayManager() # 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建, # 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险, # 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读 # 策略时方便(更多是个编程习惯的选择) #---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'双EMA演示策略初始化') initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.putEvent() #---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog(u'双EMA演示策略启动') self.putEvent() #---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'双EMA演示策略停止') self.putEvent() #---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.bm.updateTick(tick) #---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" def handleData(context,data): dt = context.current_dt current_price = data[security].price if dt.hour == 9 and dt.minute == 30: days += 1 calculate_N() if days > numberdays: value = context.portfolio.portfolio_value cash = context.portfolio.cash if sys1 == 0 and sys2 == 0: if value < (1-loss)*context*portfolio.starting_cash: cash *= adjust value = adjust dollarvolatility = dollarPerShare*N[-1] unit = value*0.01/dollarvolatility system1 = True if sys1 == 0: marketIn(current_price,ratio*cash,shortInDate) else: stopLoss(current_price) marKetAdd(current_price,ratio*cash,shortInDate) marketOut(current_price,shortOutDdate) system1 = False if sys == 0: marketIn(current_price,ratio*cash,longInDate) else: stopLoss(current_price) marKetAdd(current_price,ratio*cash,longInDate) marketOut(current_price,longOutDdate) def calculate_N(): if days <= numberDays: price = attribute_history(g.security, g.days, '1d',('high','low','close')) lst = [] for i in range(0,days): hl = price['high'][i] - price['low'][i] hc = price['high'][i] - price['close'][i] cl = price['close'][i] - price['low'][i] trueRange = max(hl,hc,cl) lst.append(trueRange) currentN = np.mean(np.array(lst)) N.append(currentN) else: price = attribute_history(g.security, 1, '1d',('high','low','close')) h_l = price['high'][0]-price['low'][0] h_c = price['high'][0]-price['close'][0] c_l = price['close'][0]-price['low'][0] trueRange = max(hl,hc,cl) current_N = (True_Range + (g.number_days-1)*(g.N)[-1])/g.number_days (g.N).append(current_N) def marketIn(current_price,cash,in_date): price = attribute_history(g.security, in_date, '1d', ('close')) if current_price > max(price['close']): num_of_shares = cash/current_price if num_of_shares >= g.unit: print "买入" print current_price print max(price['close']) if g.system1 == True: if g.sys1 < int(g.unit_limit*g.unit): order(g.security, int(g.unit)) g.sys1 += int(g.unit) g.break_price1 = current_price else: if g.sys2 < int(g.unit_limit*g.unit): order(g.security, int(g.unit)) g.sys2 += int(g.unit) g.break_price2 = current_price def market_add(current_price, cash, in_date): if g.system1 == True: break_price=g.break_price1 else: break_price=g.break_price2 # 每上涨0.5N,加仓一个单元 if current_price >= break_price + 0.5*(g.N)[-1]: num_of_shares = cash/current_price # 加仓 if num_of_shares >= g.unit: print "加仓" print g.sys1 print g.sys2 print current_price print break_price + 0.5*(g.N)[-1] if g.system1 == True: if g.sys1 < int(g.unit_limit*g.unit): order(g.security, int(g.unit)) g.sys1 += int(g.unit) g.break_price1 = current_price else: if g.sys2 < int(g.unit_limit*g.unit): order(g.security, int(g.unit)) g.sys2 += int(g.unit) g.break_price2 = current_price #8 # 离场函数 # 输入:当前价格-float, 天数-int # 输出:none def market_out(current_price, out_date): # Function for leaving the market price = attribute_history(g.security, out_date, '1d', ('close')) # 若当前价格低于前out_date天的收盘价的最小值, 则卖掉所有持仓 if current_price < min(price['close']): print "离场" print current_price print min(price['close']) if g.system1 == True: if g.sys1>0: order(g.security, -g.sys1) g.sys1 = 0 else: if g.sys2>0: order(g.security, -g.sys2) g.sys2 = 0 #9 # 止损函数 # 输入:当前价格-float # 输出:none def stop_loss(current_price): # 损失大于2N,卖出股票 if g.system1 == True: break_price = g.break_price1 else: break_price = g.break_price2 # If the price has decreased by 2N, then clear all position if current_price < (break_price - 2*(g.N)[-1]): print "止损" print current_price print break_price - 2*(g.N)[-1] if g.system1 == True: order(g.security, -g.sys1) g.sys1 = 0 else: order(g.security, -g.sys2) g.sys2 = 0
class tick_strategy(CtaTemplate): """结合ATR和RSI指标的一个分钟线交易策略""" className = 'CN' author = u'张安翔' buyOrderIDList = [] # 委托买入开仓的委托号 shortOrderIDList = [] # 委托卖出开仓的委托号 orderList = [] # 保存委托代码的列表 # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'maxHold', 'maxWin', 'minLose', 'mutiple', 'volume', 'init_asset', 'minEnterPrice', 'MaxTolerate' ] # 变量列表,保存了变量的名称 varList = [ 'LongSignalSpread', 'ShortSignalSpread', 'pos', 'atrValue', 'atrMa', 'rsiValue', 'rsiBuy', 'rsiSell' ] def __init__(self, ctaEngine, setting): # 策略参数 self.contract_size = 100 self.MaxTolerate = 0 self.maxHold = 0 self.Ticks = 4 #追单数量 self.stopping = False self.stoppingdt = None # 止损后最小开仓时间 self.stoppPeriods = 15 # 止损后15分钟不能开仓 self.ShortSignalSpread = None self.LongSignalSpread = None self.short_enter_price = None self.short_exit_price = None self.long_enter_price = None self.long_exit_price = None self.maxHold = 0 self.maxWin = 0 self.minLose = 0 self.mutiple = 0 self.minEnterPrice = 0 self.volume = 0 self.init_asset = 0 """Constructor""" super(tick_strategy, self).__init__(ctaEngine, setting) # 策略变量 self.bm = BarManager(self.onBar, 1) # 创建K线合成器对象 self.am = ArrayManager() # # time.sleep(5) # ct = VtContractData() # ct.gatewayName = "ONETOKEN" # ct.symbol = 'huobip/btc.usdt' # ct.exchange = 'huobip' # ct.vtSymbol = 'huobip/btc.usdt' # self.ctaEngine.mainEngine.dataEngine.contractDict['huobip/btc.usdt'] = ct # self.ctaEngine.mainEngine.dataEngine.saveContracts() # ctaEngine.subscribe(req, 'ONETOKEN') def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 # initData = self.loadBar(self.initDays) # for bar in initData: # self.onBar(bar) 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) dt = tick.datetime # TODO: 计算spread preSpread = self.spread self.spread = new_spread # 更近spread spread = self.spread price = tick.lastPrice if self.long_enter: # 判断信号 if self.LongSignalSpread + self.MaxTolerate > spread: self.buyOrderIDList.append(self.buy(price, 1)) # 开多 self.count = 0 self.maxdt = dt + datetime.timedelta( minutes=self.maxHold) # 只持仓到那个时间点 self.minExitdt = dt + datetime.timedelta( minutes=0.5) # TODO:半分钟,or不要? else: if self.count == self.Ticks: self.qidan(price, dt, spread, direction='long') self.count = 0 else: self.count += 1 elif self.short_enter: if self.ShortSignalSpread - self.MaxTolerate < spread: self.shortOrderIDList.append(self.short(price, 1)) # 卖空 self.count = 0 self.maxdt = dt + datetime.timedelta(minutes=self.maxHold) self.minExitdt = dt + datetime.timedelta(minutes=0.5) # TODO else: # 经过几个tick后还未达到想要的价格,就弃单 if self.count == self.Ticks: self.qidan(price, dt, spread, direction='short') self.count = 0 else: self.count += 1 elif self.short_exit: if self.count == self.Ticks: self.buyOrderIDList.append(self.cover(price, 1)) # 平空 self.count = 0 if self.stopwinning or self.stopLosing: self.stopping = True self.stoppingdt = dt + datetime.timedelta( minutes=self.stoppPeriods) self.maxdt = None self.minExitdt = None else: self.maxdt = None self.minExitdt = None self.minEnterdt = dt + datetime.timedelta(minutes=0.5) else: self.count += 1 elif self.long_exit: if self.count == self.Ticks: self.shortOrderIDList.append(self.sell(price, 1)) # 平多 self.count = 0 if self.stopwinning or self.stopLosing: self.stopping = True self.stoppingdt = dt + datetime.timedelta( minutes=self.stoppPeriods) self.maxdt = None self.minExitdt = None else: self.maxdt = None self.minExitdt = None self.minEnterdt = dt + datetime.timedelta(minutes=0.5) else: self.count += 1 self.ResetSignal() dtAbove = datetime.datetime.combine(dt.date(), datetime.time(dt.hour, dt.minute)) try: # TODO: 需要计算Std,std是一小时1min_bar的收盘价的std std = self.cal_std() except: std = np.nan # 开空仓信号 if not self.stopping: if self.pos == 0: if dt > self.minEnterdt: # 如果满足最小进场时间 if preSpread: if ((spread - preSpread) > self.minEnterPrice ) or (spread - preSpread) > +self.mutiple * std: self.short_enter = True self.ShortSignalSpread = spread elif ((preSpread - spread) > self.minEnterPrice ) or (preSpread - spread) > self.mutiple * std: self.long_enter = True self.LongSignalSpread = spread else: pass if self.pos == -1: if dt > self.minExitdt: # 如果满足最小进场时间 if dt >= self.maxdt: # 如果超过最大持仓时间 self.short_exit = True self.ShortSignalSpread = spread else: if (self.short_enter_price - spread) > self.maxWin: # 止盈 self.short_exit = True self.stopwinning = True self.ShortSignalSpread = spread elif (spread - self.short_enter_price) > self.minLose: # 止损 self.short_exit = True self.stopLosing = True self.ShortSignalSpread = spread else: pass if self.pos == 1: # 若有仓位 if dt > self.minExitdt: # 若符合最小进场时间 if dt >= self.maxdt: # 若超过最大持仓周期 self.long_exit = True self.LongSignalSpread = spread else: if (spread - self.long_enter_price) > self.maxWin: # 止盈 self.long_exit = True self.stopwinning = True self.LongSignalSpread = spread elif (self.long_enter_price - spread) > self.minLose: # 止损 self.long_exit = True self.stopLosing = True self.LongSignalSpread = spread else: pass else: if dt >= self.stoppingdt: self.stopping = False self.stoppingdt = None def updateTick(self, event): print('-' * 30, 'strategy_updateTick', '-' * 30) def onBar(self, bar): self.bm.updateBar(bar) '''交易后的账户余额或保证金''' def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" # print(order) # self.writeCtaLog(u'委托变化推送: %s' % order) # pass def onTrade(self, trade): if self.pos != 0: # 多头开仓成交后,撤消空头委托 if self.pos > 0: for shortOrderID in self.shortOrderIDList: self.cancelOrder(shortOrderID) # 反之同样 elif self.pos < 0: for buyOrderID in self.buyOrderIDList: self.cancelOrder(buyOrderID) # 移除委托号 for orderID in (self.buyOrderIDList + self.shortOrderIDList): if orderID in self.orderList: self.orderList.remove(orderID) # 发出状态更新事件 self.putEvent() def ResetSignal(self): self.long_enter = False self.long_exit = False self.short_enter = False self.short_exit = False self.stopwinning = False self.stopLosing = False def cal_std(self): pass def getPos(self): """获取cn仓位""" # 0:空仓,1:做多,-1:做空 老版本的,已废除 # fileName = 'CTA_setting.json' # try: # f = file(fileName) # except IOError: # print('读取param参数配置出错,请检查') # # 解析json文件----------------------------------------------------- # mysetting = json.load(f) # if self.pair == 'sc_wti': # cnvtSymbol = str(mysetting[0]['vtSymbol']) # usvtSymbol = str(mysetting[1]['vtSymbol']).split('.')[0] # elif self.pair == 'brent_sc': # cnvtSymbol = str(mysetting[3]['vtSymbol']) # usvtSymbol = str(mysetting[2]['vtSymbol']).split('.')[0] # reqID = self.api.getTrades({'instrument': usvtSymbol}) # cnPosObj = self.banzhuan_query_position(cnvtSymbol) cnPosObj = self.banzhuan_query_position() # 已改为不传参数,待测试是否有效 # print '-------------------------昨仓今仓-------------------------\nlongYd:', cnPosObj.longYd, '\nlongTd:', cnPosObj.longTd, '\nshortYd:', cnPosObj.shortYd, '\nshortTd:', cnPosObj.shortTd # self.longYd = cnPosObj.longYd # vtEngine.py 633行。昨仓今仓分别获取。 # self.longTd = cnPosObj.longTd # self.shortYd = cnPosObj.shortYd # self.shortTd = cnPosObj.shortTd self.r.set('cnpositionlongYd', cnPosObj.longYd) self.r.set('cnpositionlongTd', cnPosObj.longTd) self.r.set('cnpositionshortYd', cnPosObj.shortYd) self.r.set('cnpositionshortTd', cnPosObj.shortTd)
class tick_strategy_cn(CtaTemplate): """结合ATR和RSI指标的一个分钟线交易策略""" className = 'CN' author = u'用Python的交易员' # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'author', 'vtSymbol', 'atrLength', 'fastMaLength', 'slowMaLength', 'rsiLength', 'rsiEntry', 'trailingPercent'] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'atrValue', 'atrMa', 'rsiValue', 'rsiBuy', 'rsiSell'] buyOrderIDList = [] # 委托买入开仓的委托号 shortOrderIDList = [] # 委托卖出开仓的委托号 orderList = [] # 保存委托代码的列表 def __init__(self, ctaEngine, setting): fileName = 'param.json' try: f = file(fileName) except IOError: print('读取param参数配置出错,请检查') # 解析json文件----------------------------------------------------- mysetting = json.load(f) redisHost = str(mysetting['redisHost']) # redisPort = str(mysetting['redisPort']) self.r = redis.Redis(host=redisHost, port=int(redisPort), db=8) # 策略参数 self.contract_size = 100 self.MaxTolerate = 0 self.maxHold = 0 self.Ticks = 4 #追单数量 self.stopping = False self.stoppingdt = None # 止损后最小开仓时间 self.stoppPeriods = 15 # 止损后15分钟不能开仓 self.ShortSignalSpread = None self.LongSignalSpread = None self.short_enter_price = None self.short_exit_price = None self.long_enter_price = None self.long_exit_price = None self.maxHold = 0 self.maxWin = 0 self.minLose = 0 self.mutiple = 0 self.minEnterPrice = 0 self.volume = 0 self.init_asset = 0 self.bm = BarManager(self.onBar, 1) # 创建K线合成器对象 """Constructor""" super(tick_strategy_cn, self).__init__(ctaEngine, setting) # 策略变量 self.bar = None # K线对象 self.bm = BarManager(self.onBar, 1) # 创建K线合成器对象 self.barMinute = EMPTY_STRING # K线当前的分钟 self.bufferSize = 100 # 需要缓存的数据的大小 self.bufferCount = 0 # 目前已经缓存了的数据的计数 self.highArray = np.zeros(self.bufferSize) # K线最高价的数组 self.lowArray = np.zeros(self.bufferSize) # K线最低价的数组 self.closeArray = np.zeros(self.bufferSize) # K线收盘价的数组 self.getPos() # self.longYd = 0 # 这四个是昨仓今仓 # self.longTd = 0 # self.shortYd = 0 # self.shortTd = 0 # self.r.set('sc_wtiusPos', 0) # 初始化仓位 # self.r.set('brent_scusPos', 0) def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 # position = self.ctaEngine.query_position() # print('qry postion: {0}'.format(position)) initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.init_data_loaded = True self.putEvent() def onStart(self): """启动策略(必须由用户继承实现)""" # self.ctaEngine.test() self.writeCtaLog(u'%s策略启动' % self.name) self.putEvent() def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略停止' % self.name) self.putEvent() def getPos(self): """获取cn仓位""" cnPosObj = self.banzhuan_query_position() # ---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" # 过滤异常值 """收到行情TICK推送(必须由用户继承实现)""" self.bm.updateTick(tick) dt = tick.datetime set_data = self.r.get('set_data') if set_data == 'True': us_close = float(self.r.get('us_close')) # TODO: US_CLOSE 没有初始化 self.r.set('set_data', 'False') else: pass ex_rate = self.usdcnhRate() # 获取汇率 spread = tick.lastPrice - ex_rate * us_close # 计算新的价差 preSpread = self.spread # 保存过去的价差 self.spread = spread # 更近价差 price = tick.lastPrice if self.long_enter: # 判断信号 if self.LongSignalSpread + self.MaxTolerate > spread: self.buyOrderIDList.append(self.buy(price, 1)) # 开多 self.count = 0 self.maxdt = dt + datetime.timedelta(minutes=self.maxHold) # 只持仓到那个时间点 self.minExitdt = dt + datetime.timedelta(minutes=0.5) # TODO:半分钟,or不要? else: if self.count == self.Ticks: self.qidan(price, dt, spread, direction='long') # TODO: 经过几个tick后还未达到想要的价格,就弃单 self.count = 0 else: self.count += 1 elif self.short_enter: if self.ShortSignalSpread - self.MaxTolerate < spread: self.shortOrderIDList.append(self.short(price, 1)) # 卖空 self.count = 0 self.maxdt = dt + datetime.timedelta(minutes=self.maxHold) self.minExitdt = dt + datetime.timedelta(minutes=0.5) # TODO else: # 经过几个tick后还未达到想要的价格,就弃单 if self.count == self.Ticks: self.qidan(price, dt, spread, direction='short') self.count = 0 else: self.count += 1 elif self.short_exit: if self.count == self.Ticks: self.buyOrderIDList.append(self.cover_today(price, 1)) # 平今空 self.count = 0 if self.stopwinning or self.stopLosing: self.stopping = True self.stoppingdt = dt + datetime.timedelta(minutes=self.stoppPeriods) self.maxdt = None self.minExitdt = None else: self.maxdt = None self.minExitdt = None self.minEnterdt = dt + datetime.timedelta(minutes=0.5) else: self.count += 1 elif self.long_exit: if self.count == self.Ticks: self.shortOrderIDList.append(self.sell_today(price, 1)) # 平今多 self.count = 0 if self.stopwinning or self.stopLosing: self.stopping = True self.stoppingdt = dt + datetime.timedelta(minutes=self.stoppPeriods) self.maxdt = None self.minExitdt = None else: self.maxdt = None self.minExitdt = None self.minEnterdt = dt + datetime.timedelta(minutes=0.5) else: self.count += 1 self.ResetSignal() dtAbove = datetime.datetime.combine(dt.date(), datetime.time(dt.hour, dt.minute)) try: # TODO: 需要计算Std,std是一小时1min_bar的收盘价的std std = self.cal_std() except: std = np.nan # 开空仓信号 if not self.stopping: if self.pos == 0: if dt > self.minEnterdt: # 如果满足最小进场时间 if preSpread: if ((spread - preSpread) > self.minEnterPrice) or (spread - preSpread) > + self.mutiple * std: self.short_enter = True self.ShortSignalSpread = spread elif ((preSpread - spread) > self.minEnterPrice) or (preSpread - spread) > self.mutiple * std: self.long_enter = True self.LongSignalSpread = spread else: pass if self.pos == -1: if dt > self.minExitdt: # 如果满足最小进场时间 if dt >= self.maxdt: # 如果超过最大持仓时间 self.short_exit = True self.ShortSignalSpread = spread else: if (self.short_enter_price - spread) > self.maxWin: # 止盈 self.short_exit = True self.stopwinning = True self.ShortSignalSpread = spread elif (spread - self.short_enter_price) > self.minLose: # 止损 self.short_exit = True self.stopLosing = True self.ShortSignalSpread = spread else: pass if self.pos == 1: # 若有仓位 if dt > self.minExitdt: # 若符合最小进场时间 if dt >= self.maxdt: # 若超过最大持仓周期 self.long_exit = True self.LongSignalSpread = spread else: if (spread - self.long_enter_price) > self.maxWin: # 止盈 self.long_exit = True self.stopwinning = True self.LongSignalSpread = spread elif (self.long_enter_price - spread) > self.minLose: # 止损 self.long_exit = True self.stopLosing = True self.LongSignalSpread = spread else: pass else: if dt >= self.stoppingdt: self.stopping = False self.stoppingdt = None # ---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" pass # ---------------------------------------------------------------------- def onXminBar(self, bar): """交易后的账户余额或保证金""" pass def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" # print(order) # self.writeCtaLog(u'委托变化推送: %s' % order) pass def onTrade(self, trade): # print('%s %s, price:%s, volume:%.4f, capital:%.2f' %(trade.dt,trade.direction, trade.price, trade.volume,trade.price * trade.volume)) # self.writeCtaLog(u'成交信息推送: %s' % trade) # 发出状态更新事件 self.putEvent() def usdcnhRate(self): url = 'http://webforex.hermes.hexun.com/forex/quotelist?code=FOREXUSDCNH&column=Code,Price' r = GET(url) data = json.loads(r[1:-2]) rate = float(data['Data'][0][0][1]) / 10000.0 # print '------------------rate---------------\n',rate self.r.set('usdcnhRate', rate) def ResetSignal(self): self.long_enter = False self.long_exit = False self.short_enter = False self.short_exit = False self.stopwinning = False self.stopLosing = False
class DoubleMaStrategy(CtaTemplate): """双指数均线策略Demo""" className = 'DoubleMaStrategy' author = u'用Python的交易员' # 策略参数 fastWindow = 10 # 快速均线参数 slowWindow = 60 # 慢速均线参数 initDays = 10 # 初始化数据所用的天数 # 策略变量 fastMa0 = EMPTY_FLOAT # 当前最新的快速EMA fastMa1 = EMPTY_FLOAT # 上一根的快速EMA slowMa0 = EMPTY_FLOAT slowMa1 = EMPTY_FLOAT # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'author', 'vtSymbol', 'fastWindow', 'slowWindow'] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'fastMa0', 'fastMa1', 'slowMa0', 'slowMa1'] # 同步列表,保存了需要保存到数据库的变量名称 syncList = ['pos'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(DoubleMaStrategy, self).__init__(ctaEngine, setting) self.bm = BarManager(self.onBar) self.am = ArrayManager() # 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建, # 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险, # 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读 # 策略时方便(更多是个编程习惯的选择) #---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'双EMA演示策略初始化') initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.putEvent() #---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog(u'双EMA演示策略启动') self.putEvent() #---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'双EMA演示策略停止') self.putEvent() #---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.bm.updateTick(tick) #---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" am = self.am am.updateBar(bar) if not am.inited: return # 计算快慢均线 fastMa = am.sma(self.fastWindow, array=True) self.fastMa0 = fastMa[-1] self.fastMa1 = fastMa[-2] slowMa = am.sma(self.slowWindow, array=True) self.slowMa0 = slowMa[-1] self.slowMa1 = slowMa[-2] # 判断买卖 crossOver = self.fastMa0>self.slowMa0 and self.fastMa1<self.slowMa1 # 金叉上穿 crossBelow = self.fastMa0<self.slowMa0 and self.fastMa1>self.slowMa1 # 死叉下穿 # 金叉和死叉的条件是互斥 # 所有的委托均以K线收盘价委托(这里有一个实盘中无法成交的风险,考虑添加对模拟市价单类型的支持) if crossOver: # 如果金叉时手头没有持仓,则直接做多 if self.pos == 0: self.buy(bar.close, 1) # 如果有空头持仓,则先平空,再做多 elif self.pos < 0: self.cover(bar.close, 1) self.buy(bar.close, 1) # 死叉和金叉相反 elif crossBelow: if self.pos == 0: self.short(bar.close, 1) elif self.pos > 0: self.sell(bar.close, 1) self.short(bar.close, 1) # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" # 对于无需做细粒度委托控制的策略,可以忽略onOrder pass #---------------------------------------------------------------------- def onTrade(self, trade): """收到成交推送(必须由用户继承实现)""" # 对于无需做细粒度委托控制的策略,可以忽略onOrder pass #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class BollChannelStrategy(CtaTemplate): """基于布林通道的交易策略""" className = 'BollChannelStrategy' author = u'用Python的交易员' # 策略参数 bollWindow = 18 # 布林通道窗口数 bollDev = 3.4 # 布林通道的偏差 cciWindow = 10 # CCI窗口数 atrWindow = 30 # ATR窗口数 slMultiplier = 5.2 # 计算止损距离的乘数 initDays = 10 # 初始化数据所用的天数 fixedSize = 1 # 每次交易的数量 # 策略变量 bollUp = 0 # 布林通道上轨 bollDown = 0 # 布林通道下轨 cciValue = 0 # CCI指标数值 atrValue = 0 # ATR指标数值 intraTradeHigh = 0 # 持仓期内的最高点 intraTradeLow = 0 # 持仓期内的最低点 longStop = 0 # 多头止损 shortStop = 0 # 空头止损 # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'author', 'vtSymbol', 'bollWindow', 'bollDev', 'cciWindow', 'atrWindow', 'slMultiplier', 'initDays', 'fixedSize'] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'bollUp', 'bollDown', 'cciValue', 'atrValue', 'intraTradeHigh', 'intraTradeLow', 'longStop', 'shortStop'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(BollChannelStrategy, self).__init__(ctaEngine, setting) self.bm = BarManager(self.onBar, 15, self.onXminBar) # 创建K线合成器对象 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 onXminBar(self, bar): """收到X分钟K线""" # 全撤之前发出的委托 self.cancelAll() # 保存K线数据 am = self.am am.updateBar(bar) if not am.inited: return # 计算指标数值 self.bollUp, self.bollDown = am.boll(self.bollWindow, self.bollDev) self.cciValue = am.cci(self.cciWindow) self.atrValue = am.atr(self.atrWindow) # 判断是否要进行交易 # 当前无仓位,发送开仓委托 if self.pos == 0: self.intraTradeHigh = bar.high self.intraTradeLow = bar.low if self.cciValue > 0: self.buy(self.bollUp, self.fixedSize, True) elif self.cciValue < 0: self.short(self.bollDown, self.fixedSize, True) # 持有多头仓位 elif 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) # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass #---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class DualThrustStrategy(CtaTemplate): """DualThrust交易策略""" className = 'DualThrustStrategy' author = u'用Python的交易员' # 策略参数 fixedSize = 100 k1 = 0.4 k2 = 0.6 initDays = 10 # 策略变量 barList = [] # K线对象的列表 dayOpen = 0 dayHigh = 0 dayLow = 0 range = 0 longEntry = 0 shortEntry = 0 exitTime = time(hour=14, minute=55) longEntered = False shortEntered = False # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'author', 'vtSymbol', 'k1', 'k2'] # 变量列表,保存了变量的名称 varList = [ 'inited', 'trading', 'pos', 'range', 'longEntry', 'shortEntry', 'exitTime' ] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(DualThrustStrategy, self).__init__(ctaEngine, setting) self.bm = BarManager(self.onBar) self.barList = [] #---------------------------------------------------------------------- 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.cancelAll() # 计算指标数值 self.barList.append(bar) if len(self.barList) <= 2: return else: self.barList.pop(0) lastBar = self.barList[-2] # 新的一天 if lastBar.datetime.date() != bar.datetime.date(): # 如果已经初始化 if self.dayHigh: self.range = self.dayHigh - self.dayLow self.longEntry = bar.open + self.k1 * self.range self.shortEntry = bar.open - self.k2 * self.range self.dayOpen = bar.open self.dayHigh = bar.high self.dayLow = bar.low self.longEntered = False self.shortEntered = False else: self.dayHigh = max(self.dayHigh, bar.high) self.dayLow = min(self.dayLow, bar.low) # 尚未到收盘 if not self.range: return if bar.datetime.time() < self.exitTime: if self.pos == 0: if bar.close > self.dayOpen: if not self.longEntered: self.buy(self.longEntry, self.fixedSize, stop=True) else: if not self.shortEntered: self.short(self.shortEntry, self.fixedSize, stop=True) # 持有多头仓位 elif self.pos > 0: self.longEntered = True # 多头止损单 self.sell(self.shortEntry, self.fixedSize, stop=True) # 空头开仓单 if not self.shortEntered: self.short(self.shortEntry, self.fixedSize, stop=True) # 持有空头仓位 elif self.pos < 0: self.shortEntered = True # 空头止损单 self.cover(self.longEntry, self.fixedSize, stop=True) # 多头开仓单 if not self.longEntered: self.buy(self.longEntry, self.fixedSize, stop=True) # 收盘平仓 else: if self.pos > 0: self.sell(bar.close * 0.99, abs(self.pos)) elif self.pos < 0: self.cover(bar.close * 1.01, abs(self.pos)) # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass #---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class BollChannelStrategy(CtaTemplate): """基于布林通道的交易策略""" className = 'BollChannelStrategy' author = u'用Python的交易员' # 策略参数 bollWindow = 18 # 布林通道窗口数 bollDev = 3.4 # 布林通道的偏差 cciWindow = 10 # CCI窗口数 atrWindow = 30 # ATR窗口数 slMultiplier = 5.2 # 计算止损距离的乘数 initDays = 10 # 初始化数据所用的天数 fixedSize = 1 # 每次交易的数量 # 策略变量 bollUp = 0 # 布林通道上轨 bollDown = 0 # 布林通道下轨 cciValue = 0 # CCI指标数值 atrValue = 0 # ATR指标数值 intraTradeHigh = 0 # 持仓期内的最高点 intraTradeLow = 0 # 持仓期内的最低点 longStop = 0 # 多头止损 shortStop = 0 # 空头止损 # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'author', 'vtSymbol', 'bollWindow', 'bollDev', 'cciWindow', 'atrWindow', 'slMultiplier', 'initDays', 'fixedSize'] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'bollUp', 'bollDown', 'cciValue', 'atrValue', 'intraTradeHigh', 'intraTradeLow', 'longStop', 'shortStop'] # 同步列表,保存了需要保存到数据库的变量名称 syncList = ['pos', 'intraTradeHigh', 'intraTradeLow'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(BollChannelStrategy, self).__init__(ctaEngine, setting) self.bm = BarManager(self.onBar, 15, self.onXminBar) # 创建K线合成器对象 self.bm30 = BarManager(self.onBar, 30, self.on30minBar) self.am = ArrayManager() #---------------------------------------------------------------------- def on30minBar(self, bar): """""" #---------------------------------------------------------------------- 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 onXminBar(self, bar): """收到X分钟K线""" # 全撤之前发出的委托 self.cancelAll() # 保存K线数据 am = self.am am.updateBar(bar) if not am.inited: return # 计算指标数值 self.bollUp, self.bollDown = am.boll(self.bollWindow, self.bollDev) self.cciValue = am.cci(self.cciWindow) self.atrValue = am.atr(self.atrWindow) # 判断是否要进行交易 # 当前无仓位,发送开仓委托 if self.pos == 0: self.intraTradeHigh = bar.high self.intraTradeLow = bar.low if self.cciValue > 0: self.buy(self.bollUp, self.fixedSize, True) elif self.cciValue < 0: self.short(self.bollDown, self.fixedSize, True) # 持有多头仓位 elif 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) # 同步数据到数据库 self.saveSyncData() # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass #---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class BarMStrategy(CtaTemplate): """多周期策略""" className = 'BarMStrategy' author = u'toriphy' # 策略参数 kkLength = 15 # 计算通道中值的窗口数 kkDevUp = 2.2 # 计算通道宽度的偏差 取2.1或者2.2比较好 kkDevDown = 1.9 # 初始值1.9 trailingPrcnt = 1.1 # 移动止损, 初始值1.2 thresholdRatio = 0.15 # 持仓量指标阈值 initDays = 10 # 初始化数据所用的天数,注意这个值是天数而不是bar的个数 fixedSize = 1 # 每次交易的数量 barBin = 5 # 五分钟线 短周期 barLongBin = 15 # 十五分钟线,长周期 shortMAperiod = 6 longMAperiod = 12 bufferSize = 100 # 需要缓存的数据的大小 65 longCycleBufferSize = 30 # 长周期需要缓存的数据大小 20 bufferCount = 0 # 目前已经缓存了的数据的计数 longCycleBufferCount = 0 # 长周期目前已经缓存了的数据的计数 longCycleTradingFlag = 0 # 长周期交易信号 atrValue = 0 # 最新的ATR指标数值 kkMid = 0 # KK通道中轨 kkUp = 0 # KK通道上轨 kkDown = 0 # KK通道下轨 openRatioModi = 0 # 开仓指标调整 intraTradeHigh = 0 # 持仓期内的最高点 intraTradeLow = 0 # 持仓期内的最低点 longStop = 0 # 多头的移动止损点位 shortStop = 0 # 空头的移动止损点位 openRatioModiArray = np.zeros(bufferSize) longCycleLLTArrayShort = np.zeros(longCycleBufferSize) # 短周期部分 ,alpha # 其他不相关的 buyOrderID = None # OCO委托买入开仓的委托号 shortOrderID = None # OCO委托卖出开仓的委托号 orderList = [] # 保存委托代码的列表 # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'kkLength', 'kkDevUp', 'kkDevDown', 'thresholdRatio', 'trailingPrcnt' ] # 变量列表,保存了变量的名称 varList = [ 'inited', 'trading', 'pos', 'kkMid', 'kkUp', 'kkDown', 'barOpenRatioModi', 'longStop', 'shortStop', 'longCycleTradingFlag' ] # 同步列表,保存了需要保存到数据库的变量名称 syncList = ['pos', 'longStop', 'shortStop'] # 持仓数据和trailing stop 是一定要保存的 # ---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(BarMStrategy, self).__init__(ctaEngine, setting) # 创建K线合成器对象 self.bm = BarManager(self.onBar) # 1分钟线(因为要调取1分钟线的持仓量和成交量信息) self.am = ArrayManager() self.bm5 = BarManager(self.onBar, self.barBin, self.on5MinBar) self.am5 = ArrayManager() self.bm15 = BarManager(self.onBar, self.barLongBin, self.on15MinBar) self.am15 = ArrayManager(size=self.longCycleBufferSize) # ---------------------------------------------------------------------- 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推送(必须由用户继承实现)""" # 基于15分钟判断趋势过滤,因此先更新 self.am.updateBar(bar) self.vArray1min = self.am.volume[-5:] self.oArray1min = self.am.openInterest[-6:] self.bm15.updateBar(bar) # 基于5分钟判断 self.bm5.updateBar(bar) # ---------------------------------------------------------------------- def on5MinBar(self, bar): """收到5分钟K线""" self.cancelAll() # 保存K线数据 self.am5.updateBar(bar) barOpenRatioModi = ((np.sqrt(self.vArray1min) / np.sqrt(self.vArray1min).sum()) * ((self.oArray1min[1:] - \ self.oArray1min[:-1]) / self.vArray1min)).mean() self.openRatioModiArray[0:self.bufferSize - 1] = self.openRatioModiArray[1:self.bufferSize] self.openRatioModiArray[-1] = barOpenRatioModi # 开仓比例 self.bufferCount += 1 if self.bufferCount < self.bufferSize: return # 计算指标数值 self.atrValue = talib.ATR(self.am5.high, self.am5.low, self.am5.close, self.kkLength)[-1] self.kkMid = talib.MA(self.am5.close, self.kkLength)[-1] self.kkUp = self.kkMid + self.atrValue * self.kkDevUp self.kkDown = self.kkMid - self.atrValue * self.kkDevDown self.openRatioModi = self.openRatioModiArray[-1] # 开仓量指标 conditionKKBuy = self.am5.close[-1] > self.kkUp conditionKKSell = self.am5.close[-1] < self.kkDown conditionOpenRatioModiBuy = self.openRatioModi > 0.022 conditionOpenRatioModiSell = self.openRatioModi > 0.026 # 最好0.026 # 当前无仓位, if self.pos == 0: self.intraTradeHigh = bar.high self.intraTradeLow = bar.low if conditionKKBuy and conditionOpenRatioModiBuy and self.longCycleTradingFlag == 1: self.buy(bar.close + 5, self.fixedSize) elif conditionKKSell and conditionOpenRatioModiSell and self.longCycleTradingFlag == -1: self.short(bar.close - 5, self.fixedSize) # 持有多头仓位 elif self.pos > 0: self.intraTradeHigh = max(self.intraTradeHigh, bar.high) self.intraTradeLow = bar.low self.longStop = self.intraTradeHigh * (1 - self.trailingPrcnt / 100) orderID = self.sell(self.longStop, abs(self.pos), stop=True) self.writeCtaLog(u'多头止损价格:' + str(self.longStop)) self.orderList.append(orderID) # 持有空头仓位 elif self.pos < 0: self.intraTradeHigh = bar.high self.intraTradeLow = min(self.intraTradeLow, bar.low) self.shortStop = self.intraTradeLow * (1 + self.trailingPrcnt / 100) orderID = self.cover(self.shortStop, abs(self.pos), stop=True) self.writeCtaLog(u'空头头止损价格:' + str(self.shortStop)) self.orderList.append(orderID) # 发出状态更新事件 self.putEvent() # ---------------------------------------------------------------------- def on15MinBar(self, bar): """15分钟K线推送""" #print 'cycletime:', bar.datetime, self.longCycleTradingFlag self.am15.updateBar(bar) alpha = 0.3 # 5分钟线取0.3最佳 alphatilde = 2 / (12 + 1) LLTShort = (alpha - (alpha ** 2) / 4) * self.am15.close[-1] + (alpha ** 2) / 2 * \ self.am15.close[-2] - \ (alpha - 3 * alpha ** 2 / 4) * self.am15.close[-3] + 2 * (1 - alpha) * \ self.longCycleLLTArrayShort[-1] - (1 - alpha ** 2) * self.longCycleLLTArrayShort[-2] self.longCycleLLTArrayShort[0:self.longCycleBufferSize - 1] = self.longCycleLLTArrayShort[ 1:self.longCycleBufferSize] self.longCycleLLTArrayShort[-1] = LLTShort #print self.am15.close[-10:],"\n","LLT:", LLTShort self.longCycleBufferCount += 1 if self.longCycleBufferCount < self.longCycleBufferSize: return longCycleMAlong = talib.MA(self.am15.close, self.longMAperiod) longCycleMAshort = talib.MA(self.am15.close, self.shortMAperiod) maLongCondition = longCycleMAshort[-1] > longCycleMAlong[-1] lltLongCondition = self.longCycleLLTArrayShort[ -1] > self.longCycleLLTArrayShort[-2] lltShortCondition = self.longCycleLLTArrayShort[ -1] < self.longCycleLLTArrayShort[-2] if maLongCondition: self.longCycleTradingFlag = 1 elif lltShortCondition: self.longCycleTradingFlag = -1 else: self.longCycleTradingFlag = 0 # ---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass # ---------------------------------------------------------------------- def onTrade(self, trade): """发出状态更新事件""" self.putEvent() # ---------------------------------------------------------------------- def sendOcoOrder(self, buyPrice, shortPrice, volume): """ 发送OCO委托 OCO(One Cancel Other)委托: 1. 主要用于实现区间突破入场 2. 包含两个方向相反的停止单 3. 一个方向的停止单成交后会立即撤消另一个方向的 """ # 发送双边的停止单委托,并记录委托号 self.buyOrderID = self.buy(buyPrice, volume, True) self.shortOrderID = self.short(shortPrice, volume, True) # 将委托号记录到列表中 self.orderList.append(self.buyOrderID) self.orderList.append(self.shortOrderID)
class AppleStartStrategy(CtaTemplate): """苹果期货新上市策略""" className = 'AppleStartStrategy' author = '中融致信投资技术部' # 策略参数 # 3900成交价格 initDays = 1 # 数据初始化天数 open_pos_time = datetime.time(hour=9, minute=1, second=0) # 开仓时间 stop_open_pos_time = datetime.time(hour=14, minute=54, second=0) # 停止开仓时间 close_pos_time = datetime.time(hour=14, minute=58, second=0) # 清仓时间 fixedSize = 1 # 每次交易的数量 # faxing_price = 7800.00 # 苹果发行价格 # faxing_price = 3801.00 # 螺纹结算价格 open_slip = 3 close_slip = 10 # ---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(AppleStartStrategy, self).__init__(ctaEngine, setting) self.bm = BarManager(self.onBar) # 创建K线合成器对象 self.am = ArrayManager(size=100) self.pre_zhongxin = None # 上一个bar的重心 # self.zhangting_price = round(self.faxing_price * 1.1, 2) # 涨停价 # self.dieting_price = round(self.faxing_price * 0.9, 2) # 跌停价 # ---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog('%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 # initData = self.loadBar(self.initDays) # for bar in initData: # self.onBar(bar) self.putEvent() #---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog('%s策略启动' % self.name) self.putEvent() #---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog('%s策略停止' % self.name) self.putEvent() #---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.bm.updateTick(tick) def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" # 保存K线数据 am = self.am am.updateBar(bar) # 如果k先还没有初始化完成,就不执行 if not am.inited: return # 先撤销之前没有成交的单子 self.cancelAll() # 获取当前时间 time_now = bar.datetime.time() # 收集计算数据 zhongxin = (bar.open + bar.high + bar.low + bar.close) / 4 # 重心 # 第一个bar先略过 if self.pre_zhongxin is None: self.pre_zhongxin = zhongxin return # 开仓时间 if time_now >= self.open_pos_time and time_now < self.stop_open_pos_time: # 判断该做空还是做多 trend = 0 # 趋势,-1 空, 0 无趋势, 1 多 if zhongxin > self.pre_zhongxin and bar.close > zhongxin: trend = 1 elif zhongxin < self.pre_zhongxin and bar.close < zhongxin: trend = -1 if self.pos == 0: # 空仓趋势多头直接开多 if trend == 1: self.buy(price=bar.close + self.open_slip, volume=self.fixedSize) # 空仓趋势空头直接开空 elif trend == -1: self.short(price=bar.close - self.open_slip, volume=self.fixedSize) # 持有多投仓位 elif self.pos > 0: # 趋势反转,反手做空 if trend == -1: self.sell(price=bar.close - self.close_slip, volume=self.fixedSize) self.short(price=bar.close - self.open_slip, volume=self.fixedSize) # 持有空头仓位 elif self.pos < 0: # 趋势反转,反手做多 if trend == 1: self.cover(price=bar.close + self.close_slip, volume=self.fixedSize) self.buy(price=bar.close + self.open_slip, volume=self.fixedSize) # 尾盘强制平仓 if time_now >= self.close_pos_time: if self.pos != 0: self.closeAllPosition(bar) # 为下一个bar数据做准备 self.pre_zhongxin = zhongxin def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass def onTrade(self, trade): """收到交易发生事件推送""" pass def onStopOrder(self, so): """收到停止单事件推送""" self.putEvent() def closeAllPosition(self, bar): """平掉所有仓位""" self.cancelAll() if self.pos > 0: self.sell(price=bar.close - self.close_slip, volume=self.fixedSize) elif self.pos < 0: self.cover(price=bar.close + self.close_slip, volume=self.fixedSize)
class tick_strategy_cn(CtaTemplate): """结合ATR和RSI指标的一个分钟线交易策略""" className = 'CN' author = u'Adam Zhang' # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'author', 'vtSymbol', 'atrLength', 'fastMaLength', 'slowMaLength', 'rsiLength', 'rsiEntry', 'trailingPercent'] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'atrValue', 'atrMa', 'rsiValue', 'rsiBuy', 'rsiSell'] def __init__(self, ctaEngine, setting): fileName = 'param.json' try: f = file(fileName) except IOError: print('读取param参数配置出错,请检查') # 解析json文件----------------------------------------------------- mysetting = json.load(f) redisHost = str(mysetting['redisHost']) # redisPort = str(mysetting['redisPort']) self.r = redis.Redis(host=redisHost, port=int(redisPort), db=8) # 策略参数 self.bm = BarManager(self.onBar, 1) # 创建K线合成器对象 """Constructor""" super(tick_strategy_cn, self).__init__(ctaEngine, setting) # 策略变量 self.bm = BarManager(self.onBar, 1) # 创建K线合成器对象 # 订阅合约 zls添加IB使用 req = VtSubscribeReq() self.symbol = 'USD.CNH' self.exchange = "IDEALPRO" # self.currency = '' self.productClass = "CASH" req.symbol = self.symbol req.exchange = self.exchange req.currency = self.currency req.productClass = self.productClass # time.sleep(5) ctaEngine.subscribe(req, 'IB') def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 # position = self.ctaEngine.query_position() # print('qry postion: {0}'.format(position)) initData = self.loadBar(self.initDays) for bar in initData: self.onBar(bar) self.init_data_loaded = True self.putEvent() def onStart(self): """启动策略(必须由用户继承实现)""" # self.ctaEngine.test() self.writeCtaLog(u'%s策略启动' % self.name) self.putEvent() def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略停止' % self.name) self.putEvent() def getPos(self): """获取cn仓位""" cnPosObj = self.banzhuan_query_position() # ---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" # 过滤异常值 """收到行情TICK推送(必须由用户继承实现)""" self.bm.updateTick(tick) # ---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" self.r.set('close', str(bar.close)) self.r.set('set_data', 'True') # ---------------------------------------------------------------------- def onXminBar(self, bar): """交易后的账户余额或保证金""" pass def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" # print(order) # self.writeCtaLog(u'委托变化推送: %s' % order) pass def onTrade(self, trade): # print('%s %s, price:%s, volume:%.4f, capital:%.2f' %(trade.dt,trade.direction, trade.price, trade.volume,trade.price * trade.volume)) # self.writeCtaLog(u'成交信息推送: %s' % trade) # 发出状态更新事件 self.putEvent()
class AtrRsiStrategy(CtaTemplate): """结合ATR和RSI指标的一个分钟线交易策略""" className = 'AtrRsiStrategy' author = u'用Python的交易员' # 策略参数 atrLength = 22 # 计算ATR指标的窗口数 atrMaLength = 10 # 计算ATR均线的窗口数 rsiLength = 5 # 计算RSI的窗口数 rsiEntry = 16 # RSI的开仓信号 trailingPercent = 0.8 # 百分比移动止损 initDays = 10 # 初始化数据所用的天数 fixedSize = 1 # 每次交易的数量 # 策略变量 atrValue = 0 # 最新的ATR指标数值 atrMa = 0 # ATR移动平均的数值 rsiValue = 0 # RSI指标的数值 rsiBuy = 0 # RSI买开阈值 rsiSell = 0 # RSI卖开阈值 intraTradeHigh = 0 # 移动止损用的持仓期内最高价 intraTradeLow = 0 # 移动止损用的持仓期内最低价 # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'atrLength', 'atrMaLength', 'rsiLength', 'rsiEntry', 'trailingPercent' ] # 变量列表,保存了变量的名称 varList = [ 'inited', 'trading', 'pos', 'atrValue', 'atrMa', 'rsiValue', 'rsiBuy', 'rsiSell' ] # 同步列表,保存了需要保存到数据库的变量名称 syncList = ['pos', 'intraTradeHigh', 'intraTradeLow'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(AtrRsiStrategy, self).__init__(ctaEngine, setting) # 创建K线合成器对象 self.bm = BarManager(self.onBar) self.am = ArrayManager() # 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建, # 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险, # 策略类中的这些可变对象属性可以选择不写,全都放在__init__下面,写主要是为了阅读 # 策略时方便(更多是个编程习惯的选择) #---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog(u'%s策略初始化' % self.name) # 初始化RSI入场阈值 self.rsiBuy = 50 + self.rsiEntry self.rsiSell = 50 - self.rsiEntry # 载入历史数据,并采用回放计算的方式初始化策略数值 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.cancelAll() # 保存K线数据 am = self.am am.updateBar(bar) if not am.inited: return # 计算指标数值 atrArray = am.atr(self.atrLength, array=True) self.atrValue = atrArray[-1] self.atrMa = atrArray[-self.atrMaLength:].mean() self.rsiValue = am.rsi(self.rsiLength) # 判断是否要进行交易 # 当前无仓位 if self.pos == 0: self.intraTradeHigh = bar.high self.intraTradeLow = bar.low # ATR数值上穿其移动平均线,说明行情短期内波动加大 # 即处于趋势的概率较大,适合CTA开仓 if self.atrValue > self.atrMa: # 使用RSI指标的趋势行情时,会在超买超卖区钝化特征,作为开仓信号 if self.rsiValue > self.rsiBuy: # 这里为了保证成交,选择超价5个整指数点下单 self.buy(bar.close + 5, self.fixedSize) elif self.rsiValue < self.rsiSell: self.short(bar.close - 5, self.fixedSize) # 持有多头仓位 elif self.pos > 0: # 计算多头持有期内的最高价,以及重置最低价 self.intraTradeHigh = max(self.intraTradeHigh, bar.high) self.intraTradeLow = bar.low # 计算多头移动止损 longStop = self.intraTradeHigh * (1 - self.trailingPercent / 100) # 发出本地止损委托 self.sell(longStop, abs(self.pos), stop=True) # 持有空头仓位 elif self.pos < 0: self.intraTradeLow = min(self.intraTradeLow, bar.low) self.intraTradeHigh = bar.high shortStop = self.intraTradeLow * (1 + self.trailingPercent / 100) self.cover(shortStop, abs(self.pos), stop=True) # 同步数据到数据库 self.saveSyncData() # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass #---------------------------------------------------------------------- def onTrade(self, trade): # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class DualThrustStrategyZR15(CtaTemplate): """DualThrust策略""" className = "DualThrustStrategyZR15" autor = "张英杰" # 策略参数 initDays = 30 # 数据初始化天数 X1 = 1.3 X2 = 1.5 fixedSize = 1 # 每次交易数量 open_time = datetime.time(hour=9, minute=15, second=0) # 开仓开始时间 close_time = datetime.time(hour=15, minute=0, second=0) # 开仓结束时间 # 参数列表,保存了参数的名称 paramList = ['name', 'className', 'autor', 'vtSymbol', ] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', ] def __init__(self, ctaEngine, setting): """Constructor""" super(DualThrustStrategyZR15, self).__init__(ctaEngine, setting) # 创建bar管理器(K线合成对象),用于合成bar和处理自定义周期的bar回调函数 self.bm = BarManager(onBar=self.onBar, xmin=15, onXminBar=self.onFifteenBar) # 创建k线序列管理工具 self.am = ArrayManager2(size=300) self.dam = DailyArrayManager() # 创建变量 # self.NN = None # 昨天离今天的k线个数,即目前为今天的第几根bar,文华需要,nvpy不需要 self.HH1 = None # 昨天所有bar的收盘最高价 self.LL1 = None # 昨天所有bar的收盘价最低价 self.CC1 = None # 昨天收盘价 self.HH2 = None # 前天所有bar最高收盘价 self.LL2 = None # 前天所有bar最低收盘价 self.CC2 = None # 前天收盘价 self.RANGE0 = None # 这两天的波幅 self.RANGE1 = None # self.YJS = None # 昨天的结算价 self.DTC = None # 根据昨天计算价判断今天是否会有跌停和涨停的风险 self.OO1 = None # 今天的开盘价 self.MN1 = None # 中轴价 偏向于趋势 self.UBUY = None # 追买中轴线 self.DSELL = None # 追卖中轴线 self.USELL = None # 卖出中轴线 self.DBUY = None # 做多中轴线 self.USELL1 = None # 卖出中轴线 self.DBUY1 = None # 做多中轴线 self.DGKX = np.zeros(68*3) self.DGKX_count = 0 self.SIZEK = None self.ZS = None self.KK = None self.now_date = None # 当前日期 self.pre_date = None # 上个交易日日期 self.now_time = None # 当前时间 self.last_trade_price = None # 最后成交价格 self.intraTradeHigh = None # 持有期内最高价 self.intraTradeLow = None # 持有期内最低价 # 为了计算DGKX 和 SIZEK def onInit(self): """初始化策略,必须由用户继承实现""" self.writeCtaLog("%s初始化策略" % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 initData = self.loadBar(days=self.initDays) # 预处理初始化的bar for bar in initData: self.onBar(bar) # 发出策略状态变化事件 self.putEvent() def onStart(self): '''启动策略(必须由用户继承实现)''' self.writeCtaLog("%s策略启动" % self.name) # 发出策略状态变化事件 self.putEvent() # 目前的结论是回测时候该方法为pass,实盘通常用于通知界面更新 def onStop(self): '''停止策略(必须由用户继承实现)''' self.writeCtaLog("%s策略停止" % self.name) # 发出策略状态变化事件 self.putEvent() def onTick(self, tick): '''收到TICK推送,必须由用户继承实现''' # 更新tick,合成k线 self.bm.updateTick(tick) def onBar(self, bar): """收到bar推送(必须由用户继承实现)""" self.bm.updateBar(bar) # 一分钟一个bar,执行周期大于1分钟的策略在自定义的执行方法里,到时间了由bm.updataBar回调执行 def onFifteenBar(self, bar): """收到5分钟bar推送""" # 保存K线数据 am = self.am am.updateBar(bar) # 保存日K数据 dam = self.dam dam.updateBar(bar) self.now_time = bar.datetime.time() # 初始化 if self.now_date is None: self.now_date = bar.date return # 日期改变 elif self.now_date != bar.date: self.pre_date = self.now_date self.now_date = bar.date # 计算变量 # 计算昨天、前天所有bar最高、最低收盘价,昨天结算价 self.HH2 = self.HH1 self.LL2 = self.LL1 self.CC2 = self.CC1 self.HH1 = am.close[-2] self.LL1 = am.close[-2] self.CC1 = am.close[-2] i = -3 while am.date[i] == self.pre_date: if am.close[i] > self.HH1: self.HH1 = am.close[i] if am.close[i] < self.LL1: self.LL1 = am.close[i] i -= 1 # 计算这两天的波幅 if self.HH1 is not None and self.HH2 is not None: self.RANGE0 = (((self.HH1 - self.LL1) * 0.65 + (self.HH2 - self.LL2) * 0.35) / am.sma(68 * 2, array=True)[-2]) * 100 self.RANGE1 = 6 if self.RANGE0 > 6 else self.RANGE0 # 昨天的结算价 tmp_sum = 0. volume_sum = 0. for i in range(-2, -2 - 15, -1): tmp_sum += self.am.close[i] * self.am.volume[i] volume_sum += self.am.volume[i] self.YJS = tmp_sum / volume_sum # 获取今日开盘价 self.OO1 = bar.open # 数据足以支持计算DGKX if am.count >= 68 * 2: self.DGKX[0: self.DGKX.size-1] = self.DGKX[1: self.DGKX.size] if abs(bar.high - bar.low) / bar.close * 10000 < 4: self.DGKX[-1] = talib.SMA(abs(am.close-am.open), 68*2)[-1] else: self.DGKX[-1] = abs(bar.close - bar.open) self.DGKX_count += 1 # 数据足以支持计算SIZEK if self.DGKX_count >= 68 * 3: self.SIZEK = talib.SMA(self.DGKX, 68*3)[-1] / talib.SMA(self.am.close, 68*3)[-1] * 1000 self.ZS = (self.SIZEK ** 0.5) * 2 self.KK = abs(bar.close - bar.open) / bar.open < 0.006 # 如果k线还没有初始化完成,就不执行 if not am.inited: return # 如果日k线还没有初始化完成,就不执行 if not dam.inited: return # # if bar.date == "20171215": # print(1) # 根据昨日计算价判断是否有涨停和跌停风险 self.DTC = bar.close > self.YJS * (1 - 0.085) and bar.close < self.YJS * (1 + 0.085) self.MN1 = (self.OO1 + (self.HH1 + self.LL1 + self.CC1) / 3) / 2 # 中轴价,偏向于趋势 self.UBUY = self.MN1 * (1 + self.X1 * self.RANGE1 / 100) # 追买中轴线 self.DSELL = self.MN1 * (1 - self.X2 * self.RANGE1 / 100) # 追买中轴线 self.USELL = self.MN1 * (1 + 1.3 * self.RANGE1 / 100) # 卖出中轴线 self.DBUY = self.MN1 * (1 - 1.6 * self.RANGE1 / 100) # 做多中轴线 self.USELL1 = self.USELL * (1 + 0.2 * self.RANGE1 / 100) # 卖出中轴线 self.DBUY1 = self.DBUY * (1 - 0.2 * self.RANGE1 / 100) # 做多中轴线 # 开仓时间 if self.pos == 0: self.intraTradeHigh = bar.close self.intraTradeLow = bar.close if self.now_time >= self.open_time and self.now_time <= self.close_time: # 金叉开仓 if self.am.close[-1] > self.UBUY and self.am.close[-2] <= self.UBUY and self.am.close[-3] < self.UBUY and self.KK: self.cancelAll() self.buy(price=bar.close+0.01, volume=self.fixedSize) # 死叉做空 elif self.am.close[-1] < self.DSELL and self.am.close[-2] >= self.DSELL and self.am.close[-3] > self.DSELL and self.KK: self.cancelAll() self.short(price=bar.close-0.01, volume=self.fixedSize) elif self.pos > 0: self.intraTradeHigh = max(self.intraTradeHigh, bar.close) self.intraTradeLow = min(self.intraTradeLow, bar.close) is_sell = False if self.intraTradeHigh > self.last_trade_price * (1 + self.ZS/1000*3) and bar.close - self.last_trade_price <= (self.intraTradeHigh - self.last_trade_price) * 0.4: is_sell = True if self.intraTradeHigh > self.last_trade_price * (1 + self.ZS/1000*6) and bar.close - self.last_trade_price <= (self.intraTradeHigh - self.last_trade_price) * 0.5: is_sell = True yuzhi = self.last_trade_price * (1 - self.ZS/1000) # 阈值缓存 if self.am.close[-1] < yuzhi and self.am.close[-2] >= yuzhi: is_sell = True yuzhi = self.last_trade_price * (1 + 10 * self.ZS / 1000) if self.am.close[-1] > yuzhi and self.am.close[-2] <= yuzhi: is_sell = True if is_sell: self.cancelAll() self.sell(price=bar.close - 0.01, volume=self.fixedSize) elif self.pos < 0: self.intraTradeHigh = max(self.intraTradeHigh, bar.close) self.intraTradeLow = min(self.intraTradeLow, bar.close) is_cover = False if self.intraTradeLow < self.last_trade_price * (1 - self.ZS/1000*3) and self.last_trade_price - bar.close <= (self.last_trade_price - self.intraTradeLow) * 0.5: is_cover = True if self.intraTradeLow < self.last_trade_price * (1 - self.ZS/1000*6) and self.last_trade_price - bar.close <= (self.last_trade_price - self.intraTradeLow) * 0.7: is_cover = True yuzhi = self.last_trade_price * (1 + self.ZS/1000) if self.am.close[-1] > yuzhi and self.am.close[-2] <= yuzhi: is_cover = True yuzhi = self.last_trade_price * (1 - 10 * self.ZS / 1000) if self.am.close[-1] < yuzhi and self.am.close[-2] >= yuzhi: is_cover = True if is_cover: self.cancelAll() self.cover(price=bar.close + 0.01, volume=self.fixedSize) def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass def onTrade(self, trade): """收到交易发生事件推送""" self.last_trade_price = trade.price print("发生交易") print(trade.__dict__) print("\n") self.putEvent() def onStopOrder(self, so): """收到停止单事件推送""" self.putEvent() def closeAllPosition(self, bar): self.cancelAll() if self.pos > 0: self.sell(price=bar.close - 0.01, volume=self.fixedSize) elif self.pos < 0: self.cover(price=bar.close + 0.01, volume=self.fixedSize)
class KkStrategy(CtaTemplate): """基于King Keltner通道的交易策略""" className = 'KkStrategy' author = u'用Python的交易员' # 策略参数 kkLength = 11 # 计算通道中值的窗口数 kkDev = 1.6 # 计算通道宽度的偏差 trailingPrcnt = 0.8 # 移动止损 initDays = 10 # 初始化数据所用的天数 fixedSize = 1 # 每次交易的数量 # 策略变量 kkUp = 0 # KK通道上轨 kkDown = 0 # KK通道下轨 intraTradeHigh = 0 # 持仓期内的最高点 intraTradeLow = 0 # 持仓期内的最低点 buyOrderIDList = [] # OCO委托买入开仓的委托号 shortOrderIDList = [] # OCO委托卖出开仓的委托号 orderList = [] # 保存委托代码的列表 # 参数列表,保存了参数的名称 paramList = [ 'name', 'className', 'author', 'vtSymbol', 'kkLength', 'kkDev' ] # 变量列表,保存了变量的名称 varList = ['inited', 'trading', 'pos', 'kkUp', 'kkDown'] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(KkStrategy, self).__init__(ctaEngine, setting) self.bm = BarManager(self.onBar, 5, self.onFiveBar) # 创建K线合成器对象 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 onFiveBar(self, bar): """收到5分钟K线""" # 撤销之前发出的尚未成交的委托(包括限价单和停止单) for orderID in self.orderList: self.cancelOrder(orderID) self.orderList = [] # 保存K线数据 am = self.am am.updateBar(bar) if not am.inited: return # 计算指标数值 self.kkUp, self.kkDown = am.keltner(self.kkLength, self.kkDev) # 判断是否要进行交易 # 当前无仓位,发送OCO开仓委托 if self.pos == 0: self.intraTradeHigh = bar.high self.intraTradeLow = bar.low self.sendOcoOrder(self.kkUp, self.kkDown, self.fixedSize) # 持有多头仓位 elif self.pos > 0: self.intraTradeHigh = max(self.intraTradeHigh, bar.high) self.intraTradeLow = bar.low l = self.sell(self.intraTradeHigh * (1 - self.trailingPrcnt / 100), abs(self.pos), True) self.orderList.extend(l) # 持有空头仓位 elif self.pos < 0: self.intraTradeHigh = bar.high self.intraTradeLow = min(self.intraTradeLow, bar.low) l = self.cover(self.intraTradeLow * (1 + self.trailingPrcnt / 100), abs(self.pos), True) self.orderList.extend(l) # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass #---------------------------------------------------------------------- def onTrade(self, trade): if self.pos != 0: # 多头开仓成交后,撤消空头委托 if self.pos > 0: for shortOrderID in self.shortOrderIDList: self.cancelOrder(shortOrderID) # 反之同样 elif self.pos < 0: for buyOrderID in self.buyOrderIDList: self.cancelOrder(buyOrderID) # 移除委托号 for orderID in (self.buyOrderIDList + self.shortOrderIDList): if orderID in self.orderList: self.orderList.remove(orderID) # 发出状态更新事件 self.putEvent() #---------------------------------------------------------------------- def sendOcoOrder(self, buyPrice, shortPrice, volume): """ 发送OCO委托 OCO(One Cancel Other)委托: 1. 主要用于实现区间突破入场 2. 包含两个方向相反的停止单 3. 一个方向的停止单成交后会立即撤消另一个方向的 """ # 发送双边的停止单委托,并记录委托号 self.buyOrderIDList = self.buy(buyPrice, volume, True) self.shortOrderIDList = self.short(shortPrice, volume, True) # 将委托号记录到列表中 self.orderList.extend(self.buyOrderIDList) self.orderList.extend(self.shortOrderIDList) #---------------------------------------------------------------------- def onStopOrder(self, so): """停止单推送""" pass
class LastGoldStrategy(CtaTemplate): """基于King Keltner通道的交易策略""" className = 'LastGoldStrategy' author = '中融致信投资技术部' # 策略参数 initDays = 10 # 数据初始化天数 # ---------------------------------------------------------------------- def __init__(self, ctaEngine, setting): """Constructor""" super(LastGoldStrategy, self).__init__(ctaEngine, setting) self.bm = BarManager(self.onBar) # 创建K线合成器对象 # self.am = ArrayManager2(size=120) self.fixedSize = 1 # 每次交易的数量 self.night_open_price = None # 夜盘开盘价 (21:00) self.night_mid_price = None # 盘中参考价(22:30) # ---------------------------------------------------------------------- def onInit(self): """初始化策略(必须由用户继承实现)""" self.writeCtaLog('%s策略初始化' % self.name) # 载入历史数据,并采用回放计算的方式初始化策略数值 # initData = self.loadBar(self.initDays) # for bar in initData: # self.onBar(bar) self.putEvent() #---------------------------------------------------------------------- def onStart(self): """启动策略(必须由用户继承实现)""" self.writeCtaLog('%s策略启动' % self.name) self.putEvent() #---------------------------------------------------------------------- def onStop(self): """停止策略(必须由用户继承实现)""" self.writeCtaLog('%s策略停止' % self.name) self.putEvent() #---------------------------------------------------------------------- def onTick(self, tick): """收到行情TICK推送(必须由用户继承实现)""" self.bm.updateTick(tick) #---------------------------------------------------------------------- def onBar(self, bar): """收到Bar推送(必须由用户继承实现)""" # 保存K线数据 # am = self.am # am.updateBar(bar) # 如果k先还没有初始化完成,就不执行 # if not am.inited: # return # 获取当前时间 time_now = bar.datetime.time() # 21:00:00 记住开盘价 if time_now == datetime.time(hour=21, minute=0, second=0): self.night_open_price = bar.open # 记住22:30:00的价格 elif time_now == datetime.time(hour=22, minute=30, second=0): self.night_mid_price = bar.open # 没有加载到比较数据,直接返回 if self.night_open_price is None or self.night_mid_price is None: return # 22:58分开仓 if time_now == datetime.time(hour=22, minute=58, second=0): if self.pos == 0: # 趋势: 1向上, -1向下,0无趋势 trend_l = 0 # 长趋势 trend_s = 0 # 短趋势 if bar.close - self.night_mid_price > bar.close * 0.005: trend_s = 1 if bar.close - self.night_open_price > bar.close * 0.005: trend_l = 1 if bar.close - self.night_mid_price < 0 - bar.close * 0.005: trend_s = -1 if bar.close - self.night_open_price < 0 - bar.close * 0.005: trend_l = -1 # 有其中一个趋势或者趋势共振 if trend_s + trend_l >= 1: self.buy(price=bar.close + 0.0, volume=self.fixedSize) elif trend_s + trend_l <= -1: self.short(price=bar.close - 0.0, volume=self.fixedSize) # 9:05平仓所有 elif time_now == datetime.time(hour=9, minute=4, second=0): self.closeAllPosition(bar) # 如果没有开仓成功则撤单 elif time_now == datetime.time(hour=23, minute=28, second=0): self.cancelAll() def onOrder(self, order): """收到委托变化推送(必须由用户继承实现)""" pass def onTrade(self, trade): """收到交易发生事件推送""" pass def onStopOrder(self, so): """收到停止单事件推送""" self.putEvent() def closeAllPosition(self, bar): """平掉所有仓位""" self.cancelAll() if self.pos > 0: self.sell(price=bar.close - 3.0, volume=self.fixedSize) elif self.pos < 0: self.cover(price=bar.close + 3.0, volume=self.fixedSize)