def generate_3mindata(self, am:ArrayManager, bar:BarData): offset = -self.offset offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) std_val2 = np.std(np.array(self.ma_tag[-10:-1])) std_val3 = np.std(np.array(am.range[-30:-10])) ma = self.ma_tag[-1] mean_val = np.mean(calc_nums) mean_val2 = np.mean(np.array(self.ma_tag[-5:-1])) mean_val3 = np.mean(np.array(self.ma_tag[-20:-1])) mean_val4 = np.mean(np.array(self.ma_tag[-30:-5])) kdj_val = am.kdj() deg1 = calc_regress_deg(am.close[offset : offset_m], False) deg2 = calc_regress_deg(am.close[offset_m :], False) deg3 = calc_regress_deg(am.close[-10 :], False) deg_full = calc_regress_deg(am.close[offset :], False) wave = self.wave(am.close[-30:]) wave_r_sum = np.sum(wave["range"]) macd=am.macd(20,40, 16) calc_data = (dict( kdj=[round(kdj_val["k"][-1],2),round(kdj_val["d"][-1],2),round(kdj_val["j"][-1],2)], cci_20=am.cci(20),rsi=am.rsi(20),adx=am.adx(20),boll=am.boll(20, 3.4), macd=[round(macd[0],2),round(macd[1],2),round(macd[2],2)], deg40_20=round(deg1,2), deg20_0=round(deg2,2), deg20_10=round(calc_regress_deg(am.close[-20:-10], False),2), deg10_0=round(deg3,2), deg30_15=round(calc_regress_deg(am.close[-30:-15], False),2), deg15_0=round(calc_regress_deg(am.close[-15:], False),2),deg_f=round(deg_full,2), atr=round(am.atr(10, length=15), 3), tr=round(am.atr(1, length=2), 3),atr_40=round(am.atr(40, length=42), 3), time=bar.datetime, price=bar.close_price, ma=round(ma, 2), std_40=round(std_val, 2),mean40=round(mean_val,2), mean_std=np.mean(self.std_range.data[-5:]), std_10=round(std_val2,2), mean30_10=round(mean_val4,2), mean10=round(mean_val2,2), vol=am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=am.range[-1:-5:-1].tolist(), range_sum=np.sum(am.range[-5:]), pattern=list(map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())), ma120t=self.ma120_track, ma120t_list=self.ma120_track_list[-1:-10:-1], ma120t_sort=sorted(self.ma120_track_list[-20:-1], key=abs), ma120t_sum=np.sum(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_mean=np.mean(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_std=np.std(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma_info=list(map(lambda x:x["std"], self.ma_info[-1:])), wave_cnt=len(wave), wave_r_sum=wave_r_sum, atr_mean=np.mean(am.atr(20, array=True,length=240)[-200:]) )) return calc_data
class AroonAtrStrategy(CtaTemplate): """""" author = "tonywang_efun" fixed_size = 1 bar_window = 26 boll_window = 39 boll_dev = 1.9 aroon_window = 14 aroon_long = 50 aroon_short = 50 atr_window = 30 atr_stop_multiplier = 3 boll_up = 0 boll_down = 0 aroon_up = 0 aroon_down = 0 intra_trade_high = 0 intra_trade_low = 0 long_stop = 0 short_stop = 0 atr_value = 0 parameters = [ "fixed_size", "bar_window", "boll_window", "boll_dev", "aroon_window", "aroon_long", "aroon_short", "atr_window", "atr_stop_multiplier" ] variables = [ "boll_up", "boll_down", "aroon_up", "aroon_down", "atr_value", "intra_trade_high", "intra_trade_low", "long_stop", "short_stop" ] def __init__( self, cta_engine, strategy_name: str, vt_symbol: str, setting: dict, ): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar, self.bar_window, self.on_xmin_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_xmin_bar(self, bar: BarData): """""" self.cancel_all() self.am.update_bar(bar) if not self.am.inited: return self.aroon_up, self.aroon_down = self.am.aroon(self.aroon_window) self.atr_value = self.am.atr(self.atr_window) self.boll_up, self.boll_down = self.am.boll(self.boll_window, self.boll_dev) if not self.pos: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price self.long_stop = 0 self.short_stop = 0 if self.aroon_up > self.aroon_down and self.aroon_up > self.aroon_long: self.buy(self.boll_up, self.fixed_size, stop=True) if self.aroon_down > self.aroon_up and self.aroon_down > self.aroon_short: self.short(self.boll_down, self.fixed_size, stop=True) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.long_stop = self.intra_trade_high - self.atr_value * self.atr_stop_multiplier self.sell(self.long_stop, abs(self.pos), stop=True) else: self.intra_trade_low = min(self.intra_trade_low, bar.low_price) self.short_stop = self.intra_trade_low + self.atr_value * self.atr_stop_multiplier self.cover(self.short_stop, abs(self.pos), stop=True) self.put_event() def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
def generate_data(self, am: ArrayManager, bar: BarData): offset = -self.offset offset_m = int(offset / 2) std_val3 = np.std(np.array(am.range[-30:-10])) kdj_val = am.kdj() has_kdj_recore = False k = kdj_val["k"] d = kdj_val["d"] j = kdj_val["j"] if (k[-1] > 75 and d[-1] > 75 and j[-1] > 75) or \ (k[-1] < 25 and d[-1] < 25 and j[-1] < 75): if (j[-2] < k[-2] or j[-2] < d[-2]) and (j[-1] > k[-1] and j[-1] > d[-1]) \ or \ (j[-2] > k[-2] or j[-2] > d[-2]) and (j[-1] < k[-1] and j[-1] < d[-1]): has_kdj_recore = True t = bar.datetime self.kdj_record.append( (t.strftime("%H:%M:%S"), round(k[-1], 3), round(d[-1], 3), round(j[-1], 3))) deg1 = calc_regress_deg(am.close[offset:offset_m], False) deg2 = calc_regress_deg(am.close[offset_m:], False) deg3 = calc_regress_deg(am.close[-10:], False) deg_full = calc_regress_deg(am.close[offset:], False) macd = am.macd(20, 40, 16) calc_data = (dict( kdj=[ round(kdj_val["k"][-1], 2), round(kdj_val["d"][-1], 2), round(kdj_val["j"][-1], 2) ], cci_20=am.cci(20), rsi=am.rsi(20), adx=am.adx(20), boll=am.boll(20, 3.4), macd=[round(macd[0], 2), round(macd[1], 2), round(macd[2], 2)], deg40_20=round(deg1, 2), deg20_0=round(deg2, 2), deg20_10=round(calc_regress_deg(am.close[-20:-10], False), 2), deg30_15=round(calc_regress_deg(am.close[-30:-15], False), 2), deg15_0=round(calc_regress_deg(am.close[-15:], False), 2), deg_f=round(deg_full, 2), deg30_10=round(calc_regress_deg(am.close[-30:-10], False), 2), deg10_0=round(deg3, 2), atr=round(am.atr(10, length=15), 3), tr=round(am.atr(1, length=2), 3), atr_40=round(am.atr(40, length=42), 3), time=bar.datetime, price=bar.close_price, mean_std=np.mean(self.std_range.data[-5:]), vol=am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=am.range[-1:-5:-1].tolist(), range_sum=np.sum(am.range[-5:]), pattern=list( map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())), atr_mean=np.mean(am.atr(20, array=True, length=240)[-200:]), )) if self.ma_info.info.index.size >= 31: ma5 = self.ma_info.info[5][-31:] x = AnalyseWave(ma5) calc_data["ma5_info"] = x.optimize ma10 = self.ma_info.info[10][-31:] x = AnalyseWave(ma10) calc_data["ma10_info"] = x.optimize return calc_data
class TurtleSignalStrategy(CtaTemplate): """""" author = "用Python的交易员" # 唐奇安上下轨突破的周期,买入位置 entry_window = 20 # 唐奇安通道,卖出位置 exit_window = 10 atr_window = 20 # 乘数,每次下单的单位大小 fixed_size = 1 entry_up = 0 entry_down = 0 exit_up = 0 exit_down = 0 atr_value = 0 # 多头入场价,每次交易后,设置为当前交易价格 long_entry = 0 short_entry = 0 # 多头止损价格 long_stop = 0 short_stop = 0 parameters = ["entry_window", "exit_window", "atr_window", "fixed_size"] variables = ["entry_up", "entry_down", "exit_up", "exit_down", "atr_value"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(TurtleSignalStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(20) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ # 取消之前未成交的单子 self.cancel_all() self.am.update_bar(bar) if not self.am.inited: return # Only calculates new entry channel when no position holding # 没有持仓时才计算入场价 if not self.pos: self.entry_up, self.entry_down = self.am.donchian( self.entry_window) self.exit_up, self.exit_down = self.am.donchian(self.exit_window) if not self.pos: self.atr_value = self.am.atr(self.atr_window) self.long_entry = 0 self.short_entry = 0 self.long_stop = 0 self.short_stop = 0 # 下本地止损单,等到突破或者跌破成交 self.send_buy_orders(self.entry_up) self.send_short_orders(self.entry_down) elif self.pos > 0: # 如果之前有多头突破单成交,下单,根据atr加仓. # 不用考虑历史仓位,默认前面都是按照规则正确下单成交的仓位,不考虑未成交情况 self.send_buy_orders(self.entry_up) # 止损价和止盈退出价中的大的一方 sell_price = max(self.long_stop, self.exit_down) # 下多头止盈单 self.sell(sell_price, abs(self.pos), True) elif self.pos < 0: # 如果之前有空仓,加仓 self.send_short_orders(self.entry_down) cover_price = min(self.short_stop, self.exit_up) # 下空头止盈单 self.cover(cover_price, abs(self.pos), True) self.put_event() def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ print( f"海龟交易,{trade.tradeid}, {trade.price}, {trade.direction}, {trade.time}" ) if trade.direction == Direction.LONG: self.long_entry = trade.price # 修改多头止损价格 self.long_stop = self.long_entry - 2 * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + 2 * self.atr_value def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def send_buy_orders(self, price): """""" t = self.pos / self.fixed_size if t < 1: self.buy(price, self.fixed_size, True) if t < 2: self.buy(price + self.atr_value * 0.5, self.fixed_size, True) if t < 3: self.buy(price + self.atr_value, self.fixed_size, True) if t < 4: self.buy(price + self.atr_value * 1.5, self.fixed_size, True) def send_short_orders(self, price): """""" t = self.pos / self.fixed_size if t > -1: self.short(price, self.fixed_size, True) if t > -2: self.short(price - self.atr_value * 0.5, self.fixed_size, True) if t > -3: self.short(price - self.atr_value, self.fixed_size, True) if t > -4: self.short(price - self.atr_value * 1.5, self.fixed_size, True)
class CincoStrategyHN(CtaTemplate): """""" author = "Huang Ning" boll_window = 42 boll_dev = 2.0 trailing_long = 0.65 trailing_short = 0.7 atr_window = 10 risk_level = 100 boll_up = 0 boll_down = 0 trading_size = 0 intra_trade_high = 0 intra_trade_low = 0 long_stop = 0 short_stop = 0 atr_value = 0 parameters = [ "boll_window", "boll_dev", "trailing_long", "trailing_short", "atr_window", "risk_level" ] variables = [ "boll_up", "boll_down", "trading_size", "intra_trade_high", "intra_trade_low", "long_stop", "short_stop", "atr_value" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(CincoStrategyHN, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar, 15, self.on_15min_bar) self.am = ArrayManager() def on_init(self): """""" self.write_log("策略初始化") self.load_bar(10) def on_start(self): """""" self.write_log("策略启动") def on_stop(self): """""" self.write_log("策略停止") def on_tick(self, tick: TickData): """""" self.bg.update_tick(tick) def on_bar(self, bar: BarData): """""" self.bg.update_bar(bar) def on_15min_bar(self, bar: BarData): """""" self.cancel_all() self.am.update_bar(bar) if not self.am.inited: return self.boll_up, self.boll_down = self.am.boll(self.boll_window, self.boll_dev) boll_width = self.boll_up - self.boll_down if not self.pos: self.atr_value = self.am.atr(self.atr_window) self.trading_size = int(self.risk_level / self.atr_value) self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price self.long_stop = 0 self.short_stop = 0 self.buy(self.boll_up, self.trading_size, stop=True) self.short(self.boll_down, self.trading_size, stop=True) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.long_stop = self.intra_trade_high - self.trailing_long * boll_width self.sell(self.long_stop, abs(self.pos), stop=True) else: self.intra_trade_low = min(self.intra_trade_low, bar.low_price) self.short_stop = self.intra_trade_low + self.trailing_short * boll_width self.cover(self.short_stop, abs(self.pos), stop=True) self.put_event() def on_order(self, order: OrderData): """""" def on_trade(self, trade: TradeData): """""" self.put_event() def on_stop_order(self, stop_order: StopOrder): """""" self.put_event()
class AtrStop_Ut(CtaTemplate): """""" author = "yunya" atrstop_window = 46 open_window = 5 nloss_singnal = 2.7 trailing_tax = 2.0 risk_level = 5000 exit_dc_length = 50 atr_length = 30 atrstop_entry = 0 current_atr_stop = 0.0 last_atr_stop = 0.0 intra_trade_high = 0 intra_trade_low = 0 nloss_array = 0.0 long_stop = 0 short_stop = 0 trading_size = 0 exit_down = 0 exit_up = 0 ask = 0 bid = 0 atr_value = 0 count = 0 parameters = [ "atrstop_window", "open_window", "nloss_singnal", "trailing_tax", "risk_level", "exit_dc_length", "atr_length" ] variables = [ "atrstop_entry", "current_atr_stop", "last_atr_stop", "intra_trade_high", "intra_trade_low", "long_stop", "short_stop", "exit_down", "exit_up", "trading_size", ] def __init__( self, cta_engine: Any, strategy_name: str, vt_symbol: str, setting: dict, ): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.atr_stop_array = np.zeros(10) self.bg_xmin = NewBarGenerator( self.on_bar, window=self.atrstop_window, on_window_bar=self.on_xmin_bar, interval=Interval.MINUTE ) self.am_xmin = ArrayManager() self.bg_5min = BarGenerator( self.on_bar, window=self.open_window, on_window_bar=self.on_5min_bar ) self.am_5min = ArrayManager(self.exit_dc_length * int(self.atr_length / self.open_window) + 10) self.inited_atr_stop = False # 状态控制初始化 self.chase_long_trigger = False self.chase_sell_trigger = False self.chase_short_trigger = False self.chase_cover_trigger = False self.cancel_status = False self.long_trade_volume = 0 self.short_trade_volume = 0 self.sell_trade_volume = 0 self.cover_trade_volume = 0 self.chase_interval = 10 # 拆单间隔:秒 def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化。。") self.load_bar(10) # self.put_event() def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动。。") self.put_event() def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止。。") self.put_event() def on_tick(self, tick: TickData): working_order_dict = self.get_position_detail(tick.vt_symbol).active_orders # working_order_dict = self.order_dict if working_order_dict: # 委托完成状态 order_finished = False vt_orderid = list(working_order_dict.items())[0][0] # 委托单vt_orderid working_order = list(working_order_dict.items())[0][1] # 委托单字典 # 开平仓追单,部分交易没有平仓指令(Offset.NONE) """获取到未成交委托单后检查未成交委托量>0,tick.datetime - 未成交委托单的datetime>追单间隔(chase_interval), 同时chase_long_trigger状态未触发和有vt_orderid的判定(之前有收过空vt_orderid,所有要加个过滤),撤销该未成交委托单, 赋值chase_long_trigger为True.chase_long_trigger为True且没有未成交委托单时执行追单, 如有未成交委托单则调用cancel_surplus_order取消所有未成交委托单,追单的委托单发送出去后初始化chase_long_trigger. 其他方向的撤单追单也是一样的流程""" if working_order.offset in (Offset.NONE, Offset.OPEN): if working_order.direction == Direction.LONG: self.long_trade_volume = working_order.untrade if ( tick.datetime - working_order.datetime).seconds > self.chase_interval and self.long_trade_volume > 0 and ( not self.chase_long_trigger) and vt_orderid: # 撤销之前发出的未成交订单 self.cancel_order(vt_orderid) self.chase_long_trigger = True elif working_order.direction == Direction.SHORT: self.short_trade_volume = working_order.untrade if ( tick.datetime - working_order.datetime).seconds > self.chase_interval and self.short_trade_volume > 0 and ( not self.chase_short_trigger) and vt_orderid: self.cancel_order(vt_orderid) self.chase_short_trigger = True # 平仓追单 elif working_order.offset in (Offset.CLOSE, Offset.CLOSETODAY): if working_order.direction == Direction.SHORT: self.sell_trade_volume = working_order.untrade if ( tick.datetime - working_order.datetime).seconds > self.chase_interval and self.sell_trade_volume > 0 and ( not self.chase_sell_trigger) and vt_orderid: self.cancel_order(vt_orderid) self.chase_sell_trigger = True if working_order.direction == Direction.LONG: self.cover_trade_volume = working_order.untrade if ( tick.datetime - working_order.datetime).seconds > self.chase_interval and self.cover_trade_volume > 0 and ( not self.chase_cover_trigger) and vt_orderid: self.cancel_order(vt_orderid) self.chase_cover_trigger = True else: order_finished = True self.cancel_status = False if self.chase_long_trigger: if order_finished: self.buy(tick.ask_price_1, self.long_trade_volume) self.chase_long_trigger = False else: self.cancel_surplus_order(list(working_order_dict)) elif self.chase_short_trigger: if order_finished: self.short(tick.bid_price_1, self.short_trade_volume) self.chase_short_trigger = False else: self.cancel_surplus_order(list(working_order_dict)) elif self.chase_sell_trigger: if order_finished: self.sell(tick.bid_price_1, self.sell_trade_volume) self.chase_sell_trigger = False else: self.cancel_surplus_order(list(working_order_dict)) elif self.chase_cover_trigger: if order_finished: self.cover(tick.ask_price_1, self.cover_trade_volume) self.chase_cover_trigger = False else: self.cancel_surplus_order(list(working_order_dict)) # ------------------------------------------------------------------------------------ def cancel_surplus_order(self, orderids: list): """ 撤销剩余活动委托单 """ if not self.cancel_status: for vt_orderid in orderids: self.cancel_order(vt_orderid) self.cancel_status = True def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg_xmin.update_bar(bar) self.bg_5min.update_bar(bar) def on_5min_bar(self, bar: BarData): self.cancel_all() self.am_5min.update_bar(bar) if not self.am_5min.inited or not self.am_xmin.inited: return if self.atr_stop_array[-3] == 0: return self.exit_up, self.exit_down = self.am_5min.donchian( self.exit_dc_length * int(self.atr_length / self.open_window)) # print(f"dc上轨:{self.exit_up},下轨:{self.exit_down}") if not self.pos: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if self.atrstop_entry > 0: self.buy(self.current_atr_stop, self.trading_size, True) elif self.atrstop_entry < 0: self.short(self.current_atr_stop, self.trading_size, True) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) long_high = self.intra_trade_high * \ (1 - self.trailing_tax / 100) self.long_stop = max(self.exit_down, long_high) self.sell(self.long_stop, abs(self.pos), True) else: self.intra_trade_low = min(self.intra_trade_low, bar.low_price) short_low = self.intra_trade_low * \ (1 + self.trailing_tax / 100) self.short_stop = min(self.exit_up, short_low) self.cover(self.short_stop, abs(self.pos), True) self.put_event() def on_xmin_bar(self, bar: BarData): """""" am_xmin = self.am_xmin am_xmin.update_bar(bar) self.atr_stop_array[:-1] = self.atr_stop_array[1:] if not am_xmin.inited: return # 计算轨道线 nloss self.nloss_array = am_xmin.atr(30, array=True) * self.nloss_singnal # 计算轨道线 self.atr_stop_array = self.atrstop( am_xmin.close, self.atr_stop_array, self.nloss_array ) # 初始化 atr_stop_array 保证前三个有值 if self.count < 4: self.count += 1 return self.current_atr_stop = self.atr_stop_array[-1] self.last_atr_stop = self.atr_stop_array[-2] current_bar = self.am_xmin.close[-1] if self.current_atr_stop > self.last_atr_stop and current_bar > self.current_atr_stop: self.atrstop_entry = 1 elif self.current_atr_stop < self.last_atr_stop and current_bar < self.current_atr_stop: self.atrstop_entry = -1 else: self.atrstop_entry = 0 if self.pos == 0: self.atr_value = self.am_xmin.atr(self.atr_length) self.trading_size = max(int(self.risk_level / self.atr_value), 1) self.sync_data() self.put_event() def on_trade(self, trade: TradeData): """ 有成交时 Callback of new trade data update. """ self.put_event() def on_order(self, order: OrderData): """ 订单更新回调 Callback of new order data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event() def atrstop(self, close, atrstop, nlossatr): # 计算轨道线 if (close[-1] > atrstop[-2]) and (close[-2] > atrstop[-2]): atrstop[-1] = max(atrstop[-2], close[-1] - nlossatr[-1]) elif (close[-1] < atrstop[-2]) and (close[-2] < atrstop[-2]): atrstop[-1] = min(atrstop[-2], close[-1] + nlossatr[-1]) elif (close[-1] > atrstop[-2]): atrstop[-1] = (close[-1] - nlossatr[-1]) else: atrstop[-1] = (close[-1] + nlossatr[-1]) return atrstop
class PatternScoreStrategy(CtaTemplate): author = "用Python的交易员" ma_level = [10, 20, 30, 60, 120] ma_tag = [] bd = [] fast_ma0 = 0.0 fast_ma1 = 0.0 slow_ma0 = 0.0 slow_ma1 = 0.0 request_order = [] bar_identify = [] score = Score() count = 0 interval = 6 parameters = ["ma_level"] variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(PatternScoreStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar) self.am = ArrayManager(400) self.am3 = ArrayManager(150) self.bg3 = BarGenerator(self.on_bar, 3, self.on_3min_bar) self.am5 = ArrayManager(120) self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.order_data = None self.positions = Position(self) self.std_range = IntervalGen(np.std, 5) self.std_range3 = IntervalGen(np.std, 5) self.std_range5 = IntervalGen(np.std, 5) self.pattern_record = PatternRecord() # self.pattern_record.set_expiry([KlinePattern.CDLEVENINGSTAR], 3) self.pattern_record.set_expiry(list(KlinePattern), 1) self.open_strategy = [self.open_kline1] self.offset = 40 self.min = 0 self.max = 0 def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") self.put_event() def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") self.put_event() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) self.bg3.update_tick(tick) self.bg5.update_tick(tick) def on_3min_bar(self, bar: BarData): self.am3.update_bar(bar) self.std_range3.update(self.am3.range[-1]) if not self.am.inited or not self.trading: return # deg = calc_regress_deg(self.am3.close[-20:]) def calc_score(self): score = 0 score += self.score.base for item in self.pattern_record.values(): score += item["value"] return score def on_5min_bar(self, bar: BarData): self.std_range5.update(self.am5.range[-1]) self.am5.update_bar(bar) if not self.am.inited or not self.trading: return diff_time = bar.datetime - self.am.time_array[-1] if diff_time.total_seconds() > 3600 or self.count > self.interval: self.count = 0 self.score.base = calc_regress_deg(self.am.close[-self.interval:], False) * 1000 print("score:", self.score.base, self.min, self.max) else: self.count += 1 # pattern_list = [KlinePattern.CDLEVENINGSTAR, KlinePattern.CDL2CROWS, KlinePattern.CDLCONCEALBABYSWALL, KlinePattern.CDLEVENINGDOJISTAR] pattern = self.am5.pattern(list(KlinePattern)) if len(pattern) > 0: print( list( map(lambda x: (KLINE_PATTERN_CHINESE[x[0]], x[1]), pattern))) self.pattern_record.add_pattern(pattern) deg_full = calc_regress_deg(self.am.close[-40:], False) print("deg:", deg_full) self.pattern_record.update() def open_kline1(self, bar: BarData, calc_data): score = self.calc_score() if score < self.min: self.min = score if score > self.max: self.max = score if abs(calc_data["range_sum"]) < 0.001 or abs(score) < 300: return # if std_val2 < 0.2: if score > 0 and calc_data["range_sum"] > 0: return self.buy(bar.close_price, 1, type=OrderType.MARKET, extra={ "reason": "开多,score={}, rang_sum={}".format( score, calc_data["range_sum"]) }) if score < 0 and calc_data["range_sum"] < 0: return self.short(bar.close_price, 1, type=OrderType.MARKET, extra={ "reason": "开多,score={}, rang_sum={}".format( score, calc_data["range_sum"]) }) def generate_data(self, bar: BarData): offset = -self.offset offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) std_val2 = np.std(np.array(self.ma_tag[-10:-1])) std_val3 = np.std(np.array(self.am.range[-30:-10])) ma = self.ma_tag[-1] mean_val = np.mean(calc_nums) mean_val2 = np.mean(np.array(self.ma_tag[-5:-1])) mean_val3 = np.mean(np.array(self.ma_tag[-20:-1])) mean_val4 = np.mean(np.array(self.ma_tag[-30:-5])) kdj_val = self.am.kdj() deg1 = calc_regress_deg(self.am.close[offset:offset_m], False) deg2 = calc_regress_deg(self.am.close[offset_m:], False) deg3 = calc_regress_deg(self.am.close[-10:], False) deg_full = calc_regress_deg(self.am.close[offset:], False) calc_data = (dict(kdj=[ round(kdj_val["k"][-1], 2), round(kdj_val["d"][-1], 2), round(kdj_val["j"][-1], 2) ], deg40_20=round(deg1, 2), deg20=round(deg2, 2), deg10=round(deg3, 2), deg_f=round(deg_full, 2), time=bar.datetime, price=bar.close_price, ma=round(ma, 2), std_40=round(std_val, 2), mean40=round(mean_val, 2), std_10=round(std_val2, 2), mean30_10=round(mean_val4, 2), mean10=round(mean_val2, 2), vol=self.am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=self.am.range[-1:-5:-1].tolist(), range_sum=np.sum(self.am.range[-5:]), atr=self.am.atr(10), tr=self.am.atr(1, length=2), pattern=list( map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())))) return calc_data def on_strategy(self, bar: BarData): calc_data = self.generate_data(bar) order_id = None if self.pos == 0: for open_strategy in self.open_strategy: if order_id is not None: break order_id = open_strategy(bar, calc_data) else: order_id = self.positions.on_strategy(bar, calc_data) if order_id is not None: offset = -self.offset offset_m = int(offset / 2) self.tracker["trade_info"].append( (self.am.time_array[offset], self.am.time_array[offset_m], bar.datetime, calc_data["deg40_20"], calc_data["deg20"])) self.request_order.extend(order_id) if self.tracker is not None: self.tracker["ma_tag_ls"].append(calc_data) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg3.update_bar(bar) self.bg5.update_bar(bar) am = self.am self.am.update_bar(bar) max_len = self.ma_level[-1] + 20 data = self.am.close[-max_len:-1] ma_lvl = [] for i in self.ma_level: ma = self.am.sma(i, True)[-1] ma_lvl.append(ma) l = len(ma_lvl) ma_lvl_tag = [] now = bar.close_price direction = 1 if now > ma_lvl[0] else 0 ma_lvl_tag.append(direction) for i in range(l - 1): val = 1 if ma_lvl[i] > ma_lvl[i + 1] else 0 ma_lvl_tag.append(val) bincount_val = np.bincount(np.array(ma_lvl_tag)) tag_val = 0 if len(bincount_val) == 2: tag_val = bincount_val[1] if len(self.ma_tag) < 200: self.ma_tag.append(tag_val) else: self.ma_tag[:-1] = self.ma_tag[1:] self.ma_tag[-1] = tag_val if self.tracker is not None: self.tracker["bar_data"].append(bar) self.std_range.update(self.am.range[-1]) if not self.am.inited or not self.trading: return self.on_strategy(bar) # median_val = np.median(calc_nums) self.put_event() # def init_order_data(self): # self.order_data = np.array([]) def on_order(self, order: OrderData): """ Callback of new order data update. """ print("{}产生了{},价格为{},交易{},".format( order.datetime.strftime("%m/%d %H:%M:%S"), order.offset.value + order.direction.value, order.price, order.status.value)) if order.vt_orderid in self.request_order: self.positions.on_order(order) if order.status == Status.ALLTRADED or order.status == Status.CANCELLED or order.status == Status.REJECTED: self.request_order.remove(order.vt_orderid) # if order.status == Status.ALLTRADED or order.status == Status.PARTTRADED: # if order.direction == Direction.LONG: # if self.positions.volumn == 0: # self.positions.close_price = round(order.price * 0.995) # self.positions.volumn += order.volume # elif order.direction == Direction.SHORT: # self.positions.volumn -= order.volume # elif order.direction == Direction.NET: # self.positions.volumn = order.volume def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class DoubleRsiAtr(CtaTemplate): """""" author = "yiran" s_window = 5 l_window = 15 atr_window = 20 atr_multiplier = 0.05 rsi_window = 11 long_threshold_l_window = 50 long_threshold_s_window = 80 exit_return = 0.02 exit_loss = 0.02 exit_return_soft_long = -0.1 exit_loss_soft_long = -0.2 exit_return_soft_short = 0.2 exit_loss_soft_short = 0.1 fixed_size = 1 start_time = time(hour=10) exit_time = time(hour=14, minute=55) long_order_record = [] short_order_record = [] rsi_value_l_window = -9999 rsi_value_s_window = -9999 atr_value = 0 position_hold = 0 long_entered = False short_entered = False parameters = [ 's_window', 'l_window', 'atr_window', 'atr_multiplier', 'exit_return_soft_long', 'exit_loss_soft_long', "rsi_window", 'exit_return_soft_short', 'exit_loss_soft_short', "long_threshold_l_window", "long_threshold_s_window", 'exit_return', 'exit_loss', "fixed_size" ] variables = ["rsi_value_l_window ", "rsi_value_s_window", "ma_trend"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.rsi_long_l = self.long_threshold_l_window self.rsi_long_s = self.long_threshold_s_window self.rsi_short_l = 100 - self.long_threshold_l_window self.rsi_short_s = 100 - self.long_threshold_s_window self.bg5 = BarGenerator(self.on_bar, self.s_window, self.on_5min_bar) self.am5 = ArrayManager() self.bg15 = BarGenerator(self.on_bar, self.l_window, self.on_15min_bar) self.am15 = ArrayManager() self.long_order_record = [] self.short_order_record = [] self.atr_value_array = np.array([]) self.atr_profit_exit_recorder = [] def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg5.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg5.update_bar(bar) self.bg15.update_bar(bar) def on_5min_bar(self, bar: BarData): """""" self.cancel_all() self.am5.update_bar(bar) if not self.am5.inited: return self.rsi_value_s_window = self.am5.rsi(self.rsi_window) self.atr_value = self.am5.atr(self.atr_window) if self.long_threshold_l_window != -9999: self.long_entered = (self.rsi_value_s_window > self.rsi_long_s) and (self.rsi_value_l_window > self.rsi_long_l) self.short_entered = ( self.rsi_value_s_window < self.rsi_short_s) and ( self.rsi_value_l_window < self.rsi_short_l) else: return if self.start_time <= bar.datetime.time() < self.exit_time: if self.pos == 0: self.position_hold = 0 if self.long_entered: self.buy(bar.close_price + 5, self.fixed_size) self.long_order_record.append(bar.close_price + 5) elif self.short_entered: self.short(bar.close_price - 5, self.fixed_size) self.short_order_record.append(bar.close_price - 5) elif self.pos > 0: self.position_hold += 1 buy_order_price = self.long_order_record[-1] initial_profit_exit_price = buy_order_price * ( 1 + self.exit_return) # 波动变大+持仓周期变长,会使得止盈的点上移 moving_profit_exit_price = buy_order_price * ( 1 + self.exit_return_soft_long ) + self.atr_value * self.atr_multiplier * self.position_hold initial_loss_exit_price = buy_order_price * (1 - self.exit_loss) # 波动变大+持仓周期变长,会使得止损的点上移 moving_loss_exit_price = buy_order_price * ( 1 + self.exit_loss_soft_long ) + self.atr_value * self.atr_multiplier * self.position_hold if initial_profit_exit_price < moving_profit_exit_price: self.atr_profit_exit_recorder.append((1, bar.datetime)) else: self.atr_profit_exit_recorder.append((0, bar.datetime)) if bar.close_price >= max(initial_profit_exit_price, moving_profit_exit_price): self.sell(bar.close_price * 0.99, abs(self.pos)) elif bar.close_price <= max(initial_loss_exit_price, moving_loss_exit_price): self.sell(bar.close_price * 0.99, abs(self.pos)) elif self.pos < 0: self.position_hold += 1 sell_order_price = self.short_order_record[-1] #初始的盈利要求比较低即空头平仓的价格比较高 initial_profit_exit_price = sell_order_price * ( 1 - self.exit_return) # 随着持仓时间推移和波动率变大,对应盈利方向上的头寸止盈要求变高,即空头平仓价格下移 moving_profit_exit_price = sell_order_price * ( 1 + self.exit_return_soft_short ) - self.atr_value * self.atr_multiplier * self.position_hold initial_loss_exit_price = sell_order_price * (1 + self.exit_loss) # 随着持仓时间推移和波动率变大,对应亏损方向上的头寸的平仓价格上升,即空头平仓价格上升 moving_loss_exit_price = sell_order_price * ( 1 + self.exit_loss_soft_short ) - self.atr_value * self.atr_multiplier * self.position_hold if bar.close_price >= min(initial_loss_exit_price, moving_loss_exit_price): self.cover(bar.close_price * 1.01, abs(self.pos)) elif bar.close_price <= min(initial_profit_exit_price, moving_profit_exit_price): self.cover(bar.close_price * 1.01, abs(self.pos)) # 通过设置合成Bar Data的周期可以使得持仓过夜 elif bar.datetime.time() > self.exit_time: if self.pos > 0: self.sell(bar.close_price * 0.99, abs(self.pos)) elif self.pos < 0: self.cover(bar.close_price * 1.01, abs(self.pos)) self.put_event() def on_15min_bar(self, bar: BarData): """""" self.am15.update_bar(bar) if not self.am15.inited: return self.rsi_value_l_window = self.am15.rsi(self.rsi_window) def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class EmaDifferenceStrategy(CtaTemplate): """ 策略逻辑: 1、计算两条不同周期均线的差离值,差离值二次求均值。 2、当差离值大于零做多,小于零做空。 3、成交价格回撤 2% 固定止损,当利润达到 5% 时,止损位移动到成本价。 """ author = "yunya" open_window = 15 express_length = 30 # 特快 fast_length = 60 # 快 slow_length = 150 # 慢 diff_ema_length = 30 # 差离ema atr_length = 6 atr_multiple = 2.0 # 成交价 2倍ATR为固定止损位 entry_mulitple = 5.0 # 当前价格超过成交价的5%时,止损价为成交价 pay_up = 5 fixed_size = 1 current_express_fast_diff = 0 last_express_fast_diff = 0 current_fast_slow_diff = 0 last_fast_slow_diff = 0 current_express_fast_ema = 0 last_express_fast_ema = 0 current_fast_slow_ema = 0 last_fast_slow_ema = 0 express_fast_inited = 0 fast_slow_inited = 0 price_tick = 0 atr_value = 0 long_entry = 0 long_stop = 0 short_entry = 0 short_stop = 0 exit_long = 0 exit_short = 0 parameters = [ "open_window", "express_length", "fast_length", "slow_length", "diff_ema_length", "atr_length", "atr_multiple", "entry_mulitple", "pay_up", "fixed_size", ] variables = [ "current_express_fast_diff", "last_express_fast_diff", "current_fast_slow_diff", "last_fast_slow_diff", "current_express_fast_ema", "last_express_fast_ema", "current_fast_slow_ema", "last_fast_slow_ema", "express_fast_inited", "fast_slow_inited", "price_tick", "atr_value", "long_entry", "long_stop", "short_entry", "short_stop", "exit_long", "exit_short", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.open_window, self.on_xmin_bar) self.am = ArrayManager(int(self.slow_length) * 100) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_xmin_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # 计算ema express_value = am.ema(self.express_length, True) fast_value = am.ema(self.fast_length, True) slow_value = am.ema(self.slow_length, True) # 计算差离值 express_fast_diff = express_value - fast_value fast_slow_diff = fast_value - slow_value # 计算差离均值 express_fast_ema = talib.EMA(express_fast_diff, self.diff_ema_length) fast_slow_ema = talib.EMA(fast_slow_diff, self.diff_ema_length) # print(f"express_fast_ema: {express_fast_ema[-10:]}" + "\n") # print(f"fast_slow_ema: {fast_slow_ema[-10:]}" + "\n") # 判断差离线交叉情况(上穿,下穿) self.current_express_fast_diff = express_fast_diff[-1] self.last_express_fast_diff = express_fast_diff[-2] self.current_fast_slow_diff = fast_slow_diff[-1] self.last_fast_slow_diff = fast_slow_diff[-2] self.current_express_fast_ema = express_fast_ema[-1] self.last_express_fast_ema = express_fast_ema[-2] self.current_fast_slow_ema = fast_slow_ema[-1] self.last_fast_slow_ema = fast_slow_ema[-2] # 计算上穿,下穿零轴 if self.current_express_fast_ema > 0 and self.last_express_fast_ema <= 0: self.express_fast_inited = 1 elif self.current_express_fast_ema < 0 and self.last_express_fast_ema >= 0: self.express_fast_inited = -1 else: self.express_fast_inited = 0 print(f"特慢:{self.express_fast_inited}" + "\n") if self.current_fast_slow_ema > 0 and self.last_fast_slow_ema <= 0: self.fast_slow_inited = 1 elif self.current_fast_slow_ema < 0 and self.last_fast_slow_ema >= 0: self.fast_slow_inited = -1 else: self.fast_slow_inited = 0 # 如果没有仓位,两条布林window一样 if self.pos == 0: # 判断是回测,还是实盘 engine_type = self.get_engine_type() if engine_type == EngineType.BACKTESTING: long_price = bar.close_price - 10 short_price = bar.close_price + 10 else: self.price_tick = self.get_pricetick() long_price = bar.close_price - self.price_tick * self.pay_up short_price = bar.close_price + self.price_tick * self.pay_up self.atr_value = self.am.atr(self.atr_length) if self.fast_slow_inited > 0: self.buy(long_price, self.fixed_size) elif self.fast_slow_inited < 0: self.short(short_price, self.fixed_size) elif self.pos > 0: long_stop_entry = bar.close_price * (1 - self.entry_mulitple / 100) self.exit_long = max(self.long_stop, long_stop_entry) if self.express_fast_inited < 0: # self.exit_long = bar.close_price - self.price_tick * self.pay_up self.exit_long = bar.close_price - 10 self.sell(self.exit_long, abs(self.pos), True) elif self.pos < 0: short_stop_entry = bar.close_price * (1 + self.entry_mulitple / 100) self.exit_short = min(self.short_stop, short_stop_entry) if self.express_fast_inited > 0: # self.exit_short = bar.close_price + self.price_tick * self.pay_up self.exit_short = bar.close_price + 10 self.cover(self.exit_short, abs(self.pos), True) self.put_event() self.sync_data() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price # 成交最高价 self.long_stop = self.long_entry - self.atr_multiple * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + self.atr_multiple * self.atr_value self.sync_data() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event() pass
class MacdRsibollDcMinuteStrategy(CtaTemplate): """ 策略逻辑: 一、、过虑信号 (小时周期) 1、使用macd 快慢线交叉来判断多空大方向。 2、使用rsiboll来判断信号强弱 二、开单信号 (分钟周期) 1、使用布林上下轨作为开单条件 三、止损 1、使用固定止损 2、dc 移动止损 3、布林宽度比例 三个止损相结合的方式 """ author = "yunya" max_window = 45 min_window = 15 open_window = 5 fast_macd = 12 slow_macd = 26 signal_macd = 9 macd_trend_level = 1.0 rsi_length = 15 boll_length = 20 boll_dev = 2.0 dc_length = 20 atr_window = 30 trailing_tax = 2.0 risk_level = 1 exit_down = 0 exit_up = 0 macd = 0 macd_entry = 0 rsi_entry = 0 intra_trade_high = 0 intra_trade_low = 0 long_stop = 0 short_stop = 0 atr_value = 0 parameters = [ "max_window", "min_window", "open_window", "fast_macd", "slow_macd", "signal_macd", "macd_trend_level", "boll_length", "boll_dev", "rsi_length", "dc_length", "atr_window", "trailing_tax", "risk_level", ] variables = [ "exit_down", "exit_up", "macd", "macd_entry", "rsi_entry", "intra_trade_high", "intra_trade_low", "long_stop", "short_stop", "atr_value", ] def __init__( self, cta_engine: Any, strategy_name: str, vt_symbol: str, setting: dict, ): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.atr_stop_array = np.zeros(10) self.bg_xhour = NewBarGenerator( on_bar=self.on_bar, window=self.max_window, on_window_bar=self.on_xhour_bar, interval=Interval.MINUTE # 由小时修改到分钟级 ) self.am_hour = ArrayManager(self.boll_length + 100) self.bg_xminute = NewBarGenerator( on_bar=self.on_bar, window=self.min_window, on_window_bar=self.on_xminute_bar ) self.am_xminute = ArrayManager(self.boll_length + 100) self.bg_open = NewBarGenerator( on_bar=self.on_bar, window=self.open_window, on_window_bar=self.on_5min_bar ) self.am_open = ArrayManager(self.dc_length * int(self.min_window / self.open_window) + 30) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化。。") self.load_bar(10) self.put_event() def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动。。") self.put_event() def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止。。") self.put_event() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg_open.update_tick(tick) self.ask = tick.ask_price_1 # 卖一价 self.bid = tick.bid_price_1 # 买一价 self.put_event() def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg_xhour.update_bar(bar) self.bg_xminute.update_bar(bar) self.bg_open.update_bar(bar) def on_5min_bar(self, bar: BarData): self.cancel_all() self.am_open.update_bar(bar) if not self.am_open.inited or not self.am_xminute.inited or not self.am_hour.inited: return # self.exit_up, self.exit_down = self.am_open.donchian( self.dc_length * int(self.min_window / self.open_window)) if not self.pos: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if self.macd_entry > 0 and self.rsi_entry > 0: self.buy(self.boll_up, self.trading_size, True) # print(bar.datetime, self.boll_up, self.trading_size) # print(bar.datetime, self.entry_up, self.trading_size, bar) if self.macd_entry < 0 and self.rsi_entry < 0: self.short(self.boll_down, self.trading_size, True) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) long_high = self.intra_trade_high * \ (1 - self.trailing_tax / 100) self.long_stop = max(self.exit_down, long_high) self.sell(self.long_stop, abs(self.pos), True) elif self.pos < 0: self.intra_trade_low = min(self.intra_trade_low, bar.low_price) short_low = self.intra_trade_low * \ (1 + self.trailing_tax / 100) self.short_stop = min(self.exit_up, short_low) self.cover(short_low, abs(self.pos), True) self.put_event() def on_xminute_bar(self, bar: BarData): """ :param bar: :return: """ self.am_xminute.update_bar(bar) if not self.am_hour.inited or not self.am_xminute.inited: return rsi_array = talib.RSI(self.am_xminute.close[:-1], self.rsi_length) ema_array = talib.EMA(self.am_xminute.close, self.rsi_length) dev_array = abs(self.am_xminute.close[:-1] - ema_array[:-1]) / rsi_array rsi_up_array = rsi_array + rsi_array * dev_array rsi_dow_array = rsi_array - rsi_array * dev_array self.rsi_value = self.am_xminute.rsi(self.rsi_length, True) self.rsi_up = rsi_up_array[-1] self.rsi_dow = rsi_dow_array[-1] current_rsi_up = rsi_up_array[-1] current_rsi_down = rsi_dow_array[-1] current_rsi_value = self.rsi_value[-1] if current_rsi_value > current_rsi_up: self.rsi_entry = 1 elif current_rsi_value < current_rsi_down: self.rsi_entry = -1 else: self.rsi_entry = 0 self.boll_up, self.boll_down = self.am_xminute.boll(self.boll_length, self.boll_dev) def on_xhour_bar(self, bar: BarData): """""" am_hour = self.am_hour am_hour.update_bar(bar) if not am_hour.inited: return macd_signal, signal, hist = self.am_hour.macd( self.fast_macd, self.slow_macd, self.signal_macd ) self.macd = signal - hist if self.macd > self.macd_trend_level: self.macd_entry = 1 elif self.macd < (-self.macd_trend_level): self.macd_entry = -1 else: self.macd_entry = 0 # 动态调整仓位 if not self.pos: self.atr_value = self.am_hour.atr(self.atr_window) if self.atr_value == 0: # 保证仓位值是有效的 return # 正向合约 atr_risk = self.am_hour.atr(self.atr_window) self.trading_size = max(int(self.risk_level / atr_risk), 1) self.put_event() def on_trade(self, trade: TradeData): """ 有成交时 Callback of new trade data update. """ self.put_event() def on_order(self, order: OrderData): """ 订单更新回调 Callback of new order data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event()
class AtrStop_Dc_Strategy(CtaTemplate): """""" author = "yunya" atrstop_window = 46 open_window = 5 distance_line = 2.0 nloss_singnal = 2.7 dc_length = 50 fixd_size = 1 atr_window = 30 atr_entry = 0 current_atr_stop = 0.0 last_atr_stop = 0.0 nloss_array = 0.0 exit_short = 0 exit_long = 0 ask = 0 bid = 0 atr_value = 0 parameters = [ "atrstop_window", "open_window", "nloss_singnal", "dc_length", "distance_line", "fixd_size", "atr_window" ] variables = [ "current_atr_stop", "last_atr_stop", "exit_short", "exit_long", "atr_entry", ] def __init__( self, cta_engine: Any, strategy_name: str, vt_symbol: str, setting: dict, ): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.atr_stop_array = np.zeros(10) self.bg_xmin = NewBarGenerator( self.on_bar, window=self.atrstop_window, on_window_bar=self.on_xmin_bar ) self.am_xmin = ArrayManager() self.bg_5min = BarGenerator( self.on_bar, window=self.open_window, on_window_bar=self.on_5min_bar ) self.am_5min = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化。。") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动。。") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止。。") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg_5min.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg_xmin.update_bar(bar) self.bg_5min.update_bar(bar) def on_5min_bar(self, bar: BarData): self.cancel_all() self.am_5min.update_bar(bar) if not self.am_5min.inited or not self.am_xmin.inited: return if self.atr_stop_array[-3] == 0: return self.atr_value = self.am_5min.atr(self.atr_window) if not self.pos: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price up_limit = self.current_atr_stop * (1 + self.distance_line / 100) down_limit = self.current_atr_stop * (1 - self.distance_line / 100) if self.atr_entry > 0 and bar.close_price < up_limit: self.buy(self.current_atr_stop, self.fixd_size, True) elif self.atr_entry < 0 and bar.close_price > down_limit: self.short(self.current_atr_stop, self.fixd_size, True) elif self.pos > 0: self.sell(self.exit_long, abs(self.pos), True) elif self.pos < 0: self.cover(self.exit_short, abs(self.pos), True) self.put_event() def on_xmin_bar(self, bar: BarData): """""" am_xmin = self.am_xmin am_xmin.update_bar(bar) self.atr_stop_array[:-1] = self.atr_stop_array[1:] if not am_xmin.inited: return # 计算轨道线 nloss self.ema_array = am_xmin.ema(3, array=True) self.nloss_array = am_xmin.atr(16, array=True) * self.nloss_singnal # 计算轨道线 self.atr_stop_array = self.atrstop( am_xmin.close, self.atr_stop_array, self.nloss_array ) # 初始化 if self.atr_stop_array[-3] == 0: return self.current_atr_stop = self.atr_stop_array[-1] self.last_atr_stop = self.atr_stop_array[-2] current_ema = self.ema_array[-1] last_ema = self.ema_array[-2] if last_ema <= self.last_atr_stop and current_ema > self.current_atr_stop: self.atr_entry = 1 elif last_ema >= self.last_atr_stop and current_ema < self.current_atr_stop: self.atr_entry = -1 self.exit_short,self.exit_long = self.am_xmin.donchian(self.dc_length) self.put_event() def on_trade(self, trade: TradeData): """ 有成交时 Callback of new trade data update. """ self.put_event() def on_order(self, order: OrderData): """ 订单更新回调 Callback of new order data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event() def atrstop(self, close, atrstop, nlossatr): # 计算轨道线 if (close[-1] > atrstop[-2]) and (close[-2] > atrstop[-2]): atrstop[-1] = max(atrstop[-2], close[-1] - nlossatr[-1]) elif (close[-1] < atrstop[-2]) and (close[-2] < atrstop[-2]): atrstop[-1] = min(atrstop[-2], close[-1] + nlossatr[-1]) elif (close[-1] > atrstop[-2]): atrstop[-1] = (close[-1] - nlossatr[-1]) else: atrstop[-1] = (close[-1] + nlossatr[-1]) return atrstop
class TurtleEStrategy(CtaTemplate): """""" # 改版海龟信号-吊灯止损法出场 author = "turtle_entry_following_stop" entry_window = 50 exit_window = 20 atr_window = 20 # stop_multiple = 10 fixed_size = 1 entry_up = 0 entry_down = 0 exit_up = 0 exit_down = 0 atr_value = 0 long_entry = 0 short_entry = 0 # long_stop = 0 # short_stop = 0 sl_multiplier = 3 intra_trade_high = 0 intra_trade_low = 0 long_stop = 0 short_stop = 0 parameters = [ "entry_window", "exit_window", "atr_window", "fixed_size", "sl_multiplier" ] variables = ["entry_up", "entry_down", "exit_up", "exit_down", "atr_value"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(20) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.cancel_all() self.am.update_bar(bar) if not self.am.inited: return # Only calculates new entry channel when no position holding if not self.pos: self.entry_up, self.entry_down = self.am.donchian( self.entry_window) self.atr_value = self.am.atr(self.atr_window) self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price self.send_buy_orders(self.entry_up) self.send_short_orders(self.entry_down) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.intra_trade_low = bar.low_price self.long_stop = self.intra_trade_high - self.atr_value * self.sl_multiplier self.sell(self.long_stop, abs(self.pos), True) elif self.pos < 0: self.intra_trade_high = bar.high_price self.intra_trade_low = min(self.intra_trade_low, bar.low_price) self.short_stop = self.intra_trade_low + self.atr_value * self.sl_multiplier self.cover(self.short_stop, abs(self.pos), True) self.put_event() def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ # if trade.direction == Direction.LONG: # self.long_entry = trade.price # self.long_stop = self.long_entry - self.stop_multiple * self.atr_value # else: # self.short_entry = trade.price # self.short_stop = self.short_entry + self.stop_multiple * self.atr_value def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def send_buy_orders(self, price): """""" self.buy(price, self.fixed_size, True) def send_short_orders(self, price): """""" self.short(price, self.fixed_size, True)
class LifeHunterStrategy(CtaTemplate): """""" author = "super dino" entry_window = 28 exit_window = 7 fast_period = 12 slow_period = 26 signal_period = 9 trend_level = 10 atr_window = 4 risk_level = 0.2 trailing_tax = 0.3 trading_size = 0 entry_up = 0 entry_down = 0 exit_up = 0 exit_down = 0 atr_value = 0 MACD_sign = 0 signal = 0 hist = 0 MACD_trend = 0 long_entry = 0 short_entry = 0 long_stop = 0 short_stop = 0 intra_trade_high = 0 intra_trade_low = 0 long_out = 0 short_out = 0 parameters = [ "entry_window", "exit_window", "fast_period", "slow_period", "signal_period", "trend_level", "atr_window", "risk_level", "trailing_tax" ] variables = [ "trading_size", "entry_up", "entry_down", "exit_up", "exit_down", "atr_value", "MACD_sign", "signal", "hist", "MACD_trend", "long_entry", "short_entry", "long_stop", "short_stop", "intra_trade_high", "intra_trade_low", "long_out", "short_out" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar, 30, self.on_30min_bar) self.am = ArrayManager() self.am30 = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(20) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) self.cancel_all() self.am.update_bar(bar) if not self.am.inited or not self.am30.inited: return # No Position if not self.pos: self.atr_value = self.am.atr(self.atr_window) if self.atr_value == 0: return atr_risk = talib.ATR(1 / self.am.high, 1 / self.am.low, 1 / self.am.close, self.atr_window)[-1] self.trading_size = max(int(self.risk_level / atr_risk), 1) self.long_entry = 0 self.short_entry = 0 self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price self.long_stop = 0 self.short_stop = 0 if self.MACD_trend > 0: self.buy(self.entry_up, self.trading_size, True) if self.MACD_trend < 0: self.short(self.entry_down, self.trading_size, True) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.long_out = self.intra_trade_high * \ (1 - self.trailing_tax / 100) sell_price = max(self.long_stop, self.exit_down, self.long_out) self.sell(sell_price, abs(self.pos), True) elif self.pos < 0: self.intra_trade_low = min(self.intra_trade_low, bar.low_price) self.short_out = self.intra_trade_low * \ (1 + self.trailing_tax / 100) cover_price = min(self.short_stop, self.exit_up, self.short_out) self.cover(cover_price, abs(self.pos), True) if bar.datetime.day == 21: print(bar.datetime, self.entry_up, bar.open_price, bar.high_price, bar.low_price, bar.close_price) self.put_event() def on_30min_bar(self, bar: BarData): """""" self.am30.update_bar(bar) if not self.am30.inited: return self.entry_up, self.entry_down = self.am30.donchian(self.entry_window) self.exit_up, self.exit_down = self.am30.donchian(self.exit_window) if bar.datetime.day == 21: print("on 30 min", bar.datetime, self.entry_up) self.MACD_sign, self.signal, self.hist = self.am30.macd( self.fast_period, self.slow_period, self.signal_period) self.MACD_sign = self.signal - self.hist if self.MACD_sign > self.trend_level: self.MACD_trend = 1 elif self.MACD_sign < (-self.trend_level): self.MACD_trend = -1 else: self.MACD_trend = 0 self.put_event() def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price self.long_stop = self.long_entry - 2 * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + 2 * self.atr_value msg = f"新的成交,策略是{self.strategy_name},方向{trade.direction},开平{trade.offset},当前仓位{self.pos}" self.send_email(msg) def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class AtrStopRsiDcStrategy(CtaTemplate): """""" author = "yunya" hour_window = 1 minute_window = 50 open_window = 5 rsi_length = 15 distance_line = 2.0 nloss_singnal = 3.1 exit_dc_length = 30 sl_multiplier = 8.0 fixd_size = 1 atr_window = 30 exit_dowm = 0 exit_up = 0 atr_entry = 0 rsi_entry = 0 current_atr_stop = 0.0 last_atr_stop = 0.0 intra_trade_high = 0 intra_trade_low = 0 nloss_array = 0.0 long_stop = 0 short_stop = 0 ask = 0 bid = 0 atr_value = 0 parameters = [ "hour_window", "minute_window", "open_window", "nloss_singnal", "rsi_length", "exit_dc_length", "sl_multiplier", "distance_line", "fixd_size", "atr_window" ] variables = [ "current_atr_stop", "last_atr_stop", "long_stop", "short_stop", "atr_entry", "atr_value", "ask", "bid" ] def __init__( self, cta_engine: Any, strategy_name: str, vt_symbol: str, setting: dict, ): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.atr_stop_array = np.zeros(10) self.bg_xhour = NewBarGenerator(on_bar=self.on_bar, window=self.hour_window, on_window_bar=self.on_xhour_bar, interval=Interval.HOUR) self.am_hour = ArrayManager() self.bg_xminute = NewBarGenerator(on_bar=self.on_bar, window=self.minute_window, on_window_bar=self.on_xminute_bar) self.am_xminute = ArrayManager() self.bg_open = NewBarGenerator(on_bar=self.on_bar, window=self.open_window, on_window_bar=self.on_5min_bar) self.am_open = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化。。") self.load_bar(10) self.put_event() def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动。。") self.put_event() def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止。。") self.put_event() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg_open.update_tick(tick) self.ask = tick.ask_price_1 # 卖一价 self.bid = tick.bid_price_1 # 买一价 self.put_event() def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg_xhour.update_bar(bar) self.bg_xminute.update_bar(bar) self.bg_open.update_bar(bar) def on_5min_bar(self, bar: BarData): self.cancel_all() self.am_open.update_bar(bar) if not self.am_open.inited or not self.am_xminute.inited or not self.am_hour.inited: return self.atr_value = self.am_open.atr(self.atr_window) if not self.pos: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price up_limit = self.current_atr_stop * (1 + self.distance_line / 100) down_limit = self.current_atr_stop * (1 - self.distance_line / 100) if self.atr_entry > 0 and self.rsi_entry > 0 and bar.close_price < up_limit: self.buy(up_limit, self.fixd_size, True) elif self.atr_entry < 0 and self.rsi_entry < 0 and bar.close_price > down_limit: self.short(down_limit, self.fixd_size, True) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.intra_trade_low = bar.low_price long_stop_high = self.intra_trade_high - self.atr_value * self.sl_multiplier self.long_stop = max(self.exit_up, long_stop_high) self.sell(self.long_stop, abs(self.pos), True) elif self.pos < 0: self.intra_trade_high = bar.high_price self.intra_trade_low = min(self.intra_trade_low, bar.low_price) short_stop_low = self.intra_trade_low + self.atr_value * self.sl_multiplier self.short_stop = min(self.exit_dowm, short_stop_low) self.cover(self.short_stop, abs(self.pos), True) self.put_event() def on_xminute_bar(self, bar: BarData): """ :param bar: :return: """ self.am_xminute.update_bar(bar) if not self.am_xminute.inited: return rsi_array = talib.RSI(self.am_xminute.close[:-1], self.rsi_length) ema_array = talib.EMA(self.am_xminute.close, self.rsi_length) dev_array = abs(self.am_xminute.close[:-1] - ema_array[:-1]) / rsi_array rsi_up_array = rsi_array + rsi_array * dev_array rsi_dow_array = rsi_array - rsi_array * dev_array self.rsi_value = self.am_xminute.rsi(self.rsi_length, True) self.rsi_up = rsi_up_array[-1] self.rsi_dow = rsi_dow_array[-1] current_rsi_up = rsi_up_array[-1] last_rsi_up = rsi_up_array[-2] current_rsi_down = rsi_dow_array[-1] last_rsi_down = rsi_dow_array[-2] current_rsi_value = self.rsi_value[-1] last_rsi_value = self.rsi_value[-2] if (current_rsi_value > current_rsi_up) and (last_rsi_value <= last_rsi_up): self.rsi_entry = 1 elif (current_rsi_value < current_rsi_down) and (last_rsi_value >= last_rsi_down): self.rsi_entry = -1 else: self.rsi_entry = 0 # print(self.rsi_entry) self.exit_dowm, self.exit_up = self.am_xminute.donchian( self.exit_dc_length) def on_xhour_bar(self, bar: BarData): """""" am_hour = self.am_hour am_hour.update_bar(bar) self.atr_stop_array[:-1] = self.atr_stop_array[1:] if not am_hour.inited: return # 计算轨道线 nloss self.ema_array = am_hour.ema(3, array=True) self.nloss_array = am_hour.atr(16, array=True) * self.nloss_singnal # 计算轨道线 self.atr_stop_array = self.atrstop(am_hour.close, self.atr_stop_array, self.nloss_array) # print(self.atr_stop_array) # 初始化 if self.atr_stop_array[-3] == 0: return self.current_atr_stop = self.atr_stop_array[-1] self.last_atr_stop = self.atr_stop_array[-2] current_ema = self.ema_array[-1] last_ema = self.ema_array[-2] if current_ema > self.current_atr_stop and last_ema <= self.last_atr_stop: self.atr_entry = 1 elif current_ema < self.current_atr_stop and last_ema >= self.last_atr_stop: self.atr_entry = -1 self.put_event() def on_trade(self, trade: TradeData): """ 有成交时 Callback of new trade data update. """ self.put_event() def on_order(self, order: OrderData): """ 订单更新回调 Callback of new order data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event() def atrstop(self, close, atrstop, nlossatr): # 计算轨道线 if (close[-1] > atrstop[-2]) and (close[-2] > atrstop[-2]): atrstop[-1] = max(atrstop[-2], close[-1] - nlossatr[-1]) elif (close[-1] < atrstop[-2]) and (close[-2] < atrstop[-2]): atrstop[-1] = min(atrstop[-2], close[-1] + nlossatr[-1]) elif (close[-1] > atrstop[-2]): atrstop[-1] = (close[-1] - nlossatr[-1]) else: atrstop[-1] = (close[-1] + nlossatr[-1]) return atrstop
class CtaTemplate_6(CtaTemplate_5): """ add bar manager """ className = 'CtaTemplate_6' author = u'rxg' # 基本变量 initDays = 20 # 初始化数据所用的天数 kLineCycle = 6 #Bar line cycle KLineSeconds = 60 #生成X秒的K线 marketTradeValue = 0 #策略的交易市值 arraySize = 100 parameters = CtaTemplate_5.parameters + \ [ 'className', 'author', 'kLineCycle', 'initDays', 'debugMode', 'KLineSeconds', 'arraySize' ] varList = CtaTemplate_5.variables + \ [ ] #---------------------------------------------------------------------- def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) print("-----") print(self.kLineCycle) self.bm = BarGenerator(self.on_bar, self.kLineCycle, self.onXminBar) # 创建K线合成器对象 self.bm.xsec = self.KLineSeconds #按指定X秒生成K线 self.am = ArrayManager(size=self.arraySize) # self.am = getSharedArrayManager(self.vt_symbol, self.kLineCycle, # self.KLineSeconds, self.arraySize) self.bm60 = BarGenerator(self.on_bar, 60, self.on60MinBar) self.am60 = ArrayManager(size=100) # self.am60 = getSharedArrayManager(self.vt_symbol, 60, # self.KLineSeconds, 100) #---------------------------------------------------------------------- # @timeit def on_init(self): """初始化策略(必须由用户继承实现)""" self.write_log(u'策略初始化') # 载入历史数据,并采用回放计算的方式初始化策略数值 self.load_bar(self.initDays) if hasattr(self, 'signal'): if hasattr(self.signal, 'am'): if not self.signal.am.inited: self.write_log(u'%s策略信号加载初始数据不足' % self.strategy_name) print(u'%s策略信号加载初始数据不足 ' % self.strategy_name, self.initDays) if not self.am.inited: print(u'%s策略加载初始数据不足 ' % self.strategy_name, self.kLineCycle, self.initDays) if not self.am60.inited: print(u'%s策略加载60 Min Bar 初始数据不足 ' % self.strategy_name, self.initDays) self.put_event() #---------------------------------------------------------------------- def on_start(self): """启动策略(必须由用户继承实现)""" self.write_log(u'策略启动') self.put_event() #---------------------------------------------------------------------- def on_stop(self): """停止策略(必须由用户继承实现)""" self.cancel_all() self.write_log(u'停止') self.put_event() #---------------------------------------------------------------------- def on_tick(self, tick: TickData): """收到行情TICK推送(必须由用户继承实现)""" super(CtaTemplate_6, self).on_tick(tick) self.bm.update_tick(tick) #---------------------------------------------------------------------- def on_bar(self, bar: BarData): '''处理分钟数据''' super(CtaTemplate_6, self).on_bar(bar) self.bm.update_bar(bar) self.bm60.update_bar(bar) #---------------------------------------------------------------------- def onXminBar(self, bar): """收到X分钟K线""" # 保存K线数据 am = self.am am.update_bar(bar) if not am.inited: return def on60MinBar(self, bar): """收到X分钟K线""" self.am60.update_bar(bar) if not self.am60.inited: return #---------------------------------------------------------------------- def getVolatility(self, volatilityTime=60): """收到X分钟K线""" # 保存K线数据 return (self.am.atr(50) / self.lastPrice) * ( (volatilityTime / self.kLineCycle)**0.5)
class MaLevelTrackStrategy(CtaTemplate): author = "用Python的交易员" ma_level = [5, 10, 20, 30, 120] ma_tag = [] bd = [] fast_ma0 = 0.0 fast_ma1 = 0.0 slow_ma0 = 0.0 slow_ma1 = 0.0 request_order = [] bar_identify = [] parameters = ["ma_level"] variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(MaLevelTrackStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar, 15, self.on_1min_bar) self.am = ArrayManager(400) self.am3 = ArrayManager(150) self.bg3 = BarGenerator(self.on_bar, 3, self.on_3min_bar) self.am5 = ArrayManager(120) self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.order_data = None self.positions = Position(self) self.std_range = IntervalGen(np.std, 5) self.std_range3 = IntervalGen(np.std, 5) self.std_range5 = IntervalGen(np.std, 5) self.pattern_record = PatternRecord() # self.pattern_record.set_expiry([KlinePattern.CDLEVENINGSTAR], 3) self.pattern_record.set_expiry(list(KlinePattern), 1) five_min_open_5 = partial(self.reverse_shape_strategy, setting={ "atr": 10, "atr_valve": 0.8, "deg1": (10, 5), "deg2": 5 }) self.open_strategy = { "1": [self.reverse_shape_strategy], "5": [five_min_open_5], } self.offset = 40 self.ma120_track = None self.ma120_track_list = [] def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") self.put_event() def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") self.put_event() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) self.bg3.update_tick(tick) self.bg5.update_tick(tick) def on_3min_bar(self, bar: BarData): self.am3.update_bar(bar) self.std_range3.update(self.am3.range[-1]) if not self.am.inited or not self.trading: return pattern = self.am3.pattern( [KlinePattern.CDLEVENINGSTAR, KlinePattern.CDL2CROWS]) if len(pattern) > 0: print(pattern) self.pattern_record.add_pattern(pattern) # deg = calc_regress_deg(self.am3.close[-20:]) def wave(self, data, window=0.0002): if len(data) <= 0: return # r = array[::-1] result = {"value": [], "range": [], "pos": [], "length": []} r = data l = len(data) - 1 now = r[0] # v_list.append(now) # p_list.append(0) pos = 1 vol = 0 u_tag = None d_tag = None end_tag = None start_pos = 0 while pos < l: if math.isnan(now): now = r[pos] pos += 1 continue else: start_pos = pos - 1 break while pos < l: if now < r[pos]: u_tag = pos if d_tag: diff = r[start_pos] - r[d_tag] if abs(diff / r[start_pos]) > window and d_tag - start_pos > 1: end_tag = d_tag elif now > r[pos]: d_tag = pos if u_tag: diff = r[start_pos] - r[u_tag] if abs(diff / r[start_pos]) > window and d_tag - start_pos > 1: end_tag = u_tag if end_tag is not None: result["range"].append(r[end_tag] / r[start_pos] - 1) result["length"].append(end_tag - start_pos) start_pos = end_tag result["value"].append(r[end_tag]) result["pos"].append(end_tag) end_tag = None vol += r[pos] - now now = r[pos] pos += 1 return pd.DataFrame(result) def mode_identify(self, bar: BarData): self.bar_identify = [] hl_scale = round(bar.high_price / bar.low_price - 1, 4) if hl_scale > 0.001: diff = bar.high_price - bar.low_price diff_up = bar.low_price + diff / 2 * 1.20 diff_down = bar.low_price + diff / 2 * 0.80 close = bar.close_price if bar.open_price < diff_up and bar.open_price > diff_down and \ bar.close_price < diff_up and bar.close_price > diff_down: if bar.close_price > bar.open_price: print("绿十字星", bar.datetime, bar.high_price, bar.low_price, diff, diff_up, diff_down, bar.open_price, bar.close_price) else: print("红十字星", bar.datetime, bar.high_price, bar.low_price, diff, diff_up, diff_down, bar.open_price, bar.close_price) def on_5min_bar(self, bar: BarData): self.std_range5.update(self.am5.range[-1]) self.am5.update_bar(bar) if not self.am.inited or not self.trading: return self.on_strategy(self.am5, bar, self.open_strategy["5"]) # pattern_list = [KlinePattern.CDLEVENINGSTAR, KlinePattern.CDL2CROWS, KlinePattern.CDLCONCEALBABYSWALL, KlinePattern.CDLEVENINGDOJISTAR] # pattern = self.am5.pattern(list(KlinePattern)) # if len(pattern) > 0: # print(list(map(lambda x: (KLINE_PATTERN_CHINESE[x[0]],x[1]), pattern))) # self.pattern_record.add_pattern(pattern) # deg_full = calc_regress_deg(self.am.close[-40 :], False) # print("deg:",deg_full) # self.pattern_record.update() def open_v3(self, am: ArrayManager, bar: BarData): std_val2 = np.std(np.array(self.ma_tag[-10:-1])) mean_val2 = np.mean(np.array(self.ma_tag[-10:-1])) mean = np.mean(np.array(self.ma_tag[-30:-10])) if std_val2 < 0.2: if mean_val2 > 3: if mean_val2 >= (mean + 1): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif mean_val2 < 2: if mean_val2 <= (mean - 1): return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_v1(self, am: ArrayManager, bar: BarData): offset = -40 offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) mean_val = np.mean(calc_nums) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) if std_val < 1 and mean_val < 2 and self.ma_tag[-1] >= (mean_val + 2): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif std_val < 1 and mean_val > 3 and self.ma_tag[-1] <= (mean_val - 2): return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_v2(self, am: ArrayManager, bar: BarData): std_val2 = np.std(np.array(self.ma_tag[-10:-1])) mean_val2 = np.mean(np.array(self.ma_tag[-10:-1])) mean = np.mean(np.array(self.ma_tag[-30:-10])) if std_val2 < 0.2: if mean_val2 > 2.5: if mean_val2 >= (mean + 1): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif mean_val2 < 2.5: if mean_val2 <= (mean - 1): return self.short(bar.close_price, 1, type=OrderType.MARKET) def open2(self, am: ArrayManager, bar: BarData, calc_data): deg = calc_data["deg20"] ma = self.ma_tag[-1] if deg > 0.5 and ma > 3 and self.am5.range[-1] > -0.002: return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif deg < -0.5 and ma < 2 and self.am5.range[-1] < 0.002: return self.short(bar.close_price, 1, type=OrderType.MARKET) def open1(self, am: ArrayManager, bar: BarData, calc_data): mean = calc_data["mean30_10"] mean_val2 = calc_data["mean10"] # if std_val2 < 0.2: if mean_val2 > 3.5 and mean_val2 >= (mean + 2): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif mean_val2 < 1.5 and mean_val2 <= (mean - 2): return self.short(bar.close_price, 1, type=OrderType.MARKET) # v形反转捕获 def reverse_shape_strategy(self, am: ArrayManager, bar: BarData, calc_data, setting={ "atr": 40, "atr_valve": 0.8, "deg1": (40, 20), "deg2": (20, 0), }): deg1 = calc_data["deg40_20"] deg2 = calc_data["deg20_0"] kdj = calc_data["kdj"] atr = self.am.atr(40) if atr < 0.08: return if deg1 > 0 and deg2 > 0 or \ deg1 < 0 and deg2 < 0: return if not (abs(deg1) > 0.15 and abs(deg2) > 0.1 and (abs(deg1) + abs(deg2)) > 0.3): return close = am.close[-40:] min_val = np.min(close) max_val = np.max(close) mid_val = max_val if deg1 > 0 else min_val mid_pos = np.where(close == mid_val)[0][0] if mid_pos < 10 or mid_pos > 30: return start_val = np.min(close[:mid_pos]) if deg1 > 0 else np.max( close[:mid_pos]) start_pos = np.where(close == start_val)[0][0] l = mid_pos - start_pos # pos2 = np.where(close == min_val)[0][0] x_fit = reg_util.regress_y_polynomial(close[:mid_pos], zoom=True) deg1_remake = calc_regress_deg(x_fit[:abs(mid_pos)], False) y_fit = reg_util.regress_y_polynomial(close[mid_pos:], zoom=True) deg2_remake = calc_regress_deg(y_fit[:abs(mid_pos)], False) print(start_pos, mid_pos, deg1, deg2, deg1_remake, deg2_remake, l, start_val, mid_val) if deg2 < 0: if kdj[0] < 20 and kdj[1] < 10 and kdj[2] < 10: # if kdj[2] < 10: return self.short(bar.close_price, 1, type=OrderType.MARKET) else: if kdj[0] > 80 and kdj[1] > 90 and kdj[2] > 90: # if kdj[2] > 90: return self.buy(bar.close_price, 1, type=OrderType.MARKET) # print("找到大v形:", deg1, deg2 ) def open5(self, am: ArrayManager, bar: BarData, calc_data): ma = self.ma_tag[-1] mean = calc_data["mean30_10"] atr = self.am.atr(10, array=True, length=20) tr = self.am.atr(1, array=True, length=11) # self.ma120_track ma120 = self.am.sma(120) # if std_val2 < 0.2: mean_std = calc_data["mean_std"] if mean_std < 0.8 and tr[-1] > 0.1 and tr[-1] / tr[-10] > 3 and tr[ -1] / atr[-1] >= 1.7 and tr[-10] / atr[-10] < 1: if np.sum(self.am.range[-10:]) > 0 and self.ma120_track > 0: return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif self.ma120_track < 0: return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_kline1(self, am: ArrayManager, bar: BarData, calc_data): if KlinePattern.CDLEVENINGSTAR not in self.pattern_record: return # if std_val2 < 0.2: deg = calc_regress_deg(self.am.close[-5:], False) print("kline_strategy", deg) if deg < -0.1: return self.short(bar.close_price, 1, type=OrderType.MARKET) def generate_data(self, bar: BarData): offset = -self.offset offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) std_val2 = np.std(np.array(self.ma_tag[-10:-1])) std_val3 = np.std(np.array(self.am.range[-30:-10])) ma = self.ma_tag[-1] mean_val = np.mean(calc_nums) mean_val2 = np.mean(np.array(self.ma_tag[-5:-1])) mean_val3 = np.mean(np.array(self.ma_tag[-20:-1])) mean_val4 = np.mean(np.array(self.ma_tag[-30:-5])) kdj_val = self.am.kdj() deg1 = calc_regress_deg(self.am.close[offset:offset_m], False) deg2 = calc_regress_deg(self.am.close[offset_m:], False) deg3 = calc_regress_deg(self.am.close[-10:], False) deg_full = calc_regress_deg(self.am.close[offset:], False) wave = self.wave(self.am.close[-30:]) wave_r_sum = np.sum(wave["range"]) macd = self.am.macd(20, 40, 16) calc_data = (dict( kdj=[ round(kdj_val["k"][-1], 2), round(kdj_val["d"][-1], 2), round(kdj_val["j"][-1], 2) ], cci_20=self.am.cci(20), rsi=self.am.rsi(20), adx=self.am.adx(20), boll=self.am.boll(20, 3.4), macd=[round(macd[0], 2), round(macd[1], 2), round(macd[2], 2)], deg40_20=round(deg1, 2), deg20_0=round(deg2, 2), deg20_10=round(calc_regress_deg(self.am.close[-20:-10], False), 2), deg10_0=round(deg3, 2), deg30_15=round(calc_regress_deg(self.am.close[-30:-15], False), 2), deg15_0=round(calc_regress_deg(self.am.close[-15:], False), 2), deg_f=round(deg_full, 2), atr=round(self.am.atr(10, length=15), 3), tr=round(self.am.atr(1, length=2), 3), atr_40=round(self.am.atr(40, length=42), 3), time=bar.datetime, price=bar.close_price, ma=round(ma, 2), std_40=round(std_val, 2), mean40=round(mean_val, 2), mean_std=np.mean(self.std_range.data[-5:]), std_10=round(std_val2, 2), mean30_10=round(mean_val4, 2), mean10=round(mean_val2, 2), vol=self.am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=self.am.range[-1:-5:-1].tolist(), range_sum=np.sum(self.am.range[-5:]), pattern=list( map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())), ma120t=self.ma120_track, ma120t_list=self.ma120_track_list[-1:-10:-1], ma120t_sort=sorted(self.ma120_track_list[-20:-1], key=abs), ma120t_sum=np.sum(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_mean=np.mean(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_std=np.std(self.ma120_track_list[-20:-1] + [self.ma120_track]), wave_cnt=len(wave), wave_r_sum=wave_r_sum, atr_mean=np.mean(self.am.atr(20, array=True, length=240)[-200:]))) return calc_data def on_strategy(self, am: ArrayManager, bar: BarData, strategy_list): calc_data = self.generate_data(bar) order_id = None if self.pos == 0: for open_strategy in strategy_list: if order_id is not None: break order_id = open_strategy(am, bar, calc_data) else: order_id = self.positions.on_strategy(bar, calc_data) if order_id is not None: offset = -self.offset offset_m = int(offset / 2) self.tracker["trade_info"].append( (self.am.time_array[offset], self.am.time_array[offset_m], bar.datetime, calc_data["deg40_20"], calc_data["deg20_0"])) self.request_order.extend(order_id) if self.tracker is not None: self.tracker["ma_tag_ls"].append(calc_data) def on_1min_bar(self, bar: BarData): self.am.update_bar(bar) am = self.am max_len = self.ma_level[-1] + 20 data = self.am.close[-max_len:-1] ma_lvl = [] for i in self.ma_level: ma = self.am.sma(i, True)[-1] ma_lvl.append(ma) l = len(ma_lvl) ma_lvl_tag = [] now = bar.close_price direction = 1 if now > ma_lvl[0] else 0 ma_lvl_tag.append(direction) for i in range(l - 1): val = 1 if ma_lvl[i] > ma_lvl[i + 1] else 0 ma_lvl_tag.append(val) bincount_val = np.bincount(np.array(ma_lvl_tag)) tag_val = 0 if len(bincount_val) == 2: tag_val = bincount_val[1] if len(self.ma_tag) < 200: self.ma_tag.append(tag_val) else: self.ma_tag[:-1] = self.ma_tag[1:] self.ma_tag[-1] = tag_val if self.tracker is not None: self.tracker["bar_data"].append(bar) self.std_range.update(self.am.range[-1]) ma120 = self.am.sma(120) if bar.close_price >= ma120: if self.ma120_track is None: self.ma120_track = 1 elif self.ma120_track > 0: self.ma120_track += 1 else: self.ma120_track_list.append(self.ma120_track) self.ma120_track = 1 elif bar.close_price < ma120: if self.ma120_track is None: self.ma120_track = -1 elif self.ma120_track < 0: self.ma120_track -= 1 else: self.ma120_track_list.append(self.ma120_track) self.ma120_track = -1 if not am.inited or not self.trading: return self.on_strategy(am, bar, self.open_strategy["1"]) # median_val = np.median(calc_nums) self.put_event() def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg3.update_bar(bar) self.bg5.update_bar(bar) self.bg.update_bar(bar) # def init_order_data(self): # self.order_data = np.array([]) def on_order(self, order: OrderData): """ Callback of new order data update. """ print("{}产生了{},价格为{},笔数为{},交易{},pos={}".format( order.datetime.strftime("%m/%d %H:%M:%S"), order.offset.value + order.direction.value, order.price, order.volume, order.status.value, self.pos)) if order.vt_orderid in self.request_order: self.positions.on_order(order) if order.status == Status.ALLTRADED or order.status == Status.CANCELLED or order.status == Status.REJECTED: self.request_order.remove(order.vt_orderid) # if order.status == Status.ALLTRADED or order.status == Status.PARTTRADED: # if order.direction == Direction.LONG: # if self.positions.volumn == 0: # self.positions.close_price = round(order.price * 0.995) # self.positions.volumn += order.volume # elif order.direction == Direction.SHORT: # self.positions.volumn -= order.volume # elif order.direction == Direction.NET: # self.positions.volumn = order.volume def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class TurtleSignalStrategy(CtaTemplate): """""" author = "用Python的交易员" entry_window = 20 exit_window = 10 atr_window = 20 fixed_size = 1 entry_up = 0 entry_down = 0 exit_up = 0 exit_down = 0 atr_value = 0 long_entry = 0 short_entry = 0 long_stop = 0 short_stop = 0 parameters = ["entry_window", "exit_window", "atr_window", "fixed_size"] variables = ["entry_up", "entry_down", "exit_up", "exit_down", "atr_value"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(TurtleSignalStrategy, self).__init__( cta_engine, strategy_name, vt_symbol, setting ) self.bg = BarGenerator(self.on_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(20) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.cancel_all() self.am.update_bar(bar) if not self.am.inited: return self.entry_up, self.entry_down = self.am.donchian(self.entry_window) self.exit_up, self.exit_down = self.am.donchian(self.exit_window) if not self.pos: self.atr_value = self.am.atr(self.atr_window) self.long_entry = 0 self.short_entry = 0 self.long_stop = 0 self.short_stop = 0 self.send_buy_orders(self.entry_up) self.send_short_orders(self.entry_down) elif self.pos > 0: self.send_buy_orders(self.long_entry) sell_price = max(self.long_stop, self.exit_down) self.sell(sell_price, abs(self.pos), True) elif self.pos < 0: self.send_short_orders(self.short_entry) cover_price = min(self.short_stop, self.exit_up) self.cover(cover_price, abs(self.pos), True) self.put_event() def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price self.long_stop = self.long_entry - 2 * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + 2 * self.atr_value def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def send_buy_orders(self, price): """""" t = self.pos / self.fixed_size if t < 1: self.buy(price, self.fixed_size, True) if t < 2: self.buy(price + self.atr_value * 0.5, self.fixed_size, True) if t < 3: self.buy(price + self.atr_value, self.fixed_size, True) if t < 4: self.buy(price + self.atr_value * 1.5, self.fixed_size, True) def send_short_orders(self, price): """""" t = self.pos / self.fixed_size if t > -1: self.short(price, self.fixed_size, True) if t > -2: self.short(price - self.atr_value * 0.5, self.fixed_size, True) if t > -3: self.short(price - self.atr_value, self.fixed_size, True) if t > -4: self.short(price - self.atr_value * 1.5, self.fixed_size, True)
class Mike_Dc_Strategy(CtaTemplate): """""" author = "yunya" exchange : Exchange = "" mike_window = 1 mike_length = 30 dc_length = 10 kk_length = 20 kk_dev = 2.0 sl_trade = 2 fixed_size = 1 ask = 0 bid = 0 ema_mid = 0 ema_hh = 0 ema_ll = 0 ema_wr = 0 #初级压力线 ema_mr = 0 #中级压力线 ema_sr = 0 #高级压力线 ema_ws = 0 #初级支撑线 ema_ms = 0 #中级支撑线 ema_ss = 0 #高级支撑线 dc_up = 0 dc_down = 0 kk_up = 0 kk_down = 0 atr_value = 0 long_stop = 0 short_stop = 0 long_stop_trade = 0 short_stop_trade = 0 long_enrty = 0 short_enrty = 0 ema_entry_crossover = 0 boll_entry_crossover = 0 boll_width = 0 parameters = [ "exchange", "mike_window", "mike_length", "dc_length", "kk_length", "kk_dev", "sl_trade", "fixed_size", ] variables = [ "long_stop", "short_stop", "ema_entry_crossover", "boll_entry_crossover", "boll_width", "ema_mid", "ema_hh", "ema_ll", "ema_wr", "ema_mr", "ema_sr", "ema_ws", "ema_ms", "ema_ss", ] def __init__(self, cta_engine, strategy_nam_xhoure, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_nam_xhoure, vt_symbol, setting) self.bg_xhour = BarGenerator( on_bar=self.on_bar, window=self.mike_window, on_window_bar=self.on_hour_bar, interval=Interval.HOUR ) self.am_xhour = ArrayManager(max(self.dc_length ,self.kk_length) + 10) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.exchange_load_bar(self.exchange) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg_xhour.update_tick(tick) self.ask = tick.ask_price_1 # 卖一价 self.bid = tick.bid_price_1 # 买一价 def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg_xhour.update_bar(bar) def on_hour_bar(self, bar: BarData): """ 计算 mike 指标线 :param_xhour bar: :return: """ self.am_xhour.update_bar(bar) if not self.am_xhour.inited: return # 计算mike压力支撑线 ema_array = (self.am_xhour.close[:-1] + self.am_xhour.high[:-1] + self.am_xhour.low[:-1]) / 3 self.ema_mid = ema_array[-1] self.ema_hh = self.am_xhour.high[-self.mike_length:-1].max() self.ema_ll = self.am_xhour.low[-self.mike_length:-1].min() self.ema_wr = self.ema_mid + (self.ema_mid - self.ema_ll) self.ema_mr = self.ema_mid + (self.ema_hh - self.ema_ll) self.ema_sr = 2 * self.ema_hh - self.ema_ll self.ema_ws = self.ema_mid - (self.ema_hh - self.ema_mid) self.ema_ms = self.ema_mid - (self.ema_hh - self.ema_ll) self.ema_ss = 2 * self.ema_ll - self.ema_hh if (self.am_xhour.close[-1] > self.ema_sr) or (self.ema_ms < self.am_xhour.close[-1] < self.ema_ws): self.ema_entry_crossover = 1 elif (self.am_xhour.close[-1] < self.ema_ss) or (self.ema_mr > self.am_xhour.close[-1] > self.ema_wr): self.ema_entry_crossover = -1 self.kk_up,self.kk_down = self.am_xhour.keltner(self.kk_length,self.kk_dev) self.dc_up,self.dc_down = self.am_xhour.donchian(self.dc_length) if self.pos == 0: self.atr_value = self.am_xhour.atr(30) if self.ema_entry_crossover > 0 : self.buy(self.kk_up, self.fixed_size,True) print(self.kk_up) elif self.ema_entry_crossover < 0 : self.short(self.kk_down, self.fixed_size,True) elif self.pos > 0: self.long_stop = max(self.dc_down,self.long_stop_trade) self.sell(self.long_stop, abs(self.pos), True) elif self.pos < 0: self.short_stop = min(self.dc_up,self.short_stop_trade) self.cover(self.short_stop, abs(self.pos), True) self.sync_data() self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ pass # self.write_log(f"on_order: status:{order.status}, orderid: {order.vt_orderid}, offset:{order.offset}, price:{order.price}, volume:{order.volume}, traded: {order.traded}") # self.put_event() def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ # if trade.direction == Direction.LONG: # self.long_enrty = trade.price # self.long_stop_trade = self.long_enrty - 2 * self.atr_value # # else: # self.short_enrty = trade.price # self.short_stop_trade = self.short_enrty + 2 * self.atr_value self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def exchange_load_bar(self,exchange:Exchange): """ 如果是火币,ok 交易所,就从数据库获取初始化数据 """ if exchange == Exchange.OKEX or exchange == Exchange.HUOBI: self.load_bar(days=10,use_database=True) else: self.load_bar(10)
class ReverseCatchStrategy(CtaTemplate): author = "用Python的交易员" ma_level = [5, 10, 20, 30, 120] ma_tag = [] bd = [] fast_ma0 = 0.0 fast_ma1 = 0.0 slow_ma0 = 0.0 slow_ma1 = 0.0 request_order = [] bar_identify = [] volumn = 0 kdj_record = [] parameters = ["ma_level"] variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"] add_pos = False safe_price = None trend_record = MaTrendRecord def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(ReverseCatchStrategy, self).__init__( cta_engine, strategy_name, vt_symbol, setting ) self.bg = BarGenerator(self.on_bar, 1, self.on_1min_bar) self.am = ArrayManager(200) self.am3 = ArrayManager(150) self.bg3 = BarGenerator(self.on_bar, 3, self.on_3min_bar) self.am5 = ArrayManager(120) self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.order_data = None self.positions = CloseoutPosition(self, {"closeout_offset": 0.003}) self.std_range = IntervalGen(np.std,5) self.std_range3 = IntervalGen(np.std,5) self.std_range5 = IntervalGen(np.std,5) self.pattern_record = PatternRecord() # self.pattern_record.set_expiry([KlinePattern.CDLEVENINGSTAR], 3) self.pattern_record.set_expiry(list(KlinePattern), 1) self.ma_info = [] five_min_open_5 = partial(self.reverse_shape_strategy, setting={"len":20, "atr":10, "atr_valve":0.8, "mid_sign":(7,14)}) self.open_strategy = { "1":[five_min_open_5], } self.offset = 40 self.ma120_track = None self.ma120_track_list = [] def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(5) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") self.put_event() def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") self.put_event() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) self.bg3.update_tick(tick) self.bg5.update_tick(tick) def on_3min_bar(self, bar: BarData): self.am3.update_bar(bar) self.std_range3.update(self.am3.range[-1]) if not self.am.inited or not self.trading: return pattern = self.am3.pattern([KlinePattern.CDLEVENINGSTAR, KlinePattern.CDL2CROWS]) if len(pattern) > 0: print(pattern) self.pattern_record.add_pattern(pattern) # deg = calc_regress_deg(self.am3.close[-20:]) def wave(self, data, window = 0.0002): if len(data) <= 0: return # r = array[::-1] result = { "value":[], "range":[], "pos":[], "length":[]} r = data l = len(data) - 1 now = r[0] # v_list.append(now) # p_list.append(0) pos = 1 vol = 0 u_tag = None d_tag = None end_tag = None start_pos = 0 while pos < l: if math.isnan(now): now = r[pos] pos += 1 continue else: start_pos = pos - 1 break while pos < l: if now < r[pos]: u_tag = pos if d_tag: diff = r[start_pos] - r[d_tag] if abs(diff / r[start_pos]) > window and d_tag - start_pos > 4: end_tag = d_tag elif now > r[pos]: d_tag = pos if u_tag: diff = r[start_pos] - r[u_tag] if abs(diff / r[start_pos]) > window and d_tag - start_pos > 4: end_tag = u_tag if end_tag is not None: result["range"].append(r[end_tag] / r[start_pos] - 1) result["length"].append(end_tag - start_pos) start_pos = end_tag result["value"].append(r[end_tag]) result["pos"].append(end_tag) end_tag = None vol += r[pos] - now now = r[pos] pos += 1 return pd.DataFrame(result) def mode_identify(self, bar: BarData): self.bar_identify = [] hl_scale = round(bar.high_price / bar.low_price - 1, 4) if hl_scale > 0.001: diff = bar.high_price - bar.low_price diff_up = bar.low_price + diff / 2 * 1.20 diff_down = bar.low_price + diff / 2 * 0.80 close = bar.close_price if bar.open_price < diff_up and bar.open_price > diff_down and \ bar.close_price < diff_up and bar.close_price > diff_down: if bar.close_price > bar.open_price: print("绿十字星",bar.datetime, bar.high_price,bar.low_price,diff,diff_up,diff_down, bar.open_price, bar.close_price) else: print("红十字星",bar.datetime, bar.high_price,bar.low_price,diff,diff_up,diff_down, bar.open_price, bar.close_price) def on_5min_bar(self, bar: BarData): self.std_range5.update(self.am5.range[-1]) self.am5.update_bar(bar) if not self.am.inited or not self.trading: return # self.on_strategy(self.am5, bar, self.open_strategy["5"]) # pattern_list = [KlinePattern.CDLEVENINGSTAR, KlinePattern.CDL2CROWS, KlinePattern.CDLCONCEALBABYSWALL, KlinePattern.CDLEVENINGDOJISTAR] # pattern = self.am5.pattern(list(KlinePattern)) # if len(pattern) > 0: # print(list(map(lambda x: (KLINE_PATTERN_CHINESE[x[0]],x[1]), pattern))) # self.pattern_record.add_pattern(pattern) # deg_full = calc_regress_deg(self.am.close[-40 :], False) # print("deg:",deg_full) # self.pattern_record.update() def open_v3(self, am:ArrayManager, bar:BarData): std_val2 = np.std(np.array(self.ma_tag[-10:-1])) mean_val2 = np.mean(np.array(self.ma_tag[-10:-1])) mean = np.mean(np.array(self.ma_tag[-30:-10])) if std_val2 < 0.2: if mean_val2 > 3: if mean_val2 >= (mean + 1): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif mean_val2 < 2: if mean_val2 <= (mean - 1): return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_v1(self, am:ArrayManager, bar:BarData): offset = -40 offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) mean_val = np.mean(calc_nums) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) if std_val < 1 and mean_val < 2 and self.ma_tag[-1] >= (mean_val + 2): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif std_val < 1 and mean_val > 3 and self.ma_tag[-1] <= (mean_val - 2): return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_v2(self, am:ArrayManager, bar:BarData): std_val2 = np.std(np.array(self.ma_tag[-10:-1])) mean_val2 = np.mean(np.array(self.ma_tag[-10:-1])) mean = np.mean(np.array(self.ma_tag[-30:-10])) if std_val2 < 0.2: if mean_val2 > 2.5: if mean_val2 >= (mean + 1): return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif mean_val2 < 2.5: if mean_val2 <= (mean - 1): return self.short(bar.close_price, 1, type=OrderType.MARKET) def ma_trend_strategy(self, am:ArrayManager, bar:BarData, calc_data, setting={"len":40, "atr":40, "atr_valve":0.09, "mid_sign":(10,30)}): # 60个bar后取消 if self.trend_record.std_val is not None: if len(self.trend_record.close) >= 60: self.trend_record.close = [] self.trend_record.std_val = None else: self.trend_record.close.append(bar.close_price) # 如果有新的bar,则覆盖 ma5_std = self.ma_info[-1]["ma5"] if ma5_std <= 0.16: self.trend_record.close = [] self.trend_record.std_val = ma5_std return if self.trend_record.std_val is not None and \ ma5_std > 0.8: y_fit = reg_util.regress_y_polynomial(self.trend_record.close, zoom=True) deg = calc_regress_deg(y_fit[:10], False) if deg < 0: # if k < 20 and d < 10 and j < 10: # if kdj[2] < 10: if self.pos == 0: calc_data["trade_open"] = "开空,deg={}".format(deg) return self.short(bar.close_price, 1, type=OrderType.MARKET) else: # if k > 80 and d > 90 and j > 90: # if kdj[2] > 90: if self.pos == 0: calc_data["trade_open"] = "开多,deg={}".format(deg) return self.buy(bar.close_price, 1, type=OrderType.MARKET) # v形反转捕获 def reverse_shape_strategy(self, am:ArrayManager, bar:BarData, calc_data, setting={"len":40, "atr":40, "atr_valve":0.09, "mid_sign":(10,30)}): length = setting["len"] offset1 = int(-length) offset2 = int(-(length / 2)) close = am.close deg1 = calc_regress_deg(close[offset1:offset2], False) deg2 = calc_regress_deg(close[offset2:], False) atr = self.am.atr(setting["atr"]) atr_valve = setting["atr_valve"] if atr < atr_valve: return if deg1 > 0 and deg2 > 0 or \ deg1 < 0 and deg2 < 0: return if not (abs(deg1) > 0.15 and abs(deg2) > 0.1 and (abs(deg1) + abs(deg2)) > 0.3) : return close = am.close[-length:] min_val = np.min(close) max_val = np.max(close) mid_val = max_val if deg1 > 0 else min_val mid_pos = np.where(close == mid_val)[0][0] if mid_pos < setting["mid_sign"][0] or mid_pos > setting["mid_sign"][1]: return start_val = np.min(close[:mid_pos]) if deg1 > 0 else np.max(close[:mid_pos]) start_pos = np.where(close == start_val)[0][0] l = mid_pos - start_pos # pos2 = np.where(close == min_val)[0][0] kdj = am.kdj() k = kdj["k"][-1] d = kdj["d"][-1] j = kdj["j"][-1] x_fit = reg_util.regress_y_polynomial(close[:mid_pos], zoom=True) deg1_remake = calc_regress_deg(x_fit[:abs(mid_pos)], False) y_fit = reg_util.regress_y_polynomial(close[mid_pos:], zoom=True) deg2_remake = calc_regress_deg(y_fit[:abs(mid_pos)], False) # print(start_pos, mid_pos, deg1, deg2, deg1_remake, deg2_remake, l, start_val, mid_val) cci = am.cci(20) ma60 = am.sma(60) if deg2 < 0: # if k < 20 and d < 10 and j < 10: # if kdj[2] < 10: if cci < -100 and bar.close_price < ma60: if self.pos == 0: calc_data["trade_open"] = "开空,deg={},cci={}".format(deg2, cci) return self.short(bar.close_price, 1, type=OrderType.MARKET) elif self.pos > 0: order_id_cover = self.sell(bar.close_price, abs(self.volumn), type=OrderType.MARKET) order_id_buy = self.short(bar.close_price, 1, type=OrderType.MARKET) return order_id_cover.extend(order_id_buy) else: # if k > 80 and d > 90 and j > 90: # if kdj[2] > 90: if cci > 100 and bar.close_price > ma60: if self.pos == 0: calc_data["trade_open"] = "开多,deg={},cci={}".format(deg2, cci) return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif self.pos < 0: order_id_cover = self.cover(bar.close_price, abs(self.volumn), type=OrderType.MARKET) order_id_buy = self.buy(bar.close_price, 1, type=OrderType.MARKET) return order_id_cover.extend(order_id_buy) # print("找到大v形:", deg1, deg2 ) def ma120_close(self, am:ArrayManager, bar:BarData, calc_data): if self.safe_price is None: return rg = (bar.close_price / self.buy_price) - 1 close_price = None if rg > 0.01 and self.volumn > 0: close_price = am.sma(120) elif rg < -0.01 and self.volumn < 0: close_price = am.sma(120) for lvl in self.ma_lvl[-1:]: # if len(self.order_data) < lvl: close_price = am.sma(lvl) break if close_price is None: lvl = self.ma_level[-1] close_price = am.sma(lvl) if self.volumn < 0: if bar.close_price > close_price: calc_data["trade_close"] = "平仓:到达MA均线价{}".format(close_price) return self.strategy.cover(bar.close_price, abs(self.volumn), type=OrderType.MARKET, extra= { "reason":"平仓:到达MA均线价{}".format(close_price)}) elif self.volumn > 0: if bar.close_price < close_price: calc_data["trade_close"] = "平仓:到达MA均线价{}".format(close_price) return self.strategy.sell(bar.close_price, abs(self.volumn), type=OrderType.MARKET, extra={"reason": "平仓:到达MA均线价{}".format(close_price)}) def add_position(self, am:ArrayManager, bar:BarData, calc_data, setting={}): if self.safe_price is None: return if not (self.volumn < 0 and bar.close_price < self.safe_price or \ self.volumn > 0 and bar.close_price > self.safe_price): return am = self.am rg = (bar.close_price / self.trade_price) - 1 close_price = None if rg > 0.01 and self.volumn > 0: close_price = am.sma(120) if not self.add_pos: self.add_pos = True return self.strategy.buy(bar.close_price, 50, type=OrderType.MARKET) elif rg < -0.01 and self.volumn < 0: close_price = am.sma(120) if not self.add_pos: self.add_pos = True return self.strategy.short(bar.close_price, 50, type=OrderType.MARKET) def reverse2_strategy(self, am:ArrayManager, bar:BarData, calc_data, setting={"len":40, "atr":40, "atr_valve":0.09, "mid_sign":(10,30)}): length = 30 offset1 = -30 offset2 = int(-10) close = am.close deg1 = calc_regress_deg(close[-30:-8], False) deg2 = calc_regress_deg(close[-8:], False) if deg1 > 0 and deg2 > 0 or \ deg1 < 0 and deg2 < 0: return if not (abs(deg1) > 0.15 and abs(deg2) > 0.15 and (abs(deg1) + abs(deg2)) > 0.35) : return close = am.close[-length:] min_val = np.min(close) max_val = np.max(close) mid_val = max_val if deg1 > 0 else min_val mid_pos = np.where(close == mid_val)[0][0] if mid_pos < setting["mid_sign"][0] or mid_pos > setting["mid_sign"][1]: return start_val = np.min(close[:mid_pos]) if deg1 > 0 else np.max(close[:mid_pos]) start_pos = np.where(close == start_val)[0][0] l = mid_pos - start_pos # pos2 = np.where(close == min_val)[0][0] kdj = am.kdj() k = kdj["k"][-1] d = kdj["d"][-1] j = kdj["j"][-1] x_fit = reg_util.regress_y_polynomial(close[:mid_pos], zoom=True) deg1_remake = calc_regress_deg(x_fit[:abs(mid_pos)], False) y_fit = reg_util.regress_y_polynomial(close[mid_pos:], zoom=True) deg2_remake = calc_regress_deg(y_fit[:abs(mid_pos)], False) # print(start_pos, mid_pos, deg1, deg2, deg1_remake, deg2_remake, l, start_val, mid_val) cci = am.cci(20) ma60 = am.sma(60) if deg2 < 0: # if k < 20 and d < 10 and j < 10: # if kdj[2] < 10: if cci < -100 and bar.close_price < ma60: if self.pos == 0: calc_data["trade_open"] = "开空,deg={},cci={}".format(deg2, cci) return self.short(bar.close_price, 1, type=OrderType.MARKET) elif self.pos > 0: calc_data["trade_close"] = "平多后做空仓,deg={},cci={}".format(deg2, cci) order_id_cover = self.sell(bar.close_price, abs(self.volumn), type=OrderType.MARKET) order_id_buy = self.short(bar.close_price, 1, type=OrderType.MARKET) return order_id_cover.extend(order_id_buy) else: # if k > 80 and d > 90 and j > 90: # if kdj[2] > 90: if cci > 100 and bar.close_price > ma60: if self.pos == 0: calc_data["trade_open"] = "开多,deg={},cci={}".format(deg2, cci) return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif self.pos < 0: calc_data["trade_close"] = "平空后多仓,deg={},cci={}".format(deg2, cci) order_id_cover = self.cover(bar.close_price, abs(self.volumn), type=OrderType.MARKET) order_id_buy = self.buy(bar.close_price, 1, type=OrderType.MARKET) return order_id_cover.extend(order_id_buy) def open5(self, am:ArrayManager, bar:BarData, calc_data): ma = self.ma_tag[-1] mean = calc_data["mean30_10"] atr = self.am.atr(10, array=True, length=20) tr = self.am.atr(1, array=True, length=11) # self.ma120_track ma120 = self.am.sma(120) # if std_val2 < 0.2: mean_std = calc_data["mean_std"] if mean_std < 0.8 and tr[-1] > 0.1 and tr[-1] / tr[-10] > 3 and tr[-1] / atr[-1] >= 1.7 and tr[-10] / atr[-10] < 1: if np.sum(self.am.range[-10:]) > 0 and self.ma120_track > 0: return self.buy(bar.close_price, 1, type=OrderType.MARKET) elif self.ma120_track < 0: return self.short(bar.close_price, 1, type=OrderType.MARKET) def open_kline1(self, am:ArrayManager, bar:BarData, calc_data): if KlinePattern.CDLEVENINGSTAR not in self.pattern_record: return # if std_val2 < 0.2: deg = calc_regress_deg(self.am.close[-5:], False) print("kline_strategy",deg) if deg < -0.1: return self.short(bar.close_price, 1, type=OrderType.MARKET) def generate_data(self, am:ArrayManager, bar:BarData): offset = -self.offset offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) std_val2 = np.std(np.array(self.ma_tag[-10:-1])) std_val3 = np.std(np.array(am.range[-30:-10])) ma = self.ma_tag[-1] mean_val = np.mean(calc_nums) mean_val2 = np.mean(np.array(self.ma_tag[-5:-1])) mean_val3 = np.mean(np.array(self.ma_tag[-20:-1])) mean_val4 = np.mean(np.array(self.ma_tag[-30:-5])) kdj_val = am.kdj() has_kdj_recore = False k = kdj_val["k"] d = kdj_val["d"] j = kdj_val["j"] if (k[-1] > 75 and d[-1] > 75 and j[-1] > 75) or \ (k[-1] < 25 and d[-1] < 25 and j[-1] < 75): if (j[-2] < k[-2] or j[-2] < d[-2]) and (j[-1] > k[-1] and j[-1] > d[-1]) \ or \ (j[-2] > k[-2] or j[-2] > d[-2]) and (j[-1] < k[-1] and j[-1] < d[-1]): has_kdj_recore = True t = local_to_eastern(bar.datetime.timestamp()) self.kdj_record.append((t.strftime("%H:%M:%S"), round(k[-1], 3), round(d[-1], 3), round(j[-1], 3))) deg1 = calc_regress_deg(am.close[offset : offset_m], False) deg2 = calc_regress_deg(am.close[offset_m :], False) deg3 = calc_regress_deg(am.close[-10 :], False) deg_full = calc_regress_deg(am.close[offset :], False) wave = self.wave(am.close[-30:]) wave_r_sum = np.sum(wave["range"]) macd=am.macd(20,40, 16) calc_data = (dict( ma_info=self.ma_info[-1:], kdj=[round(kdj_val["k"][-1],2),round(kdj_val["d"][-1],2),round(kdj_val["j"][-1],2)], cci_20=am.cci(20),rsi=am.rsi(20),adx=am.adx(20),boll=am.boll(20, 3.4), macd=[round(macd[0],2),round(macd[1],2),round(macd[2],2)], deg40_20=round(deg1,2), deg20_0=round(deg2,2), deg20_10=round(calc_regress_deg(am.close[-20:-10], False),2), deg30_10=round(calc_regress_deg(am.close[-30:-10], False),2),deg10_0=round(deg3,2), deg30_15=round(calc_regress_deg(am.close[-30:-15], False),2), deg15_0=round(calc_regress_deg(am.close[-15:], False),2),deg_f=round(deg_full,2), atr=round(am.atr(10, length=15), 3), tr=round(am.atr(1, length=2), 3),atr_40=round(am.atr(40, length=42), 3), time=bar.datetime, price=bar.close_price, ma=round(ma, 2), std_40=round(std_val, 2),mean40=round(mean_val,2), mean_std=np.mean(self.std_range.data[-5:]), std_10=round(std_val2,2), mean30_10=round(mean_val4,2), mean10=round(mean_val2,2), vol=am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=am.range[-1:-5:-1].tolist(), range_sum=np.sum(am.range[-5:]), pattern=list(map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())), ma120t=self.ma120_track, ma120t_list=self.ma120_track_list[-1:-10:-1], ma120t_sort=sorted(self.ma120_track_list[-20:-1], key=abs), ma120t_sum=np.sum(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_mean=np.mean(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_std=np.std(self.ma120_track_list[-20:-1] + [self.ma120_track]), wave_cnt=len(wave), wave_r_sum=wave_r_sum, atr_mean=np.mean(am.atr(20, array=True,length=240)[-200:]), kdj_record=self.kdj_record[-10:], )) if self.ma_info[-1]["ma5"] <= 0.16: calc_data["kdj_key"] = True return calc_data def generate_3mindata(self, am:ArrayManager, bar:BarData): offset = -self.offset offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) std_val2 = np.std(np.array(self.ma_tag[-10:-1])) std_val3 = np.std(np.array(am.range[-30:-10])) ma = self.ma_tag[-1] mean_val = np.mean(calc_nums) mean_val2 = np.mean(np.array(self.ma_tag[-5:-1])) mean_val3 = np.mean(np.array(self.ma_tag[-20:-1])) mean_val4 = np.mean(np.array(self.ma_tag[-30:-5])) kdj_val = am.kdj() deg1 = calc_regress_deg(am.close[offset : offset_m], False) deg2 = calc_regress_deg(am.close[offset_m :], False) deg3 = calc_regress_deg(am.close[-10 :], False) deg_full = calc_regress_deg(am.close[offset :], False) wave = self.wave(am.close[-30:]) wave_r_sum = np.sum(wave["range"]) macd=am.macd(20,40, 16) calc_data = (dict( kdj=[round(kdj_val["k"][-1],2),round(kdj_val["d"][-1],2),round(kdj_val["j"][-1],2)], cci_20=am.cci(20),rsi=am.rsi(20),adx=am.adx(20),boll=am.boll(20, 3.4), macd=[round(macd[0],2),round(macd[1],2),round(macd[2],2)], deg40_20=round(deg1,2), deg20_0=round(deg2,2), deg20_10=round(calc_regress_deg(am.close[-20:-10], False),2), deg10_0=round(deg3,2), deg30_15=round(calc_regress_deg(am.close[-30:-15], False),2), deg15_0=round(calc_regress_deg(am.close[-15:], False),2),deg_f=round(deg_full,2), atr=round(am.atr(10, length=15), 3), tr=round(am.atr(1, length=2), 3),atr_40=round(am.atr(40, length=42), 3), time=bar.datetime, price=bar.close_price, ma=round(ma, 2), std_40=round(std_val, 2),mean40=round(mean_val,2), mean_std=np.mean(self.std_range.data[-5:]), std_10=round(std_val2,2), mean30_10=round(mean_val4,2), mean10=round(mean_val2,2), vol=am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=am.range[-1:-5:-1].tolist(), range_sum=np.sum(am.range[-5:]), pattern=list(map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())), ma120t=self.ma120_track, ma120t_list=self.ma120_track_list[-1:-10:-1], ma120t_sort=sorted(self.ma120_track_list[-20:-1], key=abs), ma120t_sum=np.sum(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_mean=np.mean(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_std=np.std(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma_info=list(map(lambda x:x["std"], self.ma_info[-1:])), wave_cnt=len(wave), wave_r_sum=wave_r_sum, atr_mean=np.mean(am.atr(20, array=True,length=240)[-200:]) )) return calc_data def on_strategy(self, am:ArrayManager, bar: BarData, strategy_list, close_strategy_list, calc_data=None): order_id = None for open_strategy in strategy_list: if order_id is not None: break order_id = open_strategy(am, bar, calc_data) if order_id is None and self.pos != 0: for strategy in close_strategy_list: if order_id is not None: break order_id = strategy(am, bar, calc_data) if order_id is not None: offset = -self.offset offset_m = int(offset / 2) self.tracker["trade_info"].append(( self.am.time_array[offset], self.am.time_array[offset_m], bar.datetime, calc_data["deg40_20"], calc_data["deg20_0"])) self.request_order.extend(order_id) if self.tracker is not None: self.tracker["ma_tag_ls"].append(calc_data) def ma_info_update(self, am:ArrayManager): ma_info = {} ma_data = [] for i in self.ma_level: ma = am.sma(i) ma_info[i] = round(ma,2) ma_data.append(ma) data = [] diff = ma_data[-1] for v in ma_data: data.append(round(v / diff, 6)) ma_info["ma5"] = round(np.var(data)*1000000, 8) data = [] diff = ma_data[-3] for v in ma_data[:-2]: data.append(round(v / diff, 6)) ma_info["ma3"] = round(np.var(data)*1000000, 8) if len(self.ma_info) < 500: self.ma_info.append(ma_info) else: self.ma_info[:-1] = self.ma_info[1:] self.ma_info[-1] = ma_info def on_1min_bar(self, bar: BarData): self.am.update_bar(bar) am = self.am max_len = self.ma_level[-1] + 20 data = self.am.close[-max_len:-1] ma_lvl = [] for i in self.ma_level: ma = self.am.sma(i, True)[-1] ma_lvl.append(ma) l = len(ma_lvl) ma_lvl_tag = [] now = bar.close_price direction = 1 if now > ma_lvl[0] else 0 ma_lvl_tag.append(direction) for i in range(l-1): val = 1 if ma_lvl[i] > ma_lvl[i+1] else 0 ma_lvl_tag.append(val) bincount_val = np.bincount(np.array(ma_lvl_tag)) tag_val = 0 if len(bincount_val) == 2: tag_val = bincount_val[1] if len(self.ma_tag) < 200: self.ma_tag.append(tag_val) else: self.ma_tag[:-1] = self.ma_tag[1:] self.ma_tag[-1] = tag_val if self.tracker is not None: self.tracker["bar_data"].append(bar) self.std_range.update(self.am.range[-1]) ma120 = self.am.sma(120) if bar.close_price >= ma120: if self.ma120_track is None: self.ma120_track = 1 elif self.ma120_track > 0: self.ma120_track += 1 else: self.ma120_track_list.append(self.ma120_track) self.ma120_track = 1 elif bar.close_price < ma120: if self.ma120_track is None: self.ma120_track = -1 elif self.ma120_track < 0: self.ma120_track -= 1 else: self.ma120_track_list.append(self.ma120_track) self.ma120_track = -1 if not am.inited or not self.trading: return self.ma_info_update(am) calc_data = self.generate_data(am, bar) five_min_open_5 = partial(self.reverse_shape_strategy, setting={"len":20, "atr":10, "atr_valve":0.8, "mid_sign":(7,14)}) open_strategy = [self.reverse_shape_strategy, self.add_position] close_strategy = [self.positions.on_bar, self.ma120_close] self.on_strategy(am, bar, open_strategy, close_strategy, calc_data) # median_val = np.median(calc_nums) self.put_event() def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg3.update_bar(bar) self.bg5.update_bar(bar) self.bg.update_bar(bar) # def init_order_data(self): # self.order_data = np.array([]) def on_order(self, order: OrderData): """ Callback of new order data update. """ print("{}产生了{},价格为{},笔数为{},交易{},pos={}".format(order.datetime.strftime("%m/%d %H:%M:%S"), order.offset.value + order.direction.value,order.price, order.volume, order.status.value, self.pos)) if order.vt_orderid in self.request_order: if order.status == Status.ALLTRADED or order.status == Status.CANCELLED or order.status == Status.REJECTED: self.request_order.remove(order.vt_orderid) def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.vt_orderid in self.request_order: self.positions.on_trade(trade) if self.volumn == 0: self.add_pos = False if trade.direction == Direction.LONG: self.safe_price = trade.price * 1.003 self.volumn += trade.volume elif trade.direction == Direction.SHORT: self.safe_price = trade.price * 0.997 self.volumn -= trade.volume self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class DudlThrustEmaPositionStrategy(CtaTemplate): """""" author = "yunyu" open_window = 5 xminute_window = 30 rolling_period = 70 upper_open = 0.45 lower_open = 0.45 cci_length = 5 ema_length = 60 position_atr_length = 6 risk_level = 1000 # fixed_size = 1 trading_size = 0 atr_value = 0 up = 0 down = 0 current_ema = 0 last_ema = 0 ema_mid = 0 ema_new_value = 0 ema_length_new = 0 cci_value = 0 exit_long_nex = 0 exit_long_last = 0 exit_short_nex = 0 exit_short_last = 0 current_close = 0 last_close = 0 front_close = 0 exit_long = 0 exit_short = 0 ask = 0 bid = 0 parameters = [ "open_window", "xminute_window", "rolling_period", "upper_open", "lower_open", "cci_length", "ema_length", "position_atr_length", "risk_level" ] variables = [ "trading_size", "up", "down", "current_ema", "last_ema", "ema_mid", "ema_new_value", "ema_length_new", "cci_value", "exit_long_nex", "exit_long_last", "exit_short_nex", "exit_short_last", "current_close", "last_close", "front_close", "exit_long", "exit_short", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg_open = BarGenerator(on_bar=self.on_bar, window=self.open_window, on_window_bar=self.on_open_bar) self.am_open = ArrayManager() self.bg = NewBarGenerator(on_bar=self.on_bar, window=self.xminute_window, on_window_bar=self.on_xmin_bar) self.am = ArrayManager(self.rolling_period + 50) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) self.ask = tick.ask_price_1 # 卖一价 self.bid = tick.bid_price_1 # 买一价 def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) self.bg_open.update_bar(bar) def on_open_bar(self, bar: BarData): """ Callback of new bar data update. """ self.cancel_all() self.am_open.update_bar(bar) if not self.am.inited or not self.am_open.inited: return if self.pos == 0: self.cci_value = self.am.cci(self.cci_length) # 判断数据是否正常,如果atr 计算结果正常,才计算仓位,避免下单时下出不正常的数量 self.atr_value = self.am.atr(self.position_atr_length) if self.atr_value == 0: return self.trading_size = max(int(self.risk_level / self.atr_value), 1) if self.cci_value > 0: self.buy(self.up, self.trading_size, True) elif self.cci_value < 0: self.short(self.down, self.trading_size, True) elif self.pos > 0: con1 = bar.close_price < self.current_ema con2 = bar.close_price >= self.last_ema if con1 and con2: self.exit_long_nex = bar.close_price # 保存当前收盘价 if self.exit_long_last == 0 or self.exit_long_nex > self.exit_long_last: self.exit_long_last = self.exit_long_nex self.ema_length_new = self.ema_length self.exit_long = self.ema_mid else: if bar.close_price > ( (self.ema_mid + self.current_ema) / 2): self.exit_long = bar.close_price elif bar.close_price < self.ema_mid: self.exit_long = bar.close_price else: self.exit_long = self.ema_mid else: self.exit_long = self.ema_mid self.sell(self.exit_long, abs(self.pos), True) elif self.pos < 0: con1 = bar.close_price > self.current_ema con2 = bar.close_price <= self.last_ema if con1 and con2: self.exit_short_nex = bar.close_price if self.exit_short_last == 0 or self.exit_short_nex < self.exit_short_last: self.exit_short_last = self.exit_short_nex self.ema_length_new = self.ema_length self.exit_short = self.ema_mid else: if bar.close_price < (self.ema_mid + self.current_ema / 2): self.exit_short = bar.close_price elif bar.close_price < self.ema_mid: self.exit_short = bar.close_price else: self.exit_short = self.ema_mid else: self.exit_short = self.ema_mid self.cover(self.exit_short, abs(self.pos), True) self.put_event() self.sync_data() def on_xmin_bar(self, bar: BarData): """ Callback of new bar data update. """ self.am.update_bar(bar) if not self.am.inited: return # 计算海龟 上轨,下轨 high_max = self.am.high[-self.rolling_period:].max() close_min = self.am.close[-self.rolling_period:].min() close_max = self.am.close[-self.rolling_period:].max() low_min = self.am.low[-self.rolling_period:].min() hc = high_max - close_min cl = close_max - low_min dual = max(hc, cl) self.up = self.am.open[-2] + dual * self.upper_open self.down = self.am.open[-2] - dual * self.upper_open # print(f"up:{self.up},{self.down}") self.current_close = self.am.close[-1] self.last_close = self.am.close[-2] self.front_close = self.am.close[-3] if self.pos == 0: self.exit_long_nex = 0 self.exit_long_last = 0 self.exit_short_nex = 0 self.exit_short_last = 0 self.ema_length_new = self.ema_length elif self.pos > 0: close_long = self.current_close > self.last_close > self.front_close if close_long: self.ema_length_new -= 1 self.ema_length_new = max(self.ema_length_new, 5) elif self.pos < 0: close_short = self.current_close < self.last_close < self.front_close if close_short: self.ema_length_new -= 1 self.ema_length_new = max(self.ema_length_new, 5) self.ema_mid = self.am.ema(self.ema_length) ema_mid_new = self.am.ema(self.ema_length_new, True) self.current_ema = ema_mid_new[-1] self.last_ema = ema_mid_new[-2] def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass # self.put_event() def market_order(self): """""" pass # self.buy(self.last_tick.limit_up, 1) # self.write_log("执行市价单测试") def limit_order(self): """""" pass # self.buy(self.last_tick.limit_down, 1) # self.write_log("执行限价单测试") def stop_order(self): """""" pass
def generate_data(self, am:ArrayManager, bar:BarData): offset = -self.offset offset_m = int(offset / 2) calc_nums = np.array(self.ma_tag[-offset:-1]) # var_val = np.var(calc_nums) std_val = np.std(calc_nums) std_val2 = np.std(np.array(self.ma_tag[-10:-1])) std_val3 = np.std(np.array(am.range[-30:-10])) ma = self.ma_tag[-1] mean_val = np.mean(calc_nums) mean_val2 = np.mean(np.array(self.ma_tag[-5:-1])) mean_val3 = np.mean(np.array(self.ma_tag[-20:-1])) mean_val4 = np.mean(np.array(self.ma_tag[-30:-5])) kdj_val = am.kdj() has_kdj_recore = False k = kdj_val["k"] d = kdj_val["d"] j = kdj_val["j"] if (k[-1] > 75 and d[-1] > 75 and j[-1] > 75) or \ (k[-1] < 25 and d[-1] < 25 and j[-1] < 75): if (j[-2] < k[-2] or j[-2] < d[-2]) and (j[-1] > k[-1] and j[-1] > d[-1]) \ or \ (j[-2] > k[-2] or j[-2] > d[-2]) and (j[-1] < k[-1] and j[-1] < d[-1]): has_kdj_recore = True t = local_to_eastern(bar.datetime.timestamp()) self.kdj_record.append((t.strftime("%H:%M:%S"), round(k[-1], 3), round(d[-1], 3), round(j[-1], 3))) deg1 = calc_regress_deg(am.close[offset : offset_m], False) deg2 = calc_regress_deg(am.close[offset_m :], False) deg3 = calc_regress_deg(am.close[-10 :], False) deg_full = calc_regress_deg(am.close[offset :], False) wave = self.wave(am.close[-30:]) wave_r_sum = np.sum(wave["range"]) macd=am.macd(20,40, 16) calc_data = (dict( ma_info=self.ma_info[-1:], kdj=[round(kdj_val["k"][-1],2),round(kdj_val["d"][-1],2),round(kdj_val["j"][-1],2)], cci_20=am.cci(20),rsi=am.rsi(20),adx=am.adx(20),boll=am.boll(20, 3.4), macd=[round(macd[0],2),round(macd[1],2),round(macd[2],2)], deg40_20=round(deg1,2), deg20_0=round(deg2,2), deg20_10=round(calc_regress_deg(am.close[-20:-10], False),2), deg30_10=round(calc_regress_deg(am.close[-30:-10], False),2),deg10_0=round(deg3,2), deg30_15=round(calc_regress_deg(am.close[-30:-15], False),2), deg15_0=round(calc_regress_deg(am.close[-15:], False),2),deg_f=round(deg_full,2), atr=round(am.atr(10, length=15), 3), tr=round(am.atr(1, length=2), 3),atr_40=round(am.atr(40, length=42), 3), time=bar.datetime, price=bar.close_price, ma=round(ma, 2), std_40=round(std_val, 2),mean40=round(mean_val,2), mean_std=np.mean(self.std_range.data[-5:]), std_10=round(std_val2,2), mean30_10=round(mean_val4,2), mean10=round(mean_val2,2), vol=am.volume[-1], std_range=self.std_range.data[-1:-5:-1], range=am.range[-1:-5:-1].tolist(), range_sum=np.sum(am.range[-5:]), pattern=list(map(lambda x: KLINE_PATTERN_CHINESE[x], self.pattern_record.keys())), ma120t=self.ma120_track, ma120t_list=self.ma120_track_list[-1:-10:-1], ma120t_sort=sorted(self.ma120_track_list[-20:-1], key=abs), ma120t_sum=np.sum(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_mean=np.mean(self.ma120_track_list[-20:-1] + [self.ma120_track]), ma120t_std=np.std(self.ma120_track_list[-20:-1] + [self.ma120_track]), wave_cnt=len(wave), wave_r_sum=wave_r_sum, atr_mean=np.mean(am.atr(20, array=True,length=240)[-200:]), kdj_record=self.kdj_record[-10:], )) if self.ma_info[-1]["ma5"] <= 0.16: calc_data["kdj_key"] = True return calc_data
class SuperTurtleStrategyHNTest(CtaTemplate): """""" author = "Huang Ning" entry_window = 28 exit_window = 7 atr_window = 4 risk_level = 0.2 trading_size = 0 entry_up = 0 entry_down = 0 exit_up = 0 exit_down = 0 atr_value = 0 long_entry = 0 short_entry = 0 long_stop = 0 short_stop = 0 parameters = ["entry_window", "exit_window", "atr_window", "risk_level"] variables = [ "entry_up", "entry_down", "exit_up", "exit_down", "trading_size", "atr_value" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar, 1, self.on_hour_bar, interval=Interval.HOUR) self.am = ArrayManager() def on_init(self): """""" self.write_log("策略初始化") self.load_bar(20) def on_start(self): """""" self.write_log("策略启动") def on_stop(self): """""" self.write_log("策略停止") def on_tick(self, tick: TickData): """""" self.bg.update_tick(tick) def on_bar(self, bar: BarData): """""" self.bg.update_bar(bar) def on_hour_bar(self, bar: BarData): """""" self.am.update_bar(bar) if not self.am.inited: return self.entry_up, self.entry_down = self.am.donchian(self.entry_window) self.exit_up, self.exit_down = self.am.donchian(self.exit_window) if not self.pos: self.atr_value = self.am.atr(self.atr_window) if self.atr_value == 0: return atr_risk = talib.ATR(1 / self.am.high, 1 / self.am.low, 1 / self.am.close, self.atr_window)[-1] self.trading_size = max(int(self.risk_level / atr_risk), 1) self.long_entry = 0 self.short_entry = 0 self.long_stop = 0 self.short_stop = 0 self.buy(self.entry_up, self.trading_size, True) self.short(self.entry_down, self.trading_size, True) elif self.pos > 0: sell_price = max(self.long_stop, self.exit_down) self.sell(sell_price, abs(self.pos), True) elif self.pos < 0: cover_price = min(self.short_stop, self.exit_up) self.cover(cover_price, abs(self.pos), True) self.put_event() def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price self.long_stop = self.long_entry - 2 * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + 2 * self.atr_value self.sync_data() def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class TurtleFluidSizeStrategy(CtaTemplate): """""" # 改版海龟信号-ma出场-rsi过滤-atr浮动手数 author = "turtle_fluid_size" entry_window = 50 exit_window = 20 atr_window = 20 stop_multiple = 10 long_rsi = 50 short_rsi = 50 fixed_size = 1 entry_up = 0 entry_down = 0 exit_up = 0 exit_down = 0 atr_value = 0 long_entry = 0 short_entry = 0 long_stop = 0 short_stop = 0 fluid_size = 1 symbol_size = 1 risk_percent = 0.002 risk_capital = 1000000 parameters = [ "entry_window", "exit_window", "atr_window", "fixed_size", "stop_multiple", "long_rsi", "short_rsi", "symbol_size", "risk_percent", "risk_capital" ] variables = [ "entry_up", "entry_down", "exit_up", "exit_down", "atr_value", "fluid_size" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) print(self.symbol_size, self.risk_percent, self.risk_capital) self.bg = BarGenerator(self.on_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(20) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.cancel_all() self.am.update_bar(bar) if not self.am.inited: return # Only calculates new entry channel when no position holding if not self.pos: self.entry_up, self.entry_down = self.am.donchian( self.entry_window) self.exit_up = self.exit_down = self.am.sma(self.exit_window) self.rsi_value = self.am.rsi(self.entry_window) if not self.pos: self.atr_value = self.am.atr(self.atr_window) risk_amount = self.risk_capital * self.risk_percent atr_amount = self.atr_value * self.symbol_size self.fluid_size = round(risk_amount / atr_amount) * self.fixed_size self.long_entry = 0 self.short_entry = 0 self.long_stop = 0 self.short_stop = 0 if self.fluid_size and self.rsi_value > self.long_rsi: self.send_buy_orders(self.entry_up) if self.fluid_size and self.rsi_value <= self.short_rsi: self.send_short_orders(self.entry_down) elif self.pos > 0: sell_price = max(self.long_stop, self.exit_down) self.sell(sell_price, abs(self.pos), True) elif self.pos < 0: cover_price = min(self.short_stop, self.exit_up) self.cover(cover_price, abs(self.pos), True) self.put_event() def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price self.long_stop = self.long_entry - self.stop_multiple * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + self.stop_multiple * self.atr_value def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def send_buy_orders(self, price): """""" self.buy(price, self.fluid_size, True) def send_short_orders(self, price): """""" self.short(price, self.fluid_size, True)
class Boll_Kc_Dc_Reverse_Strategy(CtaTemplate): """ 本策略为反向策略,币本位 Reverse 反向 """ author = "yunya" open_window = 2 xsmall_window = 15 com_length = 250 boll_kk_dev = 2.0 kk_atr_length = 30 sl_multiplier = 0.5 risk_level = 10000 trading_size = 0 xsmall_up_min = 0 xsmall_down_min = 0 xsmall_up_max = 0 xsmall_down_max = 0 xsmall_ema_mid = 0 xsmall_com_width = 0 long_entry = 0 short_entry = 0 long_stop = 0 short_stop = 0 exit_up = 0 exit_down = 0 atr_value = 0 intra_trade_high = 0 intra_trade_low = 0 parameters = [ "open_window", "xsmall_window", "com_length", "boll_kk_dev", "kk_atr_length", "sl_multiplier", "risk_level", ] variables = [ "trading_size", "xsmall_up_min", "xsmall_down_min", "xsmall_up_max", "xsmall_down_max", "xsmall_ema_mid", "xsmall_com_width", "long_entry", "short_entry", "long_stop", "short_stop", "exit_up", "exit_down", "atr_value", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg_xsmall = BarGenerator( on_bar=self.on_bar, window=self.xsmall_window, on_window_bar=self.on_xsmall_bar, interval=Interval.MINUTE ) self.am_xsmall = ArrayManager(self.com_length + 10) self.bg = BarGenerator(self.on_bar, self.open_window, self.on_open_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg_xsmall.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) self.bg_xsmall.update_bar(bar) def on_open_bar(self,bar:BarData): """ :param bar: :return: """ # 先使用挂单全撤的粗化订单管理 self.cancel_all() self.am.update_bar(bar) if not self.am_xsmall.inited or not self.am.inited: return if self.pos == 0: # 根据布林带宽度动态调整仓位大小 self.trading_size = max(int(self.risk_level / self.xsmall_com_width), 1) self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price # 如果价格突破 xsmall_up_min 线时,在xsmall_up_max 价格挂停止单 if self.am_xsmall.close[-1] >= self.xsmall_up_min and self.am.close[-1] >=self.xsmall_up_min: self.buy(self.xsmall_up_max,self.trading_size,True) # 如果价格突破 xsmall_down_min 线时,在xsmall_down_max 价格挂停止单 elif self.am_xsmall.close[-1] <= self.xsmall_down_min and self.am.close[-1] <= self.xsmall_down_min: self.short(self.xsmall_down_max,self.trading_size,True) elif self.pos > 0: # 成交价固定止损位与中轨中最大值为当前止损位 # self.exit_up = max(self.xsmall_ema_mid,self.long_stop) # 成交价回定止损 与最高价回撤一定比例通道宽度值 self.intra_trade_high = max(self.intra_trade_high,bar.high_price) self.intra_trade_low = bar.low_price exit_long_stop = self.intra_trade_high - self.xsmall_com_width * self.sl_multiplier self.exit_up = max(exit_long_stop,self.long_stop) self.sell(self.exit_up,abs(self.pos),True) elif self.pos < 0: # 成交价固定止损位与中轨中最小值为当前止损位 # self.exit_down = min(self.xsmall_ema_mid,self.short_stop) # 成交价回定止损 与最高价回撤一定比例通道宽度值 self.intra_trade_high = bar.high_price self.intra_trade_low = min(self.intra_trade_low,bar.low_price) exit_short_stop = self.intra_trade_low - self.xsmall_com_width * self.sl_multiplier self.exit_down = min(exit_short_stop,self.short_stop) self.cover(self.exit_down,abs(self.pos),True) self.sync_data() self.put_event() def on_xsmall_bar(self, bar: BarData): """ :param bar: :return: """ # x分钟 多策略合合成的通道线 self.am_xsmall.update_bar(bar) if not self.am_xsmall.inited : return self.xsmall_ema_mid,self.xsmall_com_width,self.xsmall_up_min, self.xsmall_down_min,\ self.xsmall_up_max, self.xsmall_down_max = self.boll_kc_dc_combination( high=self.am_xsmall.high[:-1], low=self.am_xsmall.low[:-1], close=self.am_xsmall.close[:-1], boll_kk_dev=self.boll_kk_dev, kk_atr_length=self.kk_atr_length, com_length=self.com_length ) # print(f"xsmall: mid:{self.xsmall_ema_mid},width:{self.xsmall_com_width},upmin:{self.xsmall_up_min},\ # downmin:{self.xsmall_down_min},upmax:{self.xsmall_up_max},downmax:{self.xsmall_down_max}" + "\n") self.atr_value = self.am_xsmall.atr(self.kk_atr_length) self.sync_data() self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price # 成交最高价 self.long_stop = self.long_entry - 2 * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + 2 * self.atr_value self.sync_data() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def boll_kc_dc_combination(self, high, close, low, boll_kk_dev,kk_atr_length,com_length): # 计算组合均线 ema_com = talib.EMA(close, com_length) # 计算布林带 boll_std = talib.STDDEV(close, com_length) boll_up = ema_com + boll_kk_dev * boll_std boll_down = ema_com - boll_kk_dev * boll_std # 计算肯特通道 kc_atr = talib.ATR(high, low, close, kk_atr_length) kc_up = ema_com + kc_atr * boll_kk_dev kc_dowm = ema_com - kc_atr * boll_kk_dev # 计算唐安奇通道 dc_up = talib.MAX(high, com_length) dc_down = talib.MIN(low, com_length) # 计算轨道 因kc通道是直接,最小值大概率是直接,所以去除 pass_up_min = min(dc_up[-1], boll_up[-1]) pass_down_min = max(dc_down[-1], boll_down[-1]) pass_up_max = max(kc_up[-1], dc_up[-1], boll_up[-1]) pass_down_max = min(kc_dowm[-1], dc_down[-1], boll_down[-1]) ema_mid = ema_com[-1] com_width = abs(pass_up_max - pass_down_max) return ema_mid, com_width, pass_up_min, pass_down_min, pass_up_max, pass_down_max
class AtrStop_Ut(CtaTemplate): """""" author = "yunya" atrstop_window = 46 open_window = 5 nloss_singnal = 2.7 trailing_tax = 2.0 risk_level = 5000 exit_dc_length = 50 atr_length = 30 atrstop_entry = 0 current_atr_stop = 0.0 last_atr_stop = 0.0 intra_trade_high = 0 intra_trade_low = 0 nloss_array = 0.0 long_stop = 0 short_stop = 0 trading_size = 0 exit_down = 0 exit_up = 0 ask = 0 bid = 0 atr_value = 0 count = 0 parameters = [ "atrstop_window", "open_window", "nloss_singnal", "trailing_tax", "risk_level", "exit_dc_length", "atr_length" ] variables = [ "atrstop_entry", "current_atr_stop", "last_atr_stop", "intra_trade_high", "intra_trade_low", "long_stop", "short_stop", "exit_down", "exit_up", "trading_size", ] def __init__( self, cta_engine: Any, strategy_name: str, vt_symbol: str, setting: dict, ): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.atr_stop_array = np.zeros(10) self.bg_xmin = NewBarGenerator(self.on_bar, window=self.atrstop_window, on_window_bar=self.on_xmin_bar, interval=Interval.MINUTE) self.am_xmin = ArrayManager() self.bg_5min = BarGenerator(self.on_bar, window=self.open_window, on_window_bar=self.on_5min_bar) self.am_5min = ArrayManager(self.exit_dc_length * int(self.atr_length / self.open_window) + 10) self.inited_atr_stop = False def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化。。") self.load_bar(10) # self.put_event() def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动。。") self.put_event() def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止。。") self.put_event() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg_5min.update_tick(tick) self.ask = tick.ask_price_1 # 卖一价 self.bid = tick.bid_price_1 # 买一价 self.put_event() def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg_xmin.update_bar(bar) self.bg_5min.update_bar(bar) def on_5min_bar(self, bar: BarData): self.cancel_all() self.am_5min.update_bar(bar) if not self.am_5min.inited or not self.am_xmin.inited: return if self.atr_stop_array[-3] == 0: return self.exit_up, self.exit_down = self.am_5min.donchian( self.exit_dc_length * int(self.atr_length / self.open_window)) # print(f"dc上轨:{self.exit_up},下轨:{self.exit_down}") if not self.pos: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if self.atrstop_entry > 0: self.buy(self.current_atr_stop, self.trading_size, True) elif self.atrstop_entry < 0: self.short(self.current_atr_stop, self.trading_size, True) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) long_high = self.intra_trade_high * \ (1 - self.trailing_tax / 100) self.long_stop = max(self.exit_down, long_high) self.sell(self.long_stop, abs(self.pos), True) else: self.intra_trade_low = min(self.intra_trade_low, bar.low_price) short_low = self.intra_trade_low * \ (1 + self.trailing_tax / 100) self.short_stop = min(self.exit_up, short_low) self.cover(self.short_stop, abs(self.pos), True) self.put_event() def on_xmin_bar(self, bar: BarData): """""" am_xmin = self.am_xmin am_xmin.update_bar(bar) self.atr_stop_array[:-1] = self.atr_stop_array[1:] if not am_xmin.inited: return # 计算轨道线 nloss self.nloss_array = am_xmin.atr(30, array=True) * self.nloss_singnal # 计算轨道线 self.atr_stop_array = self.atrstop(am_xmin.close, self.atr_stop_array, self.nloss_array) # 初始化 atr_stop_array 保证前三个有值 if self.count < 4: self.count += 1 return self.current_atr_stop = self.atr_stop_array[-1] self.last_atr_stop = self.atr_stop_array[-2] current_bar = self.am_xmin.close[-1] if self.current_atr_stop > self.last_atr_stop and current_bar > self.current_atr_stop: self.atrstop_entry = 1 elif self.current_atr_stop < self.last_atr_stop and current_bar < self.current_atr_stop: self.atrstop_entry = -1 else: self.atrstop_entry = 0 if self.pos == 0: self.atr_value = self.am_xmin.atr(self.atr_length) self.trading_size = max(int(self.risk_level / self.atr_value), 1) self.sync_data() self.put_event() def on_trade(self, trade: TradeData): """ 有成交时 Callback of new trade data update. """ self.put_event() def on_order(self, order: OrderData): """ 订单更新回调 Callback of new order data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event() def atrstop(self, close, atrstop, nlossatr): # 计算轨道线 if (close[-1] > atrstop[-2]) and (close[-2] > atrstop[-2]): atrstop[-1] = max(atrstop[-2], close[-1] - nlossatr[-1]) elif (close[-1] < atrstop[-2]) and (close[-2] < atrstop[-2]): atrstop[-1] = min(atrstop[-2], close[-1] + nlossatr[-1]) elif (close[-1] > atrstop[-2]): atrstop[-1] = (close[-1] - nlossatr[-1]) else: atrstop[-1] = (close[-1] + nlossatr[-1]) return atrstop
class RSIStrategy(CtaTemplate): """""" author = "用Python的交易员" no_trade_time_begin1 = time(hour=9, minute=0) no_trade_time_end1 = time(hour=9, minute=30) no_trade_time_begin2 = time(hour=23, minute=0) no_trade_time_end2 = time(hour=23, minute=30) load_bar_day = 20 boll_window = 16 boll_dev = 2.6 # cci_window = 10 atr_window = 30 # atr_ma_window = 10 rsi_f_window = 5 rsi_l_window = 10 grow_window = 5 reduce_window = 5 # rsi_entry = 16 # ma_window = 5 sl_multiplier = 7.6 fixed_size = 1 db_record = 0 bar_size = 100 boll_up = 0 boll_down = 0 # cci_value = 0 atr_value = 0 # atr_ma = 0 rsi_f_value = 0 rsi_l_value = 0 rsi_max_value = 0 rsi_min_value = 0 rsi_f_ma = 0 rsi_l_ma = 0 intra_trade_high = 0 intra_trade_low = 0 long_stop = 0 short_stop = 0 vt_1m_orderids = [] vt_15m_orderids = [] parameters = [ "boll_window", "boll_dev", "atr_window", "rsi_f_window", "rsi_l_window", "grow_window", "reduce_window", "sl_multiplier", "fixed_size", "bar_size", "db_record" ] variables = [ "boll_up", "boll_down", "atr_value", "rsi_f_value", "rsi_l_value", "rsi_f_ma", "rsi_l_ma", "rsi_max_value", "rsi_min_value", "intra_trade_high", "intra_trade_low", "long_stop", "short_stop" ] # parameters = ["boll_window", "boll_dev", "cci_window","rsi_window","rsi_entry","ma_window", # "atr_window","atr_ma_window","sl_multiplier", "fixed_size"] # variables = ["boll_up", "boll_down", "cci_value", "atr_value","atr_ma","rsi_value", # "intra_trade_high", "intra_trade_low", "long_stop", "short_stop"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) #todo,多时间周期,分长短期,判断不同的指标 self.bg = BarGenerator(self.on_bar, 15, self.on_15min_bar) #self.am_1m = ArrayManager() self.am_15m = ArrayManager(self.bar_size) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(self.load_bar_day) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ # self.cancel_order_list(self.vt_1m_orderids) # self.am_1m.update_bar(bar) # if not self.am_1m.inited: # return # # #todo 1分钟的策略 # # self.boll_up, self.boll_down = self.am_1m.boll(self.boll_window, self.boll_dev) # self.atr_value = self.am_1m.atr(self.atr_window) # rsi_f_array = self.am_1m.rsi(self.rsi_f_window, array=True) # rsi_l_array = self.am_1m.rsi(self.rsi_l_window, array=True) # self.rsi_f_value = rsi_f_array[-1] # self.rsi_l_value = rsi_l_array[-1] # # if self.pos == 0: # self.intra_trade_high = bar.high_price # self.intra_trade_low = bar.low_price # # # todo,波动不够大,应该过滤 # if self.rsi_f_value > self.rsi_l_value and if_keep_grow(self.grow_window, rsi_f_array): # vt_orderids = self.buy(self.boll_up, self.fixed_size, True) # self.vt_1m_orderids.extend(vt_orderids) # elif self.rsi_f_value < self.rsi_l_value and if_keep_reduce(self.reduce_window, rsi_f_array): # vt_orderids = self.short(self.boll_down, self.fixed_size, True) # self.vt_1m_orderids.extend(vt_orderids) # # todo,持续范围内小波动,震荡策略 # # # # elif self.pos > 0: # self.intra_trade_high = max(self.intra_trade_high, bar.high_price) # self.intra_trade_low = bar.low_price # if if_keep_reduce(self.reduce_window, rsi_f_array): # self.rsi_f_value < self.rsi_l_value and # vt_orderids = self.sell(bar.close_price - 5, abs(self.pos)) # else: # self.long_stop = self.intra_trade_high - self.atr_value * self.sl_multiplier # vt_orderids = self.sell(self.long_stop, abs(self.pos), True) # self.vt_1m_orderids.extend(vt_orderids) # elif self.pos < 0: # self.intra_trade_high = bar.high_price # self.intra_trade_low = min(self.intra_trade_low, bar.low_price) # if if_keep_grow(self.grow_window, rsi_f_array): # self.rsi_f_value > self.rsi_l_value and # vt_orderids = self.cover(bar.close_price + 5, abs(self.pos)) # else: # self.short_stop = self.intra_trade_low + self.atr_value * self.sl_multiplier # vt_orderids = self.cover(self.short_stop, abs(self.pos), True) # self.vt_1m_orderids.extend(vt_orderids) # if self.db_record: # database_manager.save_bar_calc(bar, self.get_variables()) # # self.put_event() self.bg.update_bar(bar) def on_15min_bar(self, bar: BarData): """""" self.cancel_order_list(self.vt_15m_orderids) self.am_15m.update_bar(bar) if not self.am_15m.inited: return self.boll_up, self.boll_down = self.am_15m.boll( self.boll_window, self.boll_dev) #self.cci_value = am.cci(self.cci_window) self.atr_value = self.am_15m.atr(self.atr_window) # atr_array = am.atr(self.atr_window, array=True) # self.atr_value = atr_array[-1] #self.atr_ma = atr_array[-self.atr_ma_window:].mean() rsi_f_array = self.am_15m.rsi(self.rsi_f_window, array=True) rsi_l_array = self.am_15m.rsi(self.rsi_l_window, array=True) # self.rsi_max_value = rsi_f_array[-self.rsi_f_window:].max() # self.rsi_min_value = rsi_f_array[-self.rsi_f_window:].min() # self.rsi_f_ma = rsi_f_array[-self.rsi_f_window:].mean() # self.rsi_l_ma = rsi_f_array[-self.rsi_f_window:].mean() self.rsi_f_value = rsi_f_array[-1] self.rsi_l_value = rsi_l_array[-1] #self.ma_value = am.sma(self.ma_window) # if (bar.datetime.time() >= self.no_trade_time_begin1 and bar.datetime.time() <= self.no_trade_time_end1) \ # or (bar.datetime.time() >= self.no_trade_time_begin2 and bar.datetime.time() <= self.no_trade_time_end2): # return if self.pos == 0: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price #todo,波动不够大,应该过滤 #if self.rsi_f_value > 50 and self.rsi_f_value > self.rsi_l_value and if_keep_grow(self.grow_window, rsi_f_array) and self.rsi_f_value < 85: #self.rsi_f_value>=self.rsi_max_value: if self.rsi_f_value > self.rsi_l_value: #and if_keep_grow(self.grow_window, rsi_f_array): #self.buy(bar.close_price+5, self.fixed_size) vt_orderids = self.buy(self.boll_up, self.fixed_size, True) self.vt_15m_orderids.extend(vt_orderids) #elif self.rsi_f_value < 50 and self.rsi_f_value < self.rsi_l_value and if_keep_reduce(self.reduce_window, rsi_f_array) and self.rsi_f_value >15: #self.rsi_f_value <=self.rsi_min_value: elif self.rsi_f_value < self.rsi_l_value: # and if_keep_reduce(self.reduce_window, rsi_f_array): #self.short(bar.close_price-5, self.fixed_size) vt_orderids = self.short(self.boll_down, self.fixed_size, True) self.vt_15m_orderids.extend(vt_orderids) #todo,持续范围内小波动,震荡策略 elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.intra_trade_low = bar.low_price if if_keep_reduce( self.reduce_window, rsi_f_array): #self.rsi_f_value < self.rsi_l_value and vt_orderids = self.sell(bar.close_price - 5, abs(self.pos)) else: self.long_stop = self.intra_trade_high - self.atr_value * self.sl_multiplier vt_orderids = self.sell(self.long_stop, abs(self.pos), True) self.vt_15m_orderids.extend(vt_orderids) elif self.pos < 0: self.intra_trade_high = bar.high_price self.intra_trade_low = min(self.intra_trade_low, bar.low_price) if if_keep_grow( self.grow_window, rsi_f_array): #self.rsi_f_value > self.rsi_l_value and vt_orderids = self.cover(bar.close_price + 5, abs(self.pos)) else: self.short_stop = self.intra_trade_low + self.atr_value * self.sl_multiplier vt_orderids = self.cover(self.short_stop, abs(self.pos), True) self.vt_15m_orderids.extend(vt_orderids) if self.db_record: database_manager.save_bar_calc(bar, self.get_variables()) self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ #数据库记录成交记录,bar记录,variables值 if self.db_record: database_manager.save_trade_data(trade, self.get_variables()) self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class RsiAdaptStrategy(CtaTemplate): """ 策略逻辑: 一、、过虑信号 (小时周期) 使用rsiboll来判断信号强弱 二、开单信号 (分钟周期) 1、使用布林上下轨作为开单条件 三、止损 使用动态布林中轨止损 """ author = "yunya" min_window = 45 open_window = 15 rsi_length = 23 kk_length = 80 kk_dev = 2.0 trading_size = 1 atr_length = 30 rsi_entry = 0 kk_up = 0 kk_down = 0 long_stop = 0 short_stop = 0 rsi_value = 0 rsi_up = 0 rsi_dow = 0 ema_mid = 0 ema_length_new = 0 current_ema_mid = 0 last_ema_mid = 0 current_close = 0 last_close = 0 front_close = 0 exit_long = 0 exit_short = 0 long_entry = 0 short_entry = 0 long_stop_trade = 0 short_stop_drade = 0 exit_long_nex = 0 exit_long_last = 0 exit_short_nex = 0 exit_short_last = 0 atr_value = 0 parameters = [ "open_window", "min_window", "rsi_length", "kk_length", "kk_dev", "trading_size", "atr_length", ] variables = [ "rsi_entry", "long_stop", "short_stop", "rsi_value", "rsi_up", "rsi_dow", "ema_mid", "ema_length_new", "current_ema_mid", "last_ema_mid", "current_close", "last_close", "front_close", "exit_long", "exit_short", "long_entry", "short_entry", "long_stop_trade", "short_stop_drade", "exit_long_nex", "exit_long_last", "exit_short_nex", "exit_short_last", ] def __init__( self, cta_engine: Any, strategy_name: str, vt_symbol: str, setting: dict, ): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg_xminute = NewBarGenerator(on_bar=self.on_bar, window=self.min_window, on_window_bar=self.on_xminute_bar) self.am_xminute = ArrayManager(self.kk_length * 2 + 10) self.bg_open = NewBarGenerator(on_bar=self.on_bar, window=self.open_window, on_window_bar=self.on_5min_bar) self.am_open = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化。。") self.load_bar(30) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动。。") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止。。") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg_open.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg_xminute.update_bar(bar) self.bg_open.update_bar(bar) def on_5min_bar(self, bar: BarData): """ :param bar: :type bar: :return: :rtype: """ self.cancel_all() self.am_open.update_bar(bar) if not self.am_open.inited or not self.am_xminute.inited: return ema_mid_array = self.am_open.ema(self.kk_length, True) atr = self.am_open.atr(self.kk_length, True) kk_up_array = ema_mid_array + atr * self.kk_dev kk_down_array = ema_mid_array - atr * self.kk_dev self.ema_mid = ema_mid_array[-1] self.kk_up = kk_up_array[-1] self.kk_down = kk_down_array[-1] self.current_close = self.am_open.close[-1] self.last_close = self.am_open.close[-2] self.front_close = self.am_open.close[-3] if not self.pos: self.exit_long_nex = 0 self.exit_long_last = 0 self.exit_short_nex = 0 self.exit_short_last = 0 self.ema_length_new = self.kk_length self.atr_value = self.am_open.atr(self.atr_length) if self.rsi_entry > 0: self.buy(self.kk_up, self.trading_size, True) self.write_log( f"下多单:{bar.datetime}, {self.kk_up}, {self.trading_size}") elif self.rsi_entry < 0: self.short(self.kk_down, self.trading_size, True) self.write_log( f"下多单:{bar.datetime}, {self.kk_down}, {self.trading_size}") elif self.pos > 0: close_long = self.current_close > self.last_close > self.front_close if close_long: self.ema_length_new -= 1 self.ema_length_new = max(self.ema_length_new, 5) ema_mid_new = self.am_xminute.sma(self.ema_length_new, True) self.current_ema_mid = ema_mid_new[-1] self.last_ema_mid = ema_mid_new[-2] # 仓位是long 时,如果价格下穿新布林中轨 con1 = bar.close_price < self.current_ema_mid con2 = bar.close_price >= self.last_ema_mid if con1 and con2: self.exit_long_nex = bar.close_price # 保存当前收盘价 if self.exit_long_last == 0 or self.exit_long_nex > self.exit_long_last: self.exit_long_last = self.exit_long_nex self.ema_length_new = self.kk_length # 下穿新均线,以原布林均线挂出停止单,避免快速下跌而无法止损 self.exit_long = self.ema_mid else: # 收盘价在两条均线平均价上方,以当前收盘价挂出限价单 if bar.close_price > ( (self.ema_mid + self.current_ema_mid) / 2): self.exit_long = bar.close_price elif bar.close_price < self.ema_mid: self.exit_long = bar.close_price else: self.exit_long = self.ema_mid # print(f"我是多单,收盘价在两个中轨均值下方,以原中轨挂止损单:{self.exit_long},") else: self.exit_long = self.ema_mid self.long_stop = max(self.exit_long, self.long_stop_trade) self.sell(self.long_stop, abs(self.pos), True) elif self.pos < 0: close_short = self.current_close < self.last_close < self.front_close if close_short: self.ema_length_new -= 1 self.ema_length_new = max(self.ema_length_new, 5) ema_mid_new = self.am_xminute.sma(self.ema_length_new, True) self.current_ema_mid = ema_mid_new[-1] self.last_ema_mid = ema_mid_new[-2] # 仓位是short 时,如果价格上穿新布林中轨 con1 = bar.close_price > self.current_ema_mid con2 = bar.close_price <= self.last_ema_mid if con1 and con2: self.exit_short_nex = bar.close_price if self.exit_short_last == 0 or self.exit_short_nex < self.exit_short_last: self.exit_short_last = self.exit_short_nex self.ema_length_new = self.kk_length self.exit_short = self.ema_mid else: if bar.close_price < (self.ema_mid + self.current_ema_mid / 2): self.exit_short = bar.close_price elif bar.close_price < self.ema_mid: self.exit_short = bar.close_price else: self.exit_short = self.ema_mid else: self.exit_short = self.ema_mid self.short_stop = min(self.exit_short, self.short_stop_drade) self.cover(self.short_stop, abs(self.pos), True) self.sync_data() self.put_event() def on_xminute_bar(self, bar: BarData): """ :param bar: :return: """ self.am_xminute.update_bar(bar) if not self.am_xminute.inited: return ema_array = talib.EMA(self.am_xminute.close, self.rsi_length) std_array = talib.EMA(self.am_xminute.close, self.rsi_length) dev_array = abs(self.am_xminute.close[:-1] - ema_array[:-1]) / std_array[:-1] dev_max = max(dev_array[-self.rsi_length:]) rsi_array = talib.RSI(self.am_xminute.close[:-1], self.rsi_length) rsi_up_array = rsi_array + rsi_array * dev_max rsi_dow_array = rsi_array - rsi_array * dev_max rsi_value_array = self.am_xminute.rsi(self.rsi_length, True) self.rsi_up = rsi_up_array[-1] self.rsi_dow = rsi_dow_array[-1] self.rsi_value = rsi_value_array[-1] current_rsi = rsi_value_array[-1] last_rsi = rsi_value_array[-2] current_rsi_up = rsi_up_array[-1] last_rsi_up = rsi_up_array[-2] current_rsi_down = rsi_dow_array[-1] last_rsi_down = rsi_dow_array[-2] con1 = current_rsi > current_rsi_up con2 = last_rsi <= last_rsi_up con3 = current_rsi < current_rsi_down con4 = last_rsi >= last_rsi_down if con1 > con2: self.rsi_entry = 1 elif con3 and con4: self.rsi_entry = -1 self.sync_data() def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price # 成交最高价 self.long_stop_trade = self.long_entry - 2 * self.atr_value else: self.short_entry = trade.price self.short_stop_drade = self.short_entry + 2 * self.atr_value self.sync_data() def on_order(self, order: OrderData): """ 订单更新回调 Callback of new order data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event()
class TurtleSignalStrategy(CtaTemplate): """""" author = "backtest example" entry_window = 20 exit_window = 10 atr_window = 20 fixed_size = 1 entry_up = 0 entry_down = 0 exit_up = 0 exit_down = 0 atr_value = 0 long_entry = 0 short_entry = 0 long_stop = 0 short_stop = 0 parameters = ["entry_window", "exit_window", "atr_window", "fixed_size"] variables = ["entry_up", "entry_down", "exit_up", "exit_down", "atr_value"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(TurtleSignalStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(20) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.cancel_all() self.am.update_bar(bar) if not self.am.inited: return # Only calculates new entry channel when no position holding if not self.pos: self.entry_up, self.entry_down = self.am.donchian( self.entry_window) self.exit_up, self.exit_down = self.am.donchian(self.exit_window) if not self.pos: self.atr_value = self.am.atr(self.atr_window) self.long_entry = 0 self.short_entry = 0 self.long_stop = 0 self.short_stop = 0 self.send_buy_orders(self.entry_up) self.send_short_orders(self.entry_down) elif self.pos > 0: sell_price = max(self.long_stop, self.exit_down) self.sell(sell_price, abs(self.pos), True) elif self.pos < 0: cover_price = min(self.short_stop, self.exit_up) self.cover(cover_price, abs(self.pos), True) self.put_event() def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price self.long_stop = self.long_entry - 2 * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + 2 * self.atr_value def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def send_buy_orders(self, price): """""" self.buy(price, self.fixed_size, True) def send_short_orders(self, price): """""" self.short(price, self.fixed_size, True)
class DudlThrust_NewStrategy(CtaTemplate): """""" author = "yunyu" window_min = 15 rolling_period = 70 upper_open = 0.5 lower_open = 0.6 stop_multiplier = 1.8 dc_length = 30 cci_length = 10 cci_stop = 20 trailing_tax = 1.8 fixed_size = 1 up = 0 down = 0 exit_shour = 0 exit_long = 0 intra_trade_high = 0 intra_trade_low = 0 long_stop = 0 short_stop = 0 long_entry = 0 short_entry = 0 long_out = 0 short_out = 0 cci_value = 0 ask = 0 bid = 0 parameters = [ "window_min", "rolling_period", "upper_open", "lower_open", "stop_multiplier", "dc_length", "cci_length", "cci_stop", "trailing_tax", "fixed_size", ] variables = [ "up", "down", "exit_shour", "exit_long", "intra_trade_high", "intra_trade_low", "long_stop", "short_stop", "long_entry", "short_entry", "long_out", "short_out", "cci_value" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(on_bar=self.on_bar) self.am = ArrayManager( (max(self.dc_length, self.rolling_period) + 10) * 60) self.bg_xmin = BarGenerator(on_bar=self.on_bar, window=self.window_min, on_window_bar=self.on_xmin_bar) self.am_xmin = ArrayManager( max(self.dc_length, self.rolling_period) + 10) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) self.ask = tick.ask_price_1 # 卖一价 self.bid = tick.bid_price_1 # 买一价 self.put_event() def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg_xmin.update_bar(bar) self.cancel_all() self.exit_shour, self.exit_long = self.am.donchian(self.dc_length * 60) if self.pos == 0: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if self.cci_value > self.cci_stop: self.buy(self.up, self.fixed_size, True) elif self.cci_value < -self.cci_stop: self.short(self.down, self.fixed_size, True) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.intra_trade_low = bar.low_price self.long_out = self.intra_trade_high * (1 - self.trailing_tax / 100) self.long_stop = max(self.long_entry, self.long_out, self.exit_long) self.sell(self.long_stop, abs(self.pos), True) elif self.pos < 0: self.intra_trade_high = bar.high_price self.intra_trade_low = min(self.intra_trade_low, bar.low_price) self.short_out = self.intra_trade_low * (1 + self.trailing_tax / 100) self.short_stop = min(self.short_entry, self.short_out, self.exit_shour) self.cover(self.short_stop, abs(self.pos), True) self.put_event() def on_xmin_bar(self, bar: BarData): """ Callback of new bar data update. """ self.am_xmin.update_bar(bar) if not self.am_xmin.inited: return self.up, self.down = self.dualthrust(self.am_xmin.high, self.am_xmin.low, self.am_xmin.close, self.am_xmin.open, self.rolling_period, self.upper_open, self.lower_open) self.cci_value = self.am_xmin.cci(self.cci_length) self.atr_value = self.am.atr(16) self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: long_price = trade.price self.long_entry = long_price - self.stop_multiplier * self.atr_value else: short_price = trade.price self.short_entry = short_price + self.stop_multiplier * self.atr_value self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass # self.put_event() def market_order(self): """""" pass # self.buy(self.last_tick.limit_up, 1) # self.write_log("执行市价单测试") def limit_order(self): """""" pass # self.buy(self.last_tick.limit_down, 1) # self.write_log("执行限价单测试") def stop_order(self): """""" pass # self.buy(self.last_tick.ask_price_1, 1, True) # self.write_log("执行停止单测试") def dualthrust(self, high, low, close, open, n, k1, k2): """ :param high: :param low: :param close: :return: """ #计算N日最高价的最高价,收盘价的最高价、最低价,最低价的最低价 hh = high[-n:-1].max() lc = close[-n:-1].min() hc = close[-n:-1].max() ll = low[-n:-1].max() #计算range,上下轨的距离前一根K线开盘价的距离 range = max(hh - lc, hc - ll) up = open[-2] + k1 * range down = open[-2] - k2 * range return up, down
class TurtleCStrategy(CtaTemplate): """""" # 反向海龟信号 author = "turtle_inverse_trade" entry_window = 50 exit_window = 20 atr_window = 20 stop_multiple = 2 fixed_size = 1 entry_up = 0 entry_down = 0 exit_up = 0 exit_down = 0 atr_value = 0 long_entry = 0 short_entry = 0 long_stop = 0 short_stop = 0 parameters = [ "entry_window", "exit_window", "atr_window", "fixed_size", "stop_multiple" ] variables = ["entry_up", "entry_down", "exit_up", "exit_down", "atr_value"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(TurtleCStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(20) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.cancel_all() self.am.update_bar(bar) if not self.am.inited: return # Only calculates new entry channel when no position holding if not self.pos: self.entry_up, self.entry_down = self.am.donchian( self.entry_window) # self.close_ma = self.am.sma(50) # self.entry_up += self.close_ma * 0.002 # self.entry_down -= self.close_ma * 0.002 self.exit_up, self.exit_down = self.am.donchian(self.exit_window) if not self.pos: self.atr_value = self.am.atr(self.atr_window) self.long_entry = 0 self.short_entry = 0 self.long_stop = 0 self.short_stop = 0 self.send_buy_orders(self.entry_up) self.send_short_orders(self.entry_down) elif self.pos > 0: # inverse system # 有多头要卖出,等向上再卖出 self.sell(self.exit_up, abs(self.pos), False) elif self.pos < 0: # inverse system # 有空头要买回,等向下再补回 self.cover(self.exit_down, abs(self.pos), False) self.put_event() def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price self.long_stop = self.long_entry - self.stop_multiple * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + self.stop_multiple * self.atr_value def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def send_buy_orders(self, price): """""" # invere system self.short(price, self.fixed_size, False) def send_short_orders(self, price): """""" # inverse system self.buy(price, self.fixed_size, False)
class Boll_kk_vix_simple_Strategy(CtaTemplate): """ 本策略为反向策略,币本位 Reverse 反向 """ author = "yunya" open_window = 5 xminute_window = 15 com_length = 450 exit_dc_length = 10 fast_sma_length = 45 slow_sma_length = 110 cci_length = 30 cci_exit = 26 sl_multiplier = 8.0 fixed_size = 1 bollkk_ema = 0 bollkk_up = 0 bollkk_down = 0 bollkk_width = 0 cci_vlue = 0 long_stop = 0 short_stop = 0 exit_up = 0 exit_down = 0 atr_value = 0 long_entry = 0 short_entry = 0 ma_trend = 0 exit_dc_long = 0 exit_dc_short = 0 intra_trade_high = 0 intra_trade_low = 0 parameters = [ "open_window", "xminute_window", "com_length", "fast_sma_length", "slow_sma_length", "cci_length", "cci_exit", "exit_dc_length", "sl_multiplier", "fixed_size", ] variables = [ "bollkk_ema", "bollkk_up", "bollkk_down", "bollkk_width", "cci_vlue", "long_stop", "short_stop", "exit_up", "exit_down", "atr_value", "long_entry", "short_entry", "ma_trend", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg_xminute = BarGenerator(on_bar=self.on_bar, window=self.xminute_window, on_window_bar=self.on_xminute_bar, interval=Interval.MINUTE) self.am_xminute = ArrayManager(self.com_length + 10) self.bg = BarGenerator(self.on_bar, self.open_window, self.on_open_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg_xminute.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) self.bg_xminute.update_bar(bar) def on_open_bar(self, bar: BarData): """ :param bar: :return: """ # 先使用挂单全撤的粗化订单管理 self.cancel_all() self.am.update_bar(bar) if not self.am_xminute.inited or not self.am.inited: return if self.pos == 0: # 根据布林带宽度动态调整仓位大小 # self.trading_size = max(int(self.risk_level / self.xminute_com_width), 1) self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if self.cci_value > self.cci_exit and self.ma_trend > 0: self.buy(self.bollkk_up, self.fixed_size, True) elif self.cci_value < -self.cci_exit and self.ma_trend < 0: self.short(self.bollkk_down, self.fixed_size, True) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.intra_trade_low = bar.low_price exit_long_stop = self.intra_trade_high - self.bollkk_width * self.sl_multiplier exit_long_dc = max(exit_long_stop, self.exit_dc_long) self.exit_up = max(exit_long_dc, self.long_stop) self.sell(self.exit_up, abs(self.pos), True) elif self.pos < 0: self.intra_trade_high = bar.high_price self.intra_trade_low = min(self.intra_trade_low, bar.low_price) exit_short_stop = self.intra_trade_low + self.bollkk_width * self.sl_multiplier exit_shout_dc = min(exit_short_stop, self.exit_dc_short) self.exit_down = min(exit_shout_dc, self.short_stop) self.cover(self.exit_down, abs(self.pos), True) self.put_event() self.sync_data() def on_xminute_bar(self, bar: BarData): """ :param bar: :return: """ # x分钟 多策略合合成的通道线 self.am_xminute.update_bar(bar) if not self.am_xminute.inited: return bollkk_ema_value, self.bollkk_up, self.bollkk_down, = self.boll_kk_combination( high=self.am_xminute.high[:-1], close=self.am_xminute.close[:-1], low=self.am_xminute.low[:-1], com_length=self.com_length) # 计算开平信号 self.current_close = self.am_xminute.close[-1] self.last_close = self.am_xminute.close[-2] self.bollkk_ema = bollkk_ema_value[-1] self.bollkk_width = abs(self.bollkk_up - self.bollkk_down) self.cci_value = self.am_xminute.cci(self.cci_length) self.fast_ma = self.am_xminute.sma(self.fast_sma_length) self.slow_ma = self.am_xminute.sma(self.slow_sma_length) if self.fast_ma > self.slow_ma: self.ma_trend = 1 else: self.ma_trend = -1 self.atr_value = self.am_xminute.atr(30) self.exit_dc_short, self.exit_dc_long = self.am_xminute.donchian( self.exit_dc_length) self.sync_data() self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price # 成交最高价 self.long_stop = self.long_entry - 2 * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + 2 * self.atr_value self.sync_data() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def boll_kk_combination(self, high, close, low, com_length): """ 通过计算收盘价与收盘价均线之间的倍数,来自动调整boll 、kk 的通过宽度 """ # 计算组合均线 bollkk_ema = talib.EMA(close, com_length) # 计算自适布林带 boll_std = talib.STDDEV(close, com_length) boll_dev = abs(close - bollkk_ema) / boll_std boll_up = bollkk_ema + boll_dev * boll_std boll_down = bollkk_ema - boll_dev * boll_std # 计算自适肯特通道 kk_atr = talib.ATR(high, low, close, com_length) kk_dev = abs(close - bollkk_ema) / kk_atr kk_up = bollkk_ema + kk_atr * kk_dev kk_down = bollkk_ema - kk_atr * kk_dev bollkk_up = max(boll_up[-1], kk_up[-1]) bollkk_down = min(boll_down[-1], kk_down[-1]) return bollkk_ema, bollkk_up, bollkk_down,