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 compute_index_zz500_specifications(self, df): # 注意:所有的数据库数据和列表数据都按照日期的正序排序(从小到大) # 计算zz500指数的技术指标并入库 """ @ 入参:指数k线信息 """ am = ArrayManager(size=600) for ix, row in df.iterrows(): d = row.to_dict() LOG.info(d['trade_date']) d['ts_code'] = d['ts_code'].replace('.', '_') bar = BarData( gateway_name='ctp', symbol=d['ts_code'], exchange=Exchange.SSE, datetime=string_to_datetime(d['trade_date'])) bar.symbol = d['ts_code'] bar.open_price = d['open'] bar.high_price = d['high'] bar.low_price = d['low'] bar.close_price = d['close'] am.update_bar(bar) rsi_20 = am.rsi(20) d['rsi_20'] = rsi_20 try: d['ma_5'] = am.sma(5) except: traceback.print_exc() LOG.error('************************') LOG.error(d['ts_code']) LOG.error(d['trade_date']) LOG.error(bar) d['ma_10'] = am.sma(10) d['ma_20'] = am.sma(20) d['ma_30'] = am.sma(30) d['ma_60'] = am.sma(60) d['ma_120'] = am.sma(120) d['ma_250'] = am.sma(250) d['ma_500'] = am.sma(500) flt = {'trade_date': d['trade_date']} cl_index_zz500 = self.db[CL_INDEX_ZZ500] # cl_index_zz500.replace_one(flt, d, upsert=False) cl_index_zz500.update_one(flt, {'$setOnInsert': d}, upsert=True) # 插入数据时,flt不存在则插入d,存在则不执行
class RsiSignal(CtaSignal): """""" def __init__(self, rsi_window: int, rsi_level: float): """Constructor""" super(RsiSignal, self).__init__() self.rsi_window = rsi_window self.rsi_level = rsi_level self.rsi_long = 50 + self.rsi_level self.rsi_short = 50 - self.rsi_level self.bg = BarGenerator(self.on_bar) self.am = ArrayManager() 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.am.update_bar(bar) if not self.am.inited: self.set_signal_pos(0) rsi_value = self.am.rsi(self.rsi_window) if rsi_value >= self.rsi_long: self.set_signal_pos(1) elif rsi_value <= self.rsi_short: self.set_signal_pos(-1) else: self.set_signal_pos(0)
class RsiSignal(CtaSignal): """""" minute_5_window = 5 minute_15_window = 15 minute_30_window = 30 hour_1_window = 1 ris_15_value = 0 def __init__(self, rsi_fast_window: int, rsi_middle_window: int, rsi_slow_window: int, rsi_level: float): """Constructor""" super().__init__() self.rsi_fast_window = rsi_fast_window self.rsi_middle_window = rsi_middle_window self.rsi_slow_window = rsi_slow_window self.rsi_level = rsi_level self.rsi_long = 50 + self.rsi_level self.rsi_short = 50 - self.rsi_level self.bg5 = BarGenerator(on_bar=self.on_bar, window=self.minute_5_window, on_window_bar=self.on_5minute_bar) self.am5 = ArrayManager() self.bg15 = BarGenerator(on_bar=self.on_bar, window=self.minute_15_window, on_window_bar=self.on_15minute_bar) self.am15 = ArrayManager() self.bg30 = BarGenerator(on_bar=self.on_bar, window=self.minute_30_window, on_window_bar=self.on_15minute_bar) self.am30 = ArrayManager() self.bg60 = BarGenerator(on_bar=self.on_bar, window=self.hour_1_window, on_window_bar=self.on_hour_bar, interval=Interval.HOUR) self.am60 = ArrayManager() 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.am60.update_bar(bar) self.am30.update_bar(bar) self.am15.update_bar(bar) self.bg5.update_bar(bar) def on_5minute_bar(self, bar: BarData): """ Callback of new bar data update. """ self.am5.update_bar(bar) if not self.am5.inited: self.set_signal_pos(0) return rsi_fast_value = self.am5.rsi(self.rsi_fast_window, True) rsi_middle_value = self.am5.rsi(self.rsi_middle_window, True) rsi_slow_value = self.am5.rsi(self.rsi_slow_window, True) if rsi_value >= self.rsi_long: self.set_signal_pos(1) elif rsi_value <= self.rsi_short: self.set_signal_pos(-1) else: self.set_signal_pos(0) def on_15minute_bar(self, bar: BarData): """ Callback of new bar data update. """ self.am15.update_bar(bar) if not self.am15.inited: return rsi_fast_value = self.am15.rsi(self.rsi_fast_window, True) rsi_middle_value = self.am15.rsi(self.rsi_middle_window, True) rsi_slow_value = self.am15.rsi(self.rsi_slow_window, True) last_fast_value = rsi_fast_value[-1] current_fast_value = rsi_fast_value[-2] last_middle_value = rsi_middle_value[-1] current_middle_value = rsi_middle_value[-2] last_slow_value = rsi_slow_value[-1] current_slow_value = rsi_slow_value[-2] def on_30minute_bar(self, bar: BarData): """ Callback of new bar data update. """ self.am30.update_bar(bar) if not self.am30.inited: return rsi_fast_value = self.am30.rsi(self.rsi_fast_window, True) rsi_middle_value = self.am30.rsi(self.rsi_middle_window, True) rsi_slow_value = self.am30.rsi(self.rsi_slow_window, True) last_fast_value = rsi_fast_value[-1] current_fast_value = rsi_fast_value[-2] last_middle_value = rsi_middle_value[-1] current_middle_value = rsi_middle_value[-2] last_slow_value = rsi_slow_value[-1] current_slow_value = rsi_slow_value[-2] def on_hour_bar(self, bar: BarData): """ Callback of new bar data update. """ self.am60.update_bar(bar) if not self.am60.inited: return def on_rsi(self,close, fast, slow, rsi_long, rsi_short): """ 判断 rsi 在80 20线上下方金叉,死叉 :param close: :param fast: :param middle: :param slow: :param rsi_long: :param rsi_short: :return: """ rsi_fast_value = talib.RSI(close, fast) rsi_slow_value = talib.RSI(close, slow) last_fast_value = rsi_fast_value[-2] current_fast_value = rsi_fast_value[-1] last_slow_value = rsi_slow_value[-2] current_slow_value = rsi_slow_value[-1] # 判断 20线 下方 金叉 if last_fast_value < rsi_short: if last_fast_value <= last_slow_value and current_fast_value > current_slow_value: rsi_long_inited = 1 elif last_fast_value >= last_slow_value and current_fast_value < current_slow_value: rsi_long_inited = -1 else: rsi_long_initde = 0
class MultiTimeframeStrategy(CtaTemplate): """""" author = "KK Taiwan 交易員" rsi_signal = 20 rsi_window = 14 fast_window = 12 # init define for 5mins * 12 = 1HR slow_window = 30# inti define for 5mins * 36 = 3HR fixed_size = 1 rsi_value = 0 rsi_long = 0 rsi_short = 0 fast_ma = 0 slow_ma = 0 ma_trend = 0 parameters = ["rsi_signal", "rsi_window", "fast_window", "slow_window", "fixed_size"] variables = ["rsi_value", "rsi_long", "rsi_short", "fast_ma", "slow_ma", "ma_trend","fast_ma1","slow_ma1"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.rsi_long = 50 + self.rsi_signal self.rsi_short = 50 - self.rsi_signal self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.am5 = ArrayManager() self.bg15 = BarGenerator(self.on_bar, 15, self.on_15min_bar) self.am15 = 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.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 if not self.ma_trend: return self.rsi_value = self.am5.rsi(self.rsi_window) if self.pos == 0: if self.ma_trend > 0 and self.rsi_value >= self.rsi_long: self.buy(bar.close_price + 5, self.fixed_size) elif self.ma_trend < 0 and self.rsi_value <= self.rsi_short: self.short(bar.close_price - 5, self.fixed_size) elif self.pos > 0: if self.ma_trend < 0 or self.rsi_value < 50: self.sell(bar.close_price - 5, abs(self.pos)) elif self.pos < 0: if self.ma_trend > 0 or self.rsi_value > 50: self.cover(bar.close_price + 5, abs(self.pos)) ###KK 跟新長倉策略 self.pettyfast_ma = self.am5.sma(self.fast_window) self.pettyslow_ma = self.am5.sma(self.slow_window) if self.pettyfast_ma > self.pettyslow_ma: self.ma_pettytrend = 1 else: self.ma_pettytrend = -1 ##### if(buy list) if (self.ma_pettytrend < 0) and (time > 0) if 虧 平倉時間點限制 - 2 time if < 1 平倉 else 平倉時間點限制 - time if < 1 跟新下限 from 15 mins均線 #改為短平倉 and update limit else if time < 10 平倉時間點限制 +time if(short list) if (self.ma_pettytrend > 0) and (time > 0) if 虧 平倉時間點限制 - 2 time if timw<1 平倉 else 平倉時間點限制 - time if < 1 跟新下限 from 15 mins均線 else if time < 10 平倉時間點限制 + time if self.pos == 0: if self.ma_trend > 0 and self.rsi_value >= self.rsi_long: self.buy_signal(bar.close_price + 5, self.fixed_size) elif self.ma_trend < 0 and self.rsi_value <= self.rsi_short: self.short(bar.close_price - 5, self.fixed_size) elif self.pos > 0: if self.ma_trend < 0 or self.rsi_value < 50: self.sell_signal(bar.close_price - 5, abs(self.pos)) elif self.pos < 0: if self.ma_trend > 0 or self.rsi_value > 50: self.cover_signal(bar.close_price + 5, abs(self.pos)) ### self.put_event()
class TurtleRsiFilterStrategy(CtaTemplate): """""" # 改版海龟信号-ma出场-Rsi信号过滤 author = "turtle_exit_ma" 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 parameters = ["entry_window", "exit_window", "atr_window", "fixed_size", "stop_multiple", "long_rsi", "short_rsi"] 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.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) self.long_entry = 0 self.short_entry = 0 self.long_stop = 0 self.short_stop = 0 if self.rsi_value > self.long_rsi: self.send_buy_orders(self.entry_up) if 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.fixed_size, True) def send_short_orders(self, price): """""" self.short(price, self.fixed_size, True)
class DoubleSignalGenerator(CtaTemplate): """""" author = "yiran" atr_window = 20 obv_window = 10 minus_dm_window = 10 mfi_window = 20 ad_window = 20 adosc_window = 20 plus_dm_window = 20 dx_window = 20 adx_window = 20 s_window = 5 l_window = 15 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 minus_dm_value = 0 obv_value = 0 mfi_value = 0 ad_value = 0 adosc_value = 0 plus_dm_value = 0 dx_value = 0 adx_value = 0 position_hold = 0 long_entered = False short_entered = False parameters = [] variables = [] 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.rsi_value_recorder_l_window = [] self.rsi_time_recorder_l_window = [] self.rsi_value_recorder_s_window = [] self.rsi_time_recorder_s_window = [] self.atr_time_recorder = [] self.atr_value_recorder = [] self.obv_time_recorder = [] self.obv_value_recorder = [] self.minus_dm_time_recorder = [] self.minus_dm_value_recorder = [] self.mfi_time_recorder = [] self.mfi_value_recorder = [] self.ad_time_recorder = [] self.ad_value_recorder = [] self.adosc_time_recorder = [] self.adosc_value_recorder = [] self.plus_dm_time_recorder = [] self.plus_dm_value_recorder = [] self.dx_time_recorder = [] self.dx_value_recorder = [] self.adx_time_recorder = [] self.adx_value_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) self.obv_value = self.am5.obv(self.obv_window) self.minus_dm_value = self.am5.minus_dm(self.minus_dm_window) self.mfi_value = self.am5.mfi(self.mfi_window) self.ad_value = self.am5.ad(self.ad_window) self.adosc_value = self.am5.adosc(self.adosc_window) self.plus_dm_value = self.am5.adosc(self.plus_dm_window) self.dx_value = self.am5.adosc(self.dx_window) self.adx_value = self.am5.adosc(self.adx_window) self.rsi_time_recorder_s_window.append(bar.datetime) self.rsi_value_recorder_s_window.append(self.rsi_value_s_window) self.atr_time_recorder.append(bar.datetime) self.atr_value_recorder.append(self.atr_value) self.obv_time_recorder.append(bar.datetime) self.obv_value_recorder.append(self.obv_value) self.minus_dm_time_recorder.append(bar.datetime) self.minus_dm_value_recorder.append(self.minus_dm_value) self.mfi_time_recorder.append(bar.datetime) self.mfi_value_recorder.append(self.mfi_value) self.ad_time_recorder.append(bar.datetime) self.ad_value_recorder.append(self.ad_value) self.adosc_time_recorder.append(bar.datetime) self.adosc_value_recorder.append(self.adosc_value) self.plus_dm_time_recorder.append(bar.datetime) self.plus_dm_value_recorder.append(self.plus_dm_value) self.dx_time_recorder.append(bar.datetime) self.dx_value_recorder.append(self.dx_value) self.adx_time_recorder.append(bar.datetime) self.adx_value_recorder.append(self.adx_value) 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) self.rsi_time_recorder_l_window.append(bar.datetime) self.rsi_value_recorder_l_window.append(self.rsi_value_l_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 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 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 CuatroStrategy(CtaTemplate): """""" author = "黄柠" # 定义参数 boll_window = 20 boll_dev = 2.0 rsi_window = 14 rsi_signal = 30 fast_window = 5 slow_window = 20 trailing_long = 1.0 trailing_short = 1.0 fixed_size = 1 # 定义变量 boll_up = 0.0 boll_down = 0.0 rsi_value = 0.0 rsi_long = 0.0 rsi_short = 0.0 fast_ma = 0.0 slow_ma = 0.0 ma_trend = 0 intra_trade_high = 0.0 intra_trade_low = 0.0 long_stop = 0.0 short_stop = 0.0 parameters = [ "boll_window", "boll_dev", "rsi_window", "rsi_signal", "fast_window", "slow_window", "trailing_long", "trailing_short", "fixed_size" ] variables = [ "boll_up", "boll_down", "rsi_value", "rsi_long", "rsi_short", "fast_ma", "slow_ma", "ma_trend", "intra_trade_high", "intra_trade_low", "long_stop", "short_stop" ] def __init__( self, cta_engine: Any, strategy_name: str, vt_symbol: str, setting: dict, ): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.rsi_long = 50 + self.rsi_signal self.rsi_short = 50 - self.rsi_signal self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.bg15 = BarGenerator(self.on_bar, 15, self.on_15min_bar) self.am5 = ArrayManager() self.am15 = 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.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): """ Callback of new bar data update. """ self.cancel_all() self.am5.update_bar(bar) if not self.am5.inited or not self.am15.inited: return self.boll_up, self.boll_down = self.am5.boll(self.boll_window, self.boll_dev) self.rsi_value = self.am5.rsi(self.rsi_window) boll_width = self.boll_up - self.boll_down engine_type = self.get_engine_type() if self.pos == 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.ma_trend > 0 and self.rsi_value >= self.rsi_long: if engine_type == EngineType.BACKTESTING: self.buy(self.boll_up, self.fixed_size, stop=True) else: self.buy(self.boll_up, self.fixed_size, stop=True, lock=True) if self.ma_trend <= 0 and self.rsi_value <= self.rsi_short: if engine_type == EngineType.BACKTESTING: self.short(self.boll_down, self.fixed_size, stop=True) else: self.short(self.boll_down, self.fixed_size, stop=True, lock=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_15min_bar(self, bar: BarData): """ Callback of new bar data update. """ self.am15.update_bar(bar) if self.am15.inited: return self.fast_ma = self.am15.sma(self.fast_window) self.slow_ma = self.am15.sma(self.slow_window) if self.fast_ma > self.slow_ma: self.ma_trend = 1 elif self.fast_ma <= self.slow_ma: self.ma_trend = 0 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 ZZ500Strategy(CtaTemplate): # 参考文档: https://www.doc88.com/p-5748746646083.html # TODO: 对参数调优之后再做指标共振平滑处理看效果如何 author = "digu" score_bull = 4 # 各指标得分和,超过阈值之后才发出买入信号 score_bear = 3 # 各指标得分和,低于阈值之后才发出卖出信号 pct_cnt_low = 30 # 上涨股票占比 pct_cnt_high = 90 pct_ma60_low = 40 pct_ma60_high = 90 cnt_8ma_low = 3 cnt_8ma_high = 5 ds_tushare = DataServiceTushare() c1 = 0 c2 = 0 c3 = 0 c4 = 0 c5 = 0 c6 = 0 parameters = [ "score_bull", "score_bear", "pct_cnt_low", "pct_cnt_high", "pct_ma60_low", "pct_ma60_high", "cnt_8ma_low", "cnt_8ma_high" ] variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"] 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(size=500) self.lst_turnover_rate_f = list() # 保存zz500的历史流通盘换手率 self.deque_quantile_20 = deque() self.pct_cnt_score_pre = 0 # 保存前一天的上涨股占比得分 self.cnt_8ma_score_pre = 0 # 保存前一天的8ma得分 self.ma_bull_score_pre = 0 # 保存前一天的均线多空得分 self.rsi_score_pre = 0 # 保存前一天的rsi得分 self.turnover_rate_f_score_pre = 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) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ # TODO 获取zz500的相关信息 info_zz500 = self.ds_tushare.get_zz500( '000905_SH', time_to_str(bar.datetime, '%Y%m%d')) if info_zz500 is None: LOG.info('zz500 None date: %s' % time_to_str(bar.datetime, '%Y%m%d')) return self.lst_turnover_rate_f.append(info_zz500['turnover_rate_f']) arr_turnover_rate_f = np.array(self.lst_turnover_rate_f) arr_turnover_rate_f.sort() idx_turnover_rate_f = np.argwhere( arr_turnover_rate_f > info_zz500['turnover_rate_f'] - 0.0000001)[0] quantile_turnover_rate_f = idx_turnover_rate_f / arr_turnover_rate_f.size if len(self.deque_quantile_20) < 20: self.deque_quantile_20.append(quantile_turnover_rate_f) else: self.deque_quantile_20.popleft() self.deque_quantile_20.append(quantile_turnover_rate_f) am = self.am am.update_bar(bar) if not am.inited: return # 判断当日上涨股票数目比例 pct_cnt = (info_zz500['stk_cnt_up'] * 100.0) / ( info_zz500['stk_cnt_up'] + info_zz500['stk_cnt_down']) if pct_cnt > self.pct_cnt_high: pct_cnt_score = 1 elif pct_cnt < self.pct_cnt_low: pct_cnt_score = 0 else: pct_cnt_score = self.pct_cnt_score_pre self.pct_cnt_score_pre = pct_cnt_score # 判断大于ma60强势股票数目比例 pct_ma60 = (info_zz500['stk_cnt_ma60_up'] * 100.0) / ( info_zz500['stk_cnt_ma60_up'] + info_zz500['stk_cnt_ma60_down']) if pct_ma60 < self.pct_ma60_low or pct_ma60 > self.pct_ma60_high: pct_ma60_score = 0 else: pct_ma60_score = 1 # 判断8ma指标 cnt_ma = 0 cnt_ma = cnt_ma + 1 if info_zz500['close'] > info_zz500[ 'ma_5'] else cnt_ma cnt_ma = cnt_ma + 1 if info_zz500['close'] > info_zz500[ 'ma_10'] else cnt_ma cnt_ma = cnt_ma + 1 if info_zz500['close'] > info_zz500[ 'ma_20'] else cnt_ma cnt_ma = cnt_ma + 1 if info_zz500['close'] > info_zz500[ 'ma_30'] else cnt_ma cnt_ma = cnt_ma + 1 if info_zz500['close'] > info_zz500[ 'ma_60'] else cnt_ma cnt_ma = cnt_ma + 1 if info_zz500['close'] > info_zz500[ 'ma_120'] else cnt_ma cnt_ma = cnt_ma + 1 if info_zz500['close'] > info_zz500[ 'ma_250'] else cnt_ma cnt_ma = cnt_ma + 1 if info_zz500['close'] > info_zz500[ 'ma_500'] else cnt_ma if cnt_ma > self.cnt_8ma_high: cnt_8ma_score = 1 elif cnt_ma < self.cnt_8ma_low: cnt_8ma_score = 0 else: cnt_8ma_score = self.cnt_8ma_score_pre self.cnt_8ma_score_pre = cnt_8ma_score # 判断均线多空排列指标 if info_zz500['ma_30'] > info_zz500['ma_20'] and info_zz500[ 'ma_20'] > info_zz500['ma_10']: ma_bull_score = 0 elif info_zz500['ma_10'] > info_zz500['ma_20'] and info_zz500[ 'ma_20'] > info_zz500['ma_30']: ma_bull_score = 1 else: ma_bull_score = self.ma_bull_score_pre self.ma_bull_score_pre = ma_bull_score # 判断平滑相对强弱指标MA(RSI(20), 20) arr_rsi_20 = self.am.rsi(20, array=True)[-20:] rsi_20_mean = np.mean(arr_rsi_20) rsi_20_std = np.std(arr_rsi_20) if arr_rsi_20[-1] > rsi_20_mean + rsi_20_std: rsi_score = 1 elif arr_rsi_20[-1] < rsi_20_mean - rsi_20_std: rsi_score = 0 else: rsi_score = self.rsi_score_pre self.rsi_score_pre = rsi_score # 判断A股换手率指标(历史分位数q)得分 quantile_20_mean = np.mean(np.array(self.deque_quantile_20)) quantile_20_std = np.std(np.array(self.deque_quantile_20)) if quantile_turnover_rate_f > quantile_20_mean + quantile_20_std: turnover_rate_f_score = 1 elif quantile_turnover_rate_f < quantile_20_mean - quantile_20_std: turnover_rate_f_score = 0 else: turnover_rate_f_score = self.turnover_rate_f_score_pre self.turnover_rate_f_score_pre = turnover_rate_f_score ZZ500Strategy.c1 += pct_cnt_score ZZ500Strategy.c2 += pct_ma60_score ZZ500Strategy.c3 += cnt_8ma_score ZZ500Strategy.c4 += ma_bull_score ZZ500Strategy.c5 += rsi_score ZZ500Strategy.c6 += turnover_rate_f_score score = pct_cnt_score + pct_ma60_score + cnt_8ma_score + ma_bull_score + rsi_score + turnover_rate_f_score flag_buy = True if score > self.score_bull else False flag_sell = True if score < self.score_bear else False if flag_buy: if self.pos == 0: self.cancel_all() self.buy(bar.close_price, 1) # self.buy(bar.close_price, 1, True) elif flag_sell: if self.pos > 0: self.cancel_all() self.sell(bar.close_price, 1) # self.sell(bar.close_price, 1, True) 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. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class DoubleRsi(CtaTemplate): """""" author = "yiran" s_window = 5 l_window = 15 rsi_window = 11 long_threshold_l_window = 50 long_threshold_s_window = 80 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 exit_return = 0.02 exit_loss = 0.02 long_entered = False short_entered = False intra_trade_high = 0 intra_trade_low = 0 trailing_percent = 0.8 parameters = [ 's_window', 'l_window', "rsi_window", "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 = [] 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) 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: 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: buy_order_price = self.long_order_record[-1] if bar.close_price >= buy_order_price * (1 + self.exit_return): self.sell(bar.close_price * 0.99, abs(self.pos)) elif bar.close_price <= buy_order_price * (1 - self.exit_loss): self.sell(bar.close_price * 0.99, abs(self.pos)) elif self.pos < 0: sell_order_price = self.short_order_record[-1] if bar.close_price >= sell_order_price * (1 + self.exit_loss): self.cover(bar.close_price * 1.01, abs(self.pos)) elif bar.close_price <= sell_order_price * (1 - self.exit_return): self.cover(bar.close_price * 1.01, abs(self.pos)) 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 TurtleSignal(object): """""" # ---------------------------------------------------------------------- def __init__(self, entryWindow, exitWindow, entryDev, exitDev, rsiWindow, rsiSignal): """Constructor""" self.entryWindow = entryWindow self.exitWindow = exitWindow self.entryDev = entryDev self.exitDev = exitDev self.rsiWindow = rsiWindow self.rsiSignal = rsiSignal self.am = ArrayManager(60) self.atrVolatility = 0 self.entryUp = 0 self.entryDown = 0 self.exitUp = 0 self.exitDown = 0 self.rsiValue = 0 self.unit = 0 self.result = None self.lastResult = None # ---------------------------------------------------------------------- def onBar(self, bar): """""" self.am.update_bar(bar) if not self.am.inited: return self.generateSignal(bar) self.calculateIndicator() # ---------------------------------------------------------------------- def calculateIndicator(self): """""" keltnerEntryUp, keltnerEntryDown = self.am.keltner( self.entryWindow, self.entryDev) keltnerExitUp, keltnerExitDown = self.am.keltner( self.exitWindow, self.exitDev) donchianEntryUp, donchianEntryDown = self.am.donchian(self.entryWindow) donchianExitUp, donchianExitDown = self.am.donchian(self.exitWindow) self.entryUp = max(donchianEntryUp, keltnerEntryUp) self.entryDown = min(donchianEntryDown, keltnerEntryDown) self.exitUp = min(keltnerExitUp, donchianExitUp) self.exitDown = max(keltnerExitDown, donchianExitDown) self.rsiValue = self.am.rsi(self.rsiWindow) # ---------------------------------------------------------------------- def generateSignal(self, bar): """""" # 平仓 if self.unit > 0: if bar.low_price <= self.exitDown: self.close(self.exitDown) if self.unit < 0: if bar.high_price >= self.exitUp: self.close(self.exitUp) # 开仓 else: if self.rsiValue >= (50 + self.rsiSignal): if bar.high_price >= self.entryUp: self.open(self.entryUp, 1) elif self.rsiValue <= (50 - self.rsiSignal): if bar.low_price <= self.entryDown: self.open(self.entryDown, -1) # ---------------------------------------------------------------------- def open(self, price, change): """""" self.unit += change if not self.result: self.result = TurtleResult() self.result.open(price, change) # ---------------------------------------------------------------------- def close(self, price): """""" self.unit = 0 self.result.close(price) self.lastResult = self.result self.result = None # ---------------------------------------------------------------------- def getLastPnl(self): """""" if not self.lastResult: return 0 return self.lastResult.pnl
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 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 DoubleTrendModelRsiTwoPrices(CtaTemplate): """""" author = "yiran" fixed_size = 1 s_window = 15 l_window = 30 # Rsi rsi_window = 11 long_threshold_l_window = 50 long_threshold_s_window = 80 # Trend Model fast_ma_macd = 9 slow_ma_macd = 26 signal_macd = 4 true_range_window = 4 true_range_influence_multiplier = 0.5 cross_over_record_max_num_s = 10 cross_over_slice_window_s = 4 trail_bar_window_s = 6 cross_over_record_max_num_l = 5 cross_over_slice_window_l = 4 trail_bar_window_l = 6 bar_num_s = 0 bar_num_after_crossover_s = 0 bar_num_l = 0 bar_num_after_crossover_l = 0 mdif_s = 0 cross_above_0_s = False cross_under_0_s = False cross_over_record_array_s = np.zeros( shape=(4, cross_over_record_max_num_s)) cross_over_slice_window_highest_s = 0 cross_over_slice_window_lowest_s = 0 last_cross_over_interval_s = 0 last_cross_over_side_s = 0 mdif_l = 0 cross_above_0_l = False cross_under_0_l = False cross_over_record_array_l = np.zeros( shape=(4, cross_over_record_max_num_l)) cross_over_slice_window_highest_l = 0 cross_over_slice_window_lowest_l = 0 last_cross_over_interval_l = 0 last_cross_over_side_l = 0 long_open_stop_order_price_l = 0 long_close_stop_order_price_l = 0 short_open_stop_order_price_l = 0 short_close_stop_order_price_l = 0 long_open_stop_order_price_s = 0 long_close_stop_order_price_s = 0 short_open_stop_order_price_s = 0 short_close_stop_order_price_s = 0 rsi_value_l_window = -9999 rsi_value_s_window = -9999 long_entered = False short_entered = False parameters = [ 'fast_ma_macd', 'slow_ma_macd', 'signal_macd', 'true_range_window', 'cross_over_record_max_num_l', 'cross_over_record_max_num_s', 's_window', 'l_window', 'true_range_influence_multiplier', 'cross_over_slice_window_l', 'cross_over_slice_window_s', 'trail_bar_window_l', 'trail_bar_window_s'] variables = [] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bars = [] 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.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 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): self.bg5.update_bar(bar) self.bg15.update_bar(bar) def on_5min_bar(self, bar: BarData): """ Callback of new bar data update. """ self.cancel_all() self.am5.update_bar(bar) self.bar_num_s += 1 if not self.am5.inited: return am = self.am5 self.rsi_value_s_window = self.am5.rsi(self.rsi_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 self.mdif_s, signal, hist = am.macd( self.fast_ma_macd, self.slow_ma_macd, self.signal_macd, array=True) self.long_close_stop_order_price_s = am.low[-self.trail_bar_window_s:].min( ) self.short_close_stop_order_price_s = am.high[-self.trail_bar_window_s:].max( ) if self.mdif_s[-2] < 0 < self.mdif_s[-1]: self.cross_above_0_s = True elif self.mdif_s[-2] > 0 > self.mdif_s[-1]: self.cross_under_0_s = True if self.cross_under_0_s or self.cross_above_0_s: # bar_num self.cross_over_record_array_s[0, :- 1] = self.cross_over_record_array_s[0, 1:] # high self.cross_over_record_array_s[1, :- 1] = self.cross_over_record_array_s[1, 1:] # low self.cross_over_record_array_s[2, :- 1] = self.cross_over_record_array_s[2, 1:] # cross_over_side self.cross_over_record_array_s[3, :- 1] = self.cross_over_record_array_s[3, 1:] self.cross_over_record_array_s[0, -1] = self.bar_num_s self.cross_over_record_array_s[1, -1] = am.high[-1] self.cross_over_record_array_s[2, -1] = am.low[-1] if self.cross_above_0_s: side = 1 elif self.cross_under_0_s: side = -1 self.cross_over_record_array_s[3, -1] = side self.cross_above_0_s, self.cross_under_0_s = False, False self.cross_over_slice_window_highest_s = np.max( self.cross_over_record_array_s[1, -self.cross_over_slice_window_s:]) self.cross_over_slice_window_lowest_s = np.min( self.cross_over_record_array_s[2, -self.cross_over_slice_window_s:]) self.last_cross_over_interval_s = self.bar_num_s - \ self.cross_over_record_array_s[0, -1] self.last_cross_over_side_s = self.cross_over_record_array_s[3, -1] true_range_influence = np.mean(am.trange( array=True)[-self.true_range_window:]) * self.true_range_influence_multiplier self.long_open_stop_order_price_s = self.cross_over_slice_window_highest_s + \ true_range_influence self.short_open_stop_order_price_s = self.cross_over_slice_window_lowest_s + \ true_range_influence cross_overl_l = self.last_cross_over_interval_l <= self.last_cross_over_interval_l if self.pos == 0 and cross_overl_l and self.long_entered: if self.last_cross_over_interval_s <= self.cross_over_record_max_num_s: if self.last_cross_over_side_s == 1 and self.last_cross_over_side_l == 1: long_open_price = max( self.long_open_stop_order_price_l, self.long_open_stop_order_price_s) self.buy( long_open_price, self.fixed_size, stop=True) if self.last_cross_over_side_s == - \ 1 and self.last_cross_over_side_l == -1 and self.short_entered: short_open_price = min( self.short_open_stop_order_price_l, self.short_open_stop_order_price_s) self.short( short_open_price, self.fixed_size, stop=True) elif self.pos > 0: long_close_price = min( self.long_open_stop_order_price_s, self.long_open_stop_order_price_l) self.sell(long_close_price, self.pos, stop=True) elif self.pos < 0: short_close_price = max( self.short_close_stop_order_price_l, self.short_close_stop_order_price_s) self.cover( short_close_price, np.abs( self.pos), stop=True) self.put_event() def on_15min_bar(self, bar: BarData): """ Callback of new bar data update. """ self.cancel_all() self.am15.update_bar(bar) self.bar_num_l += 1 if not self.am15.inited: return am = self.am15 self.rsi_value_l_window = self.am15.rsi(self.rsi_window) self.mdif_l, signal, hist = am.macd( self.fast_ma_macd, self.slow_ma_macd, self.signal_macd, array=True) self.long_close_stop_order_price_l = am.low[-self.trail_bar_window_l:].min( ) self.short_close_stop_order_price_l = am.high[-self.trail_bar_window_l:].max( ) if self.mdif_l[-2] < 0 < self.mdif_l[-1]: self.cross_above_0_l = True elif self.mdif_l[-2] > 0 > self.mdif_l[-1]: self.cross_under_0_l = True if self.cross_under_0_l or self.cross_above_0_l: # bar_num self.cross_over_record_array_l[0, :- 1] = self.cross_over_record_array_l[0, 1:] # high self.cross_over_record_array_l[1, :- 1] = self.cross_over_record_array_l[1, 1:] # low self.cross_over_record_array_l[2, :- 1] = self.cross_over_record_array_l[2, 1:] # cross_over_side self.cross_over_record_array_l[3, :- 1] = self.cross_over_record_array_l[3, 1:] self.cross_over_record_array_l[0, -1] = self.bar_num_l self.cross_over_record_array_l[1, -1] = am.high[-1] self.cross_over_record_array_l[2, -1] = am.low[-1] if self.cross_above_0_l: side = 1 elif self.cross_under_0_l: side = -1 self.cross_over_record_array_l[3, -1] = side self.cross_above_0_l, self.cross_under_0_l = False, False self.last_cross_over_interval_l = self.bar_num_l - \ self.cross_over_record_array_l[0, -1] self.last_cross_over_side_l = self.cross_over_record_array_l[3, -1] self.cross_over_slice_window_highest_l = np.max( self.cross_over_record_array_l[1, -self.cross_over_slice_window_l:]) self.cross_over_slice_window_lowest_l = np.min( self.cross_over_record_array_l[2, -self.cross_over_slice_window_l:]) self.last_cross_over_interval_l = self.bar_num_l - \ self.cross_over_record_array_l[0, -1] self.last_cross_over_side_l = self.cross_over_record_array_l[3, -1] true_range_influence = np.mean(am.trange( array=True)[-self.true_range_window:]) * self.true_range_influence_multiplier self.long_open_stop_order_price_l = self.cross_over_slice_window_highest_l + \ true_range_influence self.short_open_stop_order_price_l = self.cross_over_slice_window_lowest_l + \ true_range_influence 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 CuatroStrategy(CtaTemplate): """""" author = "KeKe" rsi_signal = 19 # 定义rsi阈值 rsi_window = 14 fast_window = 4 slow_window = 26 boll_window = 20 boll_dev = 1.8 trailing_short = 0.3 trailing_long = 0.5 fixed_size = 1 boll_up = 0 boll_down = 0 rsi_value = 0 rsi_long = 0 rsi_short = 0 fast_ma = 0 slow_ma = 0 ma_trend = 0 long_stop = 0 short_stop = 0 intra_trade_high = 0 intra_trade_low = 0 parameters = [ "rsi_signal", "rsi_window", "fast_window", "slow_window", "boll_window", "boll_dev", "trailing_long", "trailing_short", "fixed_size" ] variables = [ "boll_up", "boll_down", "rsi_value", "rsi_long", "rsi_short", "fast_ma", "slow_ma", "ma_trend", "long_stop", "short_stop" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(CuatroStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.rsi_long = 50 + self.rsi_signal # 用rsi阈值定义rsi超买区域 self.rsi_short = 50 - self.rsi_signal # 用rsi阈值定义rsi超卖区域 self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) # 合成5分钟K线 self.am5 = ArrayManager() # 初始化5分钟k线的时间序列 self.bg15 = BarGenerator(self.on_bar, 15, self.on_15min_bar) # 合成15分钟k线 self.am15 = ArrayManager() # 初始化15分钟k线的时间序列 def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) # 载入最近10根bar 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) # 将1分钟k线推送入bg5合成5分钟线 self.bg15.update_bar(bar) # 将1分钟k线推送入bg15合成15分钟线 def on_5min_bar(self, bar: BarData): """在5分钟级别进行交易""" self.cancel_all() self.am5.update_bar(bar) if not self.am5.inited: return if not self.ma_trend: # 如果ma_trend没有初始化,就跳过这根bar return self.rsi_value = self.am5.rsi(self.rsi_window) # 生成5分钟线的rsi指标 self.boll_up, self.boll_down = self.am5.boll( self.boll_window, self.boll_dev) # 生成5分钟线的bolling指标 boll_width = self.boll_up - self.boll_down # 赋值boll宽度变量 ## 当空仓时 if self.pos == 0: self.intra_trade_low = bar.low_price # 记录最低价,用于追踪买入后最低价 self.intra_trade_high = bar.high_price # 记录最高价,用于追踪买入后最高价 if self.ma_trend > 0 and self.rsi_value >= self.rsi_long: # 当上升趋势,且进入超买区 self.buy(self.boll_up, self.fixed_size, True) # 在bolling带上轨开1手多头单 elif self.ma_trend < 0 and self.rsi_value <= self.rsi_short: # 当下降趋势,且进入超卖区 self.short(self.boll_down, self.fixed_size, True) # 在bolling带下轨开1手空头仓位 ## 当持有多头仓时 elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) # 逐根k线记录到达过的最高价 self.long_stop = (self.intra_trade_high - self.trailing_long * boll_width ) # 追踪止损位是最高价*0.5*boll宽度 self.sell(self.long_stop, abs(self.pos), True, True) # 在追踪止损价位平所有多头仓 ## 当持有空头仓时 elif self.pos < 0: self.intra_trade_low = min(self.intra_trade_low, bar.low_price) # 逐根k线记录到达过的最低价 self.short_stop = (self.intra_trade_low + self.trailing_short * boll_width) # 追踪止损位 self.cover(self.short_stop, abs(self.pos), True, True) # 轧空 self.put_event() def on_15min_bar(self, bar: BarData): """在15分钟级别主要用于判断市场的趋势,起筛选作用""" self.am15.update_bar(bar) # 推送bar,生成15分钟的时间序列 if not self.am15.inited: # 判断15分钟线是否已初始化 return self.fast_ma = self.am15.sma(self.fast_window) # 生成15分钟级别的移动平均线快线 self.slow_ma = self.am15.sma(self.slow_window) # 生成15分钟级别的移动平均线慢线 if self.fast_ma > self.slow_ma: # 当金叉以后 self.ma_trend = 1 # 1代表上升趋势 else: self.ma_trend = -1 # -1代表下降趋势 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 ImprovedDtStrategy(CtaTemplate): """""" author = "用Python的交易员" fixed_size = 1 k1 = 0.15 k2 = 0.25 rsi_window = 30 rsi_signal = 10 trailing_long = 0.8 trailing_short = 1.4 daily_limit = 0 day_open = 0 day_high = 0 day_low = 0 day_range = 0 long_entry = 0 short_entry = 0 intra_trade_high = 0 intra_trade_low = 0 daily_count = 0 parameters = [ "k1", "k2", "rsi_window", "rsi_signal", "trailing_long", "trailing_short", "fixed_size" ] variables = ["day_range", "long_entry", "short_entry"] 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() self.last_bar = None 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.cancel_all() self.am.update_bar(bar) # 计算DT范围 if not self.last_bar: self.last_bar = bar return if self.last_bar.datetime.date() != bar.datetime.date(): if self.day_high: self.day_range = self.day_high - self.day_low self.long_entry = bar.open_price + self.k1 * self.day_range self.short_entry = bar.open_price - self.k2 * self.day_range self.day_open = bar.open_price self.day_high = bar.high_price self.day_low = bar.low_price self.long_entered = False self.short_entered = False self.daily_count = 0 else: self.day_high = max(self.day_high, bar.high_price) self.day_low = min(self.day_low, bar.low_price) self.last_bar = bar if not self.day_range or not self.am.inited: return # 计算技术指标 rsi_value = self.am.rsi(self.rsi_window) # 交易逻辑执行 if self.pos == 0: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if self.daily_count < self.daily_limit: if rsi_value >= 50 + self.rsi_signal: self.buy(self.long_entry, self.fixed_size, True) elif rsi_value <= 50 - self.rsi_signal: self.short(self.short_entry, 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 long_stop = self.intra_trade_high * (1 - self.trailing_long / 100) long_stop = max(long_stop, self.short_entry) self.sell(long_stop, self.fixed_size, True) self.short(self.short_entry, self.fixed_size, 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 = self.intra_trade_low * (1 + self.trailing_short / 100) short_stop = min(short_stop, self.long_entry) self.cover(short_stop, self.fixed_size, True) self.buy(self.long_entry, self.fixed_size, True) 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. """ 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 = 15 open_window = 5 rsi_length = 15 boll_length = 80 boll_dev = 2.0 trading_size = 1 rsi_value = 0 rsi_up = 0 rsi_dow = 0 rsi_entry = 0 boll_up = 0 boll_down = 0 boll_mid = 0 boll_length_new = 0 current_boll_mid = 0 last_boll_mid = 0 current_close = 0 last_close = 0 front_close = 0 exit_long = 0 exit_short = 0 exit_long_nex = 0 exit_long_last = 0 exit_short_nex = 0 exit_short_last = 0 parameters = [ "min_window", "open_window", "rsi_length", "boll_length", "boll_dev", "trading_size", ] variables = [ "rsi_value", "rsi_up", "rsi_dow", "rsi_entry", "boll_up", "boll_down", "boll_mid", "boll_length_new", "current_boll_mid", "last_boll_mid", "current_close", "last_close", "front_close", "exit_long", "exit_short", "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.atr_stop_array = np.zeros(10) 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() 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) 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 if not self.pos: if 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) elif self.rsi_entry < 0: self.short(self.boll_down, self.trading_size, True) elif self.pos > 0: # 仓位是long 时,如果价格下穿新布林中轨 con1 = bar.close_price < self.current_boll_mid con2 = bar.close_price >= self.last_boll_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.boll_length_new = self.boll_length # 下穿新均线,以原布林均线挂出停止单,避免快速下跌而无法止损 self.exit_long = self.boll_mid else: # 收盘价在两条均线平均价上方,以当前收盘价挂出限价单 if bar.close_price > ( (self.boll_mid + self.current_boll_mid) / 2): self.exit_long = bar.close_price elif bar.close_price < self.boll_mid: self.exit_long = bar.close_price else: self.exit_long = self.boll_mid # print(f"我是多单,收盘价在两个中轨均值下方,以原中轨挂止损单:{self.exit_long},") else: self.exit_long = self.boll_mid self.sell(self.exit_long, abs(self.pos), True) elif self.pos < 0: # 仓位是short 时,如果价格上穿新布林中轨 con1 = bar.close_price > self.current_boll_mid con2 = bar.close_price <= self.last_boll_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.boll_length_new = self.boll_length self.exit_short = self.boll_mid else: if bar.close_price < (self.boll_mid + self.current_boll_mid / 2): self.exit_short = bar.close_price elif bar.close_price < self.boll_mid: self.exit_short = bar.close_price else: self.exit_short = self.boll_mid else: self.exit_short = self.boll_mid self.cover(self.exit_short, 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 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) 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] if self.rsi_value > current_rsi_up: self.rsi_entry = 1 elif self.rsi_value < current_rsi_down: self.rsi_entry = -1 self.boll_up, self.boll_down = self.am_xminute.boll( self.boll_length, self.boll_dev) self.boll_mid = self.am_xminute.sma(self.boll_length) self.current_close = self.am_xminute.close[-1] self.last_close = self.am_xminute.close[-2] self.front_close = self.am_xminute.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.boll_length_new = self.boll_length elif self.pos > 0: # 上涨或下跌时,布林中轨均值减1 close_long = self.current_close > self.last_close > self.front_close if close_long: self.boll_length_new -= 1 self.boll_length_new = max(self.boll_length_new, 5) elif self.pos < 0: close_short = self.current_close < self.last_close < self.front_close if close_short: self.boll_length_new -= 1 self.boll_length_new = max(self.boll_length_new, 5) boll_mid_new = self.am_xminute.sma(self.boll_length_new, True) self.current_boll_mid = boll_mid_new[-1] self.last_boll_mid = boll_mid_new[-2] self.sync_data() 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 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 MultiTimeframeStrategyHNTest(CtaTemplate): """""" author = "Huang Ning" parameters = [] variables = [] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.pricetick = self.get_pricetick() self.bg1 = XminBarGenerator(self.on_bar, self.bar_window1, self.on_Xmin1_bar) self.am1 = ArrayManager() self.bg2 = XminBarGenerator(self.on_bar, self.bar_window2, self.on_Xmin2_bar) self.am2 = ArrayManager() self.buy_vt_orderids = [] self.sell_vt_orderids = [] self.short_vt_orderids = [] self.cover_vt_orderids = [] self.buy_price = 0 self.sell_price = 0 self.short_price = 0 self.cover_price = 0 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.bg1.update_tick(tick) def on_bar(self, bar: BarData): """""" # 注意:不同周期K线合成的顺序对结果是有影响的 self.bg1.update_bar(bar) self.bg2.update_bar(bar) if self.buy_vt_orderids: for vt_orderid in self.buy_vt_orderids: self.cancel_order(vt_orderid) self.buy_vt_orderids = self.buy( bar.close_price + self.pricetick * self.pricetick_multilplier2, self.fixed_size, True) elif self.sell_vt_orderids: for vt_orderid in self.sell_vt_orderids: self.cancel_order(vt_orderid) self.sell_vt_orderids = self.sell( bar.close_price - self.pricetick * self.pricetick_multilplier2, self.fixed_size, True) elif self.short_vt_orderids: for vt_orderid in self.short_vt_orderids: self.cancel_order(vt_orderid) self.short_vt_orderids = self.short( bar.close_price - self.pricetick * self.pricetick_multilplier2, self.fixed_size, True) elif self.cover_vt_orderids: for vt_orderid in self.cover_vt_orderids: self.cancel_order(vt_orderid) self.cover_vt_orderids = self.cover( bar.close_price + self.pricetick * self.pricetick_multilplier2, self.fixed_size, True) def on_Xmin1_bar(self, bar: BarData): """""" self.am1.update_bar(bar) if not self.am1.inited: return if not self.ma_trend: return self.rsi_value = self.am1.rsi(self.rsi_window) if self.pos == 0: self.buy_price = bar.close_price + self.pricetick * self.pricetick_multiplier1 self.sell_price = 0 self.short_price = bar.close_price - self.pricetick * self.pricetick_multiplier1 self.cover_price = 0 elif self.pos > 0: self.buy_price = 0 self.sell_price = bar.close_price - self.pricetick * self.pricetick_multiplier1 self.short_price = 0 self.cover_price = 0 else: self.buy_price = 0 self.sell_price = 0 self.short_price = 0 self.cover_price = bar.close_price + self.pricetick * self.pricetick_multiplier1 if self.pos == 0: if not self.buy_vt_orderids: if self.ma_trend > 0 and self.rsi_value >= self.rsi_long: self.buy(self.buy_price, self.fixed_size, True) self.buy_price = 0 else: for vt_orderid in self.buy_vt_orderids: self.cancel_order(vt_orderid) if not self.short_vt_orderids: if self.ma_trend < 0 and self.rsi_value <= self.rsi_short: self.short(self.short_price, self.fixed_size, True) self.short_price = 0 else: for vt_orderid in self.short_vt_orderids: self.cancel_order(vt_orderid) elif self.pos > 0: if not self.sell_vt_orderids: if self.ma_trend < 0 or self.rsi_value < 50: self.sell(self.sell_price, abs(self.pos), True) self.sell_price = 0 else: for vt_orderid in self.sell_vt_orderids: self.cancel_order(vt_orderid) else: if not self.cover_vt_orderids: if self.ma_trend > 0 or self.rsi_value > 50: self.cover(self.cover_price, abs(self.pos), True) self.cover_price = 0 else: for vt_orderid in self.cover_vt_orderids: self.cancel_order(vt_orderid) def on_Xmin2_bar(self, bar: BarData): """""" self.am2.update_bar(bar) if not self.am2.inited: return self.fast_ma = self.am2.sma(self.fast_window) self.slow_ma = self.am2.sma(self.slow_window) if self.fast_ma > self.slow_ma: self.ma_trend = 1 elif self.fast_ma < self.slow_ma: self.ma_trend = -1 else: self.ma_trend = 0 def on_stop_order(self, stop_order: StopOrder): """""" if stop_order.status == StopOrderStatus.WAITING: return for buf_orderids in [ self.buy_vt_orderids, self.sell_vt_orderids, self.short_vt_orderids, self.cover_vt_orderids ]: if stop_order.stop_orderid in buf_orderids: buf_orderids.remove(stop_order.stop_orderid)
class CincoRB2005Strategy(CtaTemplate): """""" author = "tonywang_efun" boll_window = 44 boll_dev = 2.0 rsi_window = 8 rsi_long = 58 rsi_short = 20 trailing_long = 2.6 trailing_short = 2.6 fixed_size = 2 boll_up = 0 boll_down = 0 rsi_value = 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", "rsi_window", "rsi_long", "rsi_short", "trailing_long", "trailing_short", "fixed_size" ] variables = [ "boll_up", "boll_down", "rsi_value", "trading_size", "intra_trade_high", "intra_trade_low", "long_stop", "short_stop", "atr_value" ] def __init__( self, cta_engine, strategy_name: str, vt_symbol: str, setting: dict, ): """""" super(CincoRB2005Strategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar, 13, self.on_15min_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_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) self.rsi_value = self.am.rsi(self.rsi_window) boll_width = self.boll_up - self.boll_down 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 # print(self.boll_up, self.boll_down, self.intra_trade_high, self.intra_trade_low) if self.rsi_value >= self.rsi_long: self.buy(self.boll_up, self.fixed_size, stop=True) if self.rsi_value <= self.rsi_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.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_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
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 TrendModelDoubleRsi(CtaTemplate): """""" author = "yiran" s_window = 5 l_window = 15 rsi_window = 11 long_threshold_l_window = 50 long_threshold_s_window = 80 fixed_size = 1 fast_ma_macd = 9 slow_ma_macd = 26 signal_macd = 4 true_range_window = 4 true_range_influence_multiplier = 0.5 cross_over_record_max_num = 50 cross_over_slice_window = 4 trail_bar_window = 6 mdif = 0 cross_above_0 = False cross_under_0 = False cross_over_record_array = np.zeros(shape=(4, cross_over_record_max_num)) cross_over_slice_window_highest = 0 cross_over_slice_window_lowest = 0 last_cross_over_interval = 0 last_cross_over_side = 0 bar_num = 0 bar_num_after_crossover = 0 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 exit_return = 0.02 exit_loss = 0.02 long_entered = False short_entered = False intra_trade_high = 0 intra_trade_low = 0 trailing_percent = 0.8 parameters = [ 's_window', 'l_window', "rsi_window", "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 = [] 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) 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: time_constraint = self.last_cross_over_interval <= self.cross_over_record_max_num if self.pos == 0 and time_constraint: 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: buy_order_price = self.long_order_record[-1] if bar.close_price >= buy_order_price * (1 + self.exit_return): self.sell(bar.close_price * 0.99, abs(self.pos)) elif bar.close_price <= buy_order_price * (1 - self.exit_loss): self.sell(bar.close_price * 0.99, abs(self.pos)) elif self.pos < 0: sell_order_price = self.short_order_record[-1] if bar.close_price >= sell_order_price * (1 + self.exit_loss): self.cover(bar.close_price * 1.01, abs(self.pos)) elif bar.close_price <= sell_order_price * (1 - self.exit_return): self.cover(bar.close_price * 1.01, abs(self.pos)) 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) self.bar_num += 1 if not self.am15.inited: return self.rsi_value_l_window = self.am15.rsi(self.rsi_window) am = self.am15 self.mdif, signal, hist = am.macd(self.fast_ma_macd, self.slow_ma_macd, self.signal_macd, array=True) self.long_close_stop_order_price = am.low[-self.trail_bar_window:].min( ) self.short_close_stop_order_price = am.high[-self. trail_bar_window:].max() if self.mdif[-2] < 0 < self.mdif[-1]: self.cross_above_0 = True elif self.mdif[-2] > 0 > self.mdif[-1]: self.cross_under_0 = True if self.cross_under_0 or self.cross_above_0: # bar_num self.cross_over_record_array[ 0, :-1] = self.cross_over_record_array[0, 1:] # high self.cross_over_record_array[ 1, :-1] = self.cross_over_record_array[1, 1:] # low self.cross_over_record_array[ 2, :-1] = self.cross_over_record_array[2, 1:] # cross_over_side self.cross_over_record_array[ 3, :-1] = self.cross_over_record_array[3, 1:] self.cross_over_record_array[0, -1] = self.bar_num self.cross_over_record_array[1, -1] = am.high[-1] self.cross_over_record_array[2, -1] = am.low[-1] if self.cross_above_0: side = 1 elif self.cross_under_0: side = -1 self.cross_over_record_array[3, -1] = side self.cross_above_0, self.cross_under_0 = False, False self.cross_over_slice_window_highest = np.max( self.cross_over_record_array[1, -self.cross_over_slice_window:]) self.cross_over_slice_window_lowest = np.min( self.cross_over_record_array[2, -self.cross_over_slice_window:]) self.last_cross_over_interval = self.bar_num - \ self.cross_over_record_array[0, -1] self.last_cross_over_side = self.cross_over_record_array[3, -1] true_range_influence = np.mean( am.trange(array=True)[-self.true_range_window:] ) * self.true_range_influence_multiplier self.long_open_stop_order_price = self.cross_over_slice_window_highest + \ true_range_influence self.short_open_stop_order_price = self.cross_over_slice_window_lowest + \ true_range_influence 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 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 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 BollFluidStrategy(CtaTemplate): """""" # 布尔通道入场-同样窗口数的均线出场-rsi过滤-按atr计算手数 author = "boll-fluid-size" boll_window = 20 boll_dev = 3 cci_window = 10 atr_window = 30 sl_multiplier = 3.5 fixed_size = 1 boll_up = 0 boll_down = 0 cci_value = 0 atr_value = 0 rsi_value = 0 intra_trade_high = 0 intra_trade_low = 0 long_stop = 0 short_stop = 0 fluid_size = 1 symbol_size = 1 risk_percent = 0.002 risk_capital = 1000000 parameters = [ "boll_window", "boll_dev", "cci_window", "symbol_size", "risk_percent", "risk_capital" "atr_window", "sl_multiplier", "fixed_size" ] variables = [ "boll_up", "boll_down", "cci_value", "atr_value", "rsi_value", "fluid_size" "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) print(self.author) print(self.symbol_size, self.risk_capital, self.risk_percent) # 用于实盘引擎的Xminbar合成,和回测引擎关系不大 # self.bg = BarGenerator(self.on_bar, 15, self.on_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") # 对于回撤引擎这里是关键,要设置好callback函数 # 回测的new_bar函数内,仍然是调用on_bar,如果不需要合成的bar逻辑,比如直接用hour线的,就是直接用on_bar作为回调函数 # 回测引擎使用的days是交易日,即开始日期+n日交易日才是真正的开始。而实盘引擎是从现在开始往历史倒推n个自然日。 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) def on_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # print(bar.datetime, bar.close_price) self.boll_up, self.boll_down = am.boll(self.boll_window, self.boll_dev) self.exit_ma = am.sma(self.boll_window) self.rsi_value = self.am.rsi(self.boll_window) self.cci_value = am.cci(self.cci_window) self.atr_value = am.atr(self.atr_window) if self.pos == 0: 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.intra_trade_high = bar.high_price # self.intra_trade_low = bar.low_price # 不用过滤器 # self.buy(self.boll_up, self.fixed_size, True) # self.short(self.boll_down, self.fixed_size, True) # 使用rsi过滤+标准化手数 if self.fluid_size and self.rsi_value >= 50: self.buy(self.boll_up, self.fluid_size, True) elif self.fluid_size and self.rsi_value < 50: self.short(self.boll_down, self.fluid_size, True) # 添加cci过滤器 # if self.cci_value > 0: # self.buy(self.boll_up, self.fixed_size, True) # elif self.cci_value < 0: # self.short(self.boll_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_stop = self.intra_trade_high - self.atr_value * self.sl_multiplier self.sell(self.exit_ma, 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.exit_ma, abs(self.pos), True) 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. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class MultiTimeframeStrategy(CtaTemplate): """""" author = "用Python的交易员" rsi_signal = 20 rsi_window = 14 fast_window = 5 slow_window = 20 fixed_size = 1 # 5min级bar下限价单时的加点,应该为最小变动价的整数倍 bar_add = 2 rsi_value = 0 rsi_long = 0 rsi_short = 0 fast_ma = 0 slow_ma = 0 ma_trend = 0 parameters = ["rsi_signal", "rsi_window", "fast_window", "slow_window", "fixed_size","bar_add"] variables = ["rsi_value", "rsi_long", "rsi_short", "fast_ma", "slow_ma", "ma_trend"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.rsi_long = 50 + self.rsi_signal self.rsi_short = 50 - self.rsi_signal # 维护两组bg/am,对应不同时间周期 self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.am5 = ArrayManager() self.bg15 = BarGenerator(self.on_bar, 15, self.on_15min_bar) self.am15 = 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.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 # 长周期趋势为短周期的过滤 if not self.ma_trend: return self.rsi_value = self.am5.rsi(self.rsi_window) if self.pos == 0: if self.ma_trend > 0 and self.rsi_value >= self.rsi_long: self.buy(bar.close_price + self.bar_add, self.fixed_size) elif self.ma_trend < 0 and self.rsi_value <= self.rsi_short: self.short(bar.close_price - self.bar_add, self.fixed_size) elif self.pos > 0: if self.ma_trend < 0 or self.rsi_value < 50: self.sell(bar.close_price - self.bar_add, abs(self.pos)) elif self.pos < 0: if self.ma_trend > 0 or self.rsi_value > 50: self.cover(bar.close_price + self.bar_add, 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.fast_ma = self.am15.sma(self.fast_window) self.slow_ma = self.am15.sma(self.slow_window) # 根据15min级的MA设置方向 if self.fast_ma > self.slow_ma: self.ma_trend = 1 else: self.ma_trend = -1 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 MultiTimeframeStrategy(CtaTemplate): """""" author = '用Python的交易员' rsi_signal = 20 rsi_window = 14 fast_window = 5 slow_window = 20 fixed_size = 1 rsi_value = 0 rsi_long = 0 rsi_short = 0 fast_ma = 0 slow_ma = 0 ma_trend = 0 parameters = ['rsi_signal', 'rsi_window', 'fast_window', 'slow_window', 'fixed_size'] variables = ['rsi_value', 'rsi_long', 'rsi_short', 'fast_ma', 'slow_ma', 'ma_trend'] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(MultiTimeframeStrategy, self).__init__( cta_engine, strategy_name, vt_symbol, setting ) self.rsi_long = 50 + self.rsi_signal self.rsi_short = 50 - self.rsi_signal self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.am5 = ArrayManager() self.bg15 = BarGenerator(self.on_bar, 15, self.on_15min_bar) self.am15 = 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.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 if not self.ma_trend: return self.rsi_value = self.am5.rsi(self.rsi_window) if self.pos == 0: if self.ma_trend > 0 and self.rsi_value >= self.rsi_long: self.buy(bar.close_price + 5, self.fixed_size) elif self.ma_trend < 0 and self.rsi_value <= self.rsi_short: self.short(bar.close_price - 5, self.fixed_size) elif self.pos > 0: if self.ma_trend < 0 or self.rsi_value < 50: self.sell(bar.close_price - 5, abs(self.pos)) elif self.pos < 0: if self.ma_trend > 0 or self.rsi_value > 50: self.cover(bar.close_price + 5, 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.fast_ma = self.am15.sma(self.fast_window) self.slow_ma = self.am15.sma(self.slow_window) if self.fast_ma > self.slow_ma: self.ma_trend = 1 else: self.ma_trend = -1 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 CuatroStrategy(CtaTemplate): """""" author = "KeKe" rsi_signal = 19 rsi_window = 14 fast_window = 4 slow_window = 26 boll_window = 21 boll_dev = 1.9 trailing_short = 0.3 trailing_long = 0.5 fixed_size = 1 boll_up = 0 boll_down = 0 rsi_value = 0 rsi_long = 0 rsi_short = 0 fast_ma = 0 slow_ma = 0 ma_trend = 0 long_stop = 0 short_stop = 0 intra_trade_high = 0 intra_trade_low = 0 parameters = [ "rsi_signal", "rsi_window", "fast_window", "slow_window", "boll_window", "boll_dev", "trailing_long", "trailing_short", "fixed_size" ] variables = [ "boll_up", "boll_down", "rsi_value", "rsi_long", "rsi_short", "fast_ma", "slow_ma", "ma_trend", "long_stop", "short_stop" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(CuatroStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.rsi_long = 50 + self.rsi_signal self.rsi_short = 50 - self.rsi_signal self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.am5 = ArrayManager() self.bg15 = BarGenerator(self.on_bar, 15, self.on_15min_bar) self.am15 = 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.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 if not self.ma_trend: return self.rsi_value = self.am5.rsi(self.rsi_window) self.boll_up, self.boll_down = self.am5.boll(self.boll_window, self.boll_dev) boll_width = self.boll_up - self.boll_down if self.pos == 0: self.intra_trade_low = bar.low_price self.intra_trade_high = bar.high_price if self.ma_trend > 0 and self.rsi_value >= self.rsi_long: self.buy(self.boll_up, self.fixed_size, True) elif self.ma_trend < 0 and self.rsi_value <= self.rsi_short: self.short(self.boll_down, self.fixed_size, 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), True, True) elif self.pos < 0: 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), True, True) self.put_event() def on_15min_bar(self, bar: BarData): """""" self.am15.update_bar(bar) if not self.am15.inited: return self.fast_ma = self.am15.sma(self.fast_window) self.slow_ma = self.am15.sma(self.slow_window) if self.fast_ma > self.slow_ma: self.ma_trend = 1 else: self.ma_trend = -1 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