class BollBbWidthtrategy(CtaTemplate): """ 布林带策略优化: 1、计算布林极限指标 BB = (收盘价 - 布林下轨)/(上轨 - 下轩) 区间:0-1 2、计算布林宽度指标 width = (上轨 - 下轨) / 中轨 区间: """ author = "yunya" open_window = 36 boll_length = 24 prop = 1.8 atr_window = 30 sl_multiplier = 0.2 dc_length = 20 fixed_size = 1 entry_crossover = 0 atr_value = 0 intra_trade_high = 0 intra_trade_low = 0 long_stop_trade = 0 short_stop_trade = 0 long_stop = 0 short_stop = 0 exit_short = 0 exit_long = 0 entry_ema = 0 parameters = [ "open_window", "boll_length", "dc_length", "sl_multiplier", "prop", "fixed_size", ] variables = ["entry_crossover", "long_stop", "short_stop"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.open_window, self.on_xmin_bar) self.am = ArrayManager(int(self.boll_length) + 100) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") 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. """ self.bg.update_bar(bar) def on_xmin_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # Calculate array 计算数组 self.sma_array = am.sma(self.boll_length, True) std_array = am.sma(self.boll_length, True) dev = abs(self.am.close[:-1] - self.sma_array[:-1]) / std_array[:-1] dev_max = dev[-self.boll_length:].max() self.boll_up_array = self.sma_array + std_array * dev_max self.boll_down_array = self.sma_array - std_array * dev_max # Get current and last index current_sma = self.sma_array[-1] last_sma = self.sma_array[-2] last_close = self.am.close[-2] currnet_boll_up = self.boll_up_array[-1] last_boll_up = self.boll_up_array[-2] current_boll_down = self.boll_down_array[-1] last_boll_down = self.boll_down_array[-2] up_limit = current_sma * (1 + self.prop / 100) down_limit = current_sma * (1 - self.prop / 100) boll_width = currnet_boll_up - current_boll_down # Get crossover if (last_close <= last_boll_up and currnet_boll_up < bar.close_price < up_limit): self.entry_crossover = 1 elif (last_close >= last_boll_down and current_boll_down > bar.close_price > down_limit): self.entry_crossover = -1 if (last_close <= last_sma and bar.close_price > current_sma): self.entry_ema = -1 elif (last_close >= last_sma and bar.close_price < current_sma): self.entry_ema = 1 else: self.entry_ema = 0 self.atr_value = am.atr(self.atr_window) self.exit_short, self.exit_long = self.am.donchian(self.dc_length) if not self.pos: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if self.entry_crossover > 0: self.buy(up_limit, self.fixed_size, True) elif self.entry_crossover < 0: self.short(down_limit, self.fixed_size, True) elif self.pos > 0: if self.entry_ema > 0: self.sell((bar.close_price - 5), abs(self.pos)) # 最高价回撤比例、固定止损、唐安奇下轨中的最大值为止损位 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 - boll_width * self.sl_multiplier long_high_trade = max(long_stop_high, self.long_stop_trade) self.long_stop = max(self.exit_long, long_high_trade) self.sell(self.long_stop, abs(self.pos), True) elif self.pos < 0: if self.entry_ema < 0: self.cover((bar.close_price + 5), abs(self.pos)) else: # 最低价回撤比例、固定止损、唐安奇上轨中的最小值为止损位 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 + boll_width * self.sl_multiplier short_low_trade = min(short_stop_low, self.short_stop_trade) self.short_stop = min(short_low_trade, self.exit_short) self.cover(self.short_stop, abs(self.pos), True) self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price # 成交最高价 self.long_stop_trade = self.long_entry - 2 * self.atr_value else: self.short_entry = trade.price self.short_stop_trade = self.short_entry + 2 * self.atr_value self.sync_data() self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event() pass
class BollStdvix(CtaTemplate): """""" author = "yunya" win_open = 15 boll_window = 80 atr_window = 30 rsi_window = 16 rsi_entry = 19 atr_multiple = 2.1 fixed_size = 1 rsi_value = 0 rsi_long = 0 rsi_short = 0 entry_rsi = 0 entry_crossover = 0 atr_value = 0 intra_trade_high = 0 intra_trade_low = 0 long_entry = 0 short_entry = 0 long_stop = 0 short_stop = 0 current_sma = 0 sma_array = 0 boll_up_array = 0 boll_down_array = 0 trade_price_long = 0 long_stop_trade = 0 trade_price_short = 0 short_stop_trade = 0 parameters = [ "win_open", "boll_window", "atr_window", "rsi_window", "rsi_entry", "atr_multiple", "fixed_size", ] variables = [ "entry_crossover", "entry_rsi", "atr_value", "long_entry", "short_entry", "long_stop", "short_stop" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.win_open, self.on_xmin_bar) self.am = ArrayManager(self.boll_window + 100) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.rsi_long = 50 + self.rsi_entry self.rsi_short = 50 - self.rsi_entry 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. """ self.bg.update_bar(bar) def on_xmin_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # Calculate array 计算数组 self.rsi_value = am.rsi(self.rsi_window, True) self.sma_array = am.sma(self.boll_window, True) std_array = am.std(self.boll_window, True) dev = abs(self.am.close[:-1] - self.sma_array[:-1]) / std_array[:-1] dev_max = dev[-self.boll_window:].max() self.boll_up_array = self.sma_array + std_array * dev_max self.boll_down_array = self.sma_array - std_array * dev_max # Get current and last index last_rsi_value = self.rsi_value[-2] current_rsi_value = self.rsi_value[-1] self.current_sma = self.sma_array[-1] last_close = self.am.close[-2] self.current_boll_up = self.boll_up_array[-1] last_boll_up = self.boll_up_array[-2] self.current_boll_down = self.boll_down_array[-1] last_boll_down = self.boll_down_array[-2] # Get crossover if current_rsi_value > self.rsi_short > last_rsi_value: self.entry_rsi = 1 elif current_rsi_value < self.rsi_long < last_rsi_value: self.entry_rsi = -1 else: self.entry_rsi = 0 if bar.close_price > self.current_boll_up and last_close <= last_boll_up: self.entry_crossover = 1 elif bar.close_price < self.current_boll_down and last_close >= last_boll_down: self.entry_crossover = -1 else: self.entry_crossover = 0 if not self.pos: self.atr_value = am.atr(self.atr_window) # 进出场逻辑,可以优化 if self.entry_crossover > 0: self.long_entry = max(self.current_boll_up,bar.close_price) self.buy(self.long_entry, self.fixed_size) elif self.entry_crossover < 0: self.short_entry = min(self.current_boll_down,bar.close_price) self.short(self.short_entry, self.fixed_size) elif self.pos > 0: self.long_stop = max(self.long_stop_trade, self.current_sma) self.sell(self.long_stop, abs(self.pos), True) elif self.pos < 0: self.short_stop = min(self.short_stop_trade, self.current_sma) self.cover(self.short_stop, abs(self.pos), True) self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.trade_price_long = trade.price # 成交最高价 self.long_stop_trade = self.trade_price_long - self.atr_multiple * self.atr_value else: self.trade_price_short = trade.price self.short_stop_trade = self.trade_price_short + self.atr_multiple * self.atr_value self.sync_data() self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event() pass
class DudlThrustEmaPositionStrategy(CtaTemplate): """""" author = "yunyu" open_window = 5 xminute_window = 30 rolling_period = 70 upper_open = 0.45 lower_open = 0.45 cci_length = 5 ema_length = 60 position_atr_length = 6 risk_level = 1000 # fixed_size = 1 trading_size = 0 atr_value = 0 up = 0 down = 0 current_ema = 0 last_ema = 0 ema_mid = 0 ema_new_value = 0 ema_length_new = 0 cci_value = 0 exit_long_nex = 0 exit_long_last = 0 exit_short_nex = 0 exit_short_last = 0 current_close = 0 last_close = 0 front_close = 0 exit_long = 0 exit_short = 0 ask = 0 bid = 0 parameters = [ "open_window", "xminute_window", "rolling_period", "upper_open", "lower_open", "cci_length", "ema_length", "position_atr_length", "risk_level" ] variables = [ "trading_size", "up", "down", "current_ema", "last_ema", "ema_mid", "ema_new_value", "ema_length_new", "cci_value", "exit_long_nex", "exit_long_last", "exit_short_nex", "exit_short_last", "current_close", "last_close", "front_close", "exit_long", "exit_short", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg_open = BarGenerator(on_bar=self.on_bar, window=self.open_window, on_window_bar=self.on_open_bar) self.am_open = ArrayManager() self.bg = NewBarGenerator(on_bar=self.on_bar, window=self.xminute_window, on_window_bar=self.on_xmin_bar) self.am = ArrayManager(self.rolling_period + 50) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) self.ask = tick.ask_price_1 # 卖一价 self.bid = tick.bid_price_1 # 买一价 def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) self.bg_open.update_bar(bar) def on_open_bar(self, bar: BarData): """ Callback of new bar data update. """ self.cancel_all() self.am_open.update_bar(bar) if not self.am.inited or not self.am_open.inited: return if self.pos == 0: self.cci_value = self.am.cci(self.cci_length) # 判断数据是否正常,如果atr 计算结果正常,才计算仓位,避免下单时下出不正常的数量 self.atr_value = self.am.atr(self.position_atr_length) if self.atr_value == 0: return self.trading_size = max(int(self.risk_level / self.atr_value), 1) if self.cci_value > 0: self.buy(self.up, self.trading_size, True) elif self.cci_value < 0: self.short(self.down, self.trading_size, True) elif self.pos > 0: con1 = bar.close_price < self.current_ema con2 = bar.close_price >= self.last_ema if con1 and con2: self.exit_long_nex = bar.close_price # 保存当前收盘价 if self.exit_long_last == 0 or self.exit_long_nex > self.exit_long_last: self.exit_long_last = self.exit_long_nex self.ema_length_new = self.ema_length self.exit_long = self.ema_mid else: if bar.close_price > ( (self.ema_mid + self.current_ema) / 2): self.exit_long = bar.close_price elif bar.close_price < self.ema_mid: self.exit_long = bar.close_price else: self.exit_long = self.ema_mid else: self.exit_long = self.ema_mid self.sell(self.exit_long, abs(self.pos), True) elif self.pos < 0: con1 = bar.close_price > self.current_ema con2 = bar.close_price <= self.last_ema if con1 and con2: self.exit_short_nex = bar.close_price if self.exit_short_last == 0 or self.exit_short_nex < self.exit_short_last: self.exit_short_last = self.exit_short_nex self.ema_length_new = self.ema_length self.exit_short = self.ema_mid else: if bar.close_price < (self.ema_mid + self.current_ema / 2): self.exit_short = bar.close_price elif bar.close_price < self.ema_mid: self.exit_short = bar.close_price else: self.exit_short = self.ema_mid else: self.exit_short = self.ema_mid self.cover(self.exit_short, abs(self.pos), True) self.put_event() self.sync_data() def on_xmin_bar(self, bar: BarData): """ Callback of new bar data update. """ self.am.update_bar(bar) if not self.am.inited: return # 计算海龟 上轨,下轨 high_max = self.am.high[-self.rolling_period:].max() close_min = self.am.close[-self.rolling_period:].min() close_max = self.am.close[-self.rolling_period:].max() low_min = self.am.low[-self.rolling_period:].min() hc = high_max - close_min cl = close_max - low_min dual = max(hc, cl) self.up = self.am.open[-2] + dual * self.upper_open self.down = self.am.open[-2] - dual * self.upper_open # print(f"up:{self.up},{self.down}") self.current_close = self.am.close[-1] self.last_close = self.am.close[-2] self.front_close = self.am.close[-3] if self.pos == 0: self.exit_long_nex = 0 self.exit_long_last = 0 self.exit_short_nex = 0 self.exit_short_last = 0 self.ema_length_new = self.ema_length elif self.pos > 0: close_long = self.current_close > self.last_close > self.front_close if close_long: self.ema_length_new -= 1 self.ema_length_new = max(self.ema_length_new, 5) elif self.pos < 0: close_short = self.current_close < self.last_close < self.front_close if close_short: self.ema_length_new -= 1 self.ema_length_new = max(self.ema_length_new, 5) self.ema_mid = self.am.ema(self.ema_length) ema_mid_new = self.am.ema(self.ema_length_new, True) self.current_ema = ema_mid_new[-1] self.last_ema = ema_mid_new[-2] def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass # self.put_event() def market_order(self): """""" pass # self.buy(self.last_tick.limit_up, 1) # self.write_log("执行市价单测试") def limit_order(self): """""" pass # self.buy(self.last_tick.limit_down, 1) # self.write_log("执行限价单测试") def stop_order(self): """""" pass
class BollVix(CtaTemplate): """""" author = "yunya" open_window = 15 boll_window = 80 fixed_size = 1 boll_mid_current = 0 boll_mid_last = 0 boll_up_current = 0 boll_up_last = 0 boll_down_current = 0 boll_down_last = 0 target_pos = 0 pos_inited = 0 parameters = [ "open_window", "boll_window", "fixed_size", ] variables = [ "boll_mid_current", "boll_mid_last", "boll_up_current", "boll_up_last", "boll_down_current", "boll_down_last", "pos_inited", "target_pos" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.open_window, self.on_minute_bar, interval=Interval.MINUTE) self.am = ArrayManager(self.boll_window * 2) self.up_array: np.ndarray = np.zeros(5) self.down_array: np.ndarray = np.zeros(5) self.boll_inited = False self.boll_count = 0 self.engine_type = self.get_engine_type() self.vt_orderids = [] self.order_price = 0 self.pos_inited = 0 def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(12) 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) # 只有实盘交易才使用BestLimit算法 if self.engine_type != EngineType.LIVE: return # 当前没有仓位 order_volume_open = self.target_pos - self.pos if not order_volume_open: return if order_volume_open > 0: if not self.vt_orderids: self.order_price = tick.bid_price_1 vt_orderids = self.buy(self.order_price, abs(order_volume_open)) self.vt_orderids.extend(vt_orderids) elif self.order_price != tick.bid_price_1: for vt_orderid in self.vt_orderids: self.cancel_order(vt_orderid) elif order_volume_open < 0: if not self.vt_orderids: self.order_price = tick.ask_price_1 vt_orderids = self.short(self.order_price, abs(order_volume_open)) self.vt_orderids.extend(vt_orderids) elif self.order_price != tick.ask_price_1: for vt_orderid in self.vt_orderids: self.cancel_order(vt_orderid) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_minute_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # 计算布林 self.boll_calculate() if not self.boll_inited: return boll_mid_array = self.am.sma(self.boll_window, True) # 计算数组 self.boll_mid = boll_mid_array[-2] self.boll_up_current = self.up_array[-1] self.boll_up_last = self.up_array[-2] self.boll_down_current = self.down_array[-1] self.boll_down_last = self.down_array[-2] if not self.pos: self.pos_inited = 0 if self.am.close[-1] > self.boll_up_current and self.am.close[-2] <= self.boll_up_last: if self.engine_type == EngineType.BACKTESTING: self.buy(self.boll_up_current, self.fixed_size) else: self.target_pos = self.fixed_size print("没有仓位,我开多") elif self.am.close[-1] < self.boll_down_current and self.am.close[-2] >= self.boll_down_last: if self.engine_type == EngineType.BACKTESTING: self.short(self.boll_down_current, self.fixed_size) else: self.target_pos = -self.fixed_size print("没有仓位,我开空") elif self.pos > 0: self.sell(self.boll_mid, abs(self.pos), True) elif self.pos < 0: self.cover(self.boll_mid, abs(self.pos), True) self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def boll_calculate(self): """ 计算布林 :return: """ if not self.boll_inited: self.boll_count += 1 if self.boll_count >= 6: self.boll_inited = True self.up_array[:-1] = self.up_array[1:] self.down_array[:-1] = self.down_array[1:] sma_array = self.am.sma(self.boll_window, True) std_array = self.am.std(self.boll_window, True) dev = abs(self.am.close[:-1] - sma_array[:-1]) / std_array[:-1] dev_max = dev[-self.boll_window:].max() up = sma_array[-1] + std_array[-1] * dev_max down = sma_array[-1] - std_array[-1] * dev_max self.up_array[-1] = up self.down_array[-1] = down
class Boll_Control_Proportion_Vix_Width(CtaTemplate): """""" author = "yunya" win_open = 21 boll_window = 90 prop = 1.8 atr_window = 30 trailing_long = 0.9 trailing_short = 0.9 exit_dc_length = 0 fixed_size = 1 exit_long = 0 exit_short = 0 entry_crossover = 0 atr_value = 0 intra_trade_high = 0 intra_trade_low = 0 long_stop = 0 short_stop = 0 parameters = [ "win_open", "boll_window", "prop", "trailing_long", "trailing_short", "fixed_size", ] variables = [ "entry_crossover", "atr_value", "intra_trade_high", "intra_trade_low", "long_stop", "short_stop", "exit_long", "exit_short", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.win_open, self.on_xmin_bar) self.am = ArrayManager(self.boll_window + 100) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") 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. """ self.bg.update_bar(bar) def on_xmin_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # Calculate array 计算数组 self.sma_array = am.sma(self.boll_window, True) std_array = am.sma(self.boll_window, True) dev = abs(self.am.close[:-1] - self.sma_array[:-1]) / std_array[:-1] dev_max = dev[-self.boll_window:].max() self.boll_up_array = self.sma_array + std_array * dev_max self.boll_down_array = self.sma_array - std_array * dev_max # Get current and last index current_sma = self.sma_array[-1] last_close = self.am.close[-2] currnet_boll_up = self.boll_up_array[-1] last_boll_up = self.boll_up_array[-2] current_boll_down = self.boll_down_array[-1] last_boll_down = self.boll_down_array[-2] up_limit = current_sma * (1 + self.prop / 100) down_limit = current_sma * (1 - self.prop / 100) boll_width = currnet_boll_up - current_boll_down self.exit_long, self.exit_short = self.am.donchian(self.exit_dc_length) # Get crossover if (last_close <= last_boll_up and bar.close_price > currnet_boll_up and bar.close_price < up_limit): self.entry_crossover = 1 elif (last_close >= last_boll_down and bar.close_price < current_boll_down and bar.close_price > down_limit): self.entry_crossover = -1 if not self.pos: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if self.entry_crossover > 0: self.buy(up_limit, self.fixed_size, True) elif self.entry_crossover < 0: self.short(down_limit, 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_high = self.intra_trade_high - boll_width * self.trailing_long self.long_stop = max(long_stop_high, self.exit_short) self.sell(self.long_stop, abs(self.pos), True) elif self.pos < 0: self.intra_trade_high = bar.high_price self.intra_trade_low = min(self.intra_trade_low, bar.low_price) self.short_stop = self.intra_trade_low + boll_width * self.trailing_short self.cover(self.short_stop, abs(self.pos), True) self.sync_data() self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() 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. """ self.put_event() pass
class BollVix(CtaTemplate): """""" author = "yunya" open_window = 15 boll_length = 530 fixed_size = 1 boll_mid_current = 0 boll_mid_last = 0 boll_up_current = 0 boll_up_last = 0 boll_down_current = 0 boll_down_last = 0 target_pos = 0 pos_inited = 0 boll_mid = 0 # 画图专用 time_list = [] open_list = [] high_list = [] low_list = [] close_list = [] volume_list = [] up_list = [] down_list = [] mid_list = [] mid_new_list = [] bias_value_list = [] bias_list = [] singnal_plot = [] singnal_list = None singnal = None plot_echarts = {} parameters = [ "open_window", "boll_length", "fixed_size", ] variables = [ "boll_mid_current", "boll_mid_last", "boll_up_current", "boll_up_last", "boll_down_current", "boll_down_last", "pos_inited", "target_pos" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.open_window, self.on_minute_bar, interval=Interval.MINUTE) self.am = ArrayManager(self.boll_length * 2) self.up_array: np.ndarray = np.zeros(5) self.down_array: np.ndarray = np.zeros(5) self.boll_inited = False self.boll_count = 0 self.engine_type = self.get_engine_type() self.vt_orderids = [] self.order_price = 0 self.pos_inited = 0 def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(12) 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) # 只有实盘交易才使用BestLimit算法 if self.engine_type != EngineType.LIVE: return # 当前没有仓位 order_volume_open = self.target_pos - self.pos if not order_volume_open: return if order_volume_open > 0: if not self.vt_orderids: self.order_price = tick.bid_price_1 vt_orderids = self.buy(self.order_price, abs(order_volume_open)) self.vt_orderids.extend(vt_orderids) elif self.order_price != tick.bid_price_1: for vt_orderid in self.vt_orderids: self.cancel_order(vt_orderid) elif order_volume_open < 0: if not self.vt_orderids: self.order_price = tick.ask_price_1 vt_orderids = self.short(self.order_price, abs(order_volume_open)) self.vt_orderids.extend(vt_orderids) elif self.order_price != tick.ask_price_1: for vt_orderid in self.vt_orderids: self.cancel_order(vt_orderid) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_minute_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # 计算布林 sma_array = self.am.sma(self.boll_length, True) std_array = self.am.std(self.boll_length, True) dev = abs(self.am.close[:-1] - sma_array[:-1]) / std_array[:-1] dev_max = dev[-self.boll_length:].max() up = sma_array + std_array * dev_max down = sma_array - std_array * dev_max boll_mid_array = self.am.sma(self.boll_length, True) # 计算数组 self.boll_mid = boll_mid_array[-2] self.boll_up_current = up[-1] self.boll_up_last = up[-2] self.boll_down_current = down[-1] self.boll_down_last = down[-2] if not self.pos: self.pos_inited = 0 if self.am.close[-1] > self.boll_up_current and self.am.close[ -2] <= self.boll_up_last: if self.engine_type == EngineType.BACKTESTING: self.buy(bar.close_price, self.fixed_size) else: self.target_pos = self.fixed_size print("没有仓位,我开多") elif self.am.close[-1] < self.boll_down_current and self.am.close[ -2] >= self.boll_down_last: if self.engine_type == EngineType.BACKTESTING: self.short(bar.close_price, self.fixed_size) else: self.target_pos = -self.fixed_size print("没有仓位,我开空") elif self.pos > 0: self.sell(self.boll_mid, abs(self.pos), True) elif self.pos < 0: self.cover(self.boll_mid, abs(self.pos), True) # 画图专用 if self.singnal != self.singnal_list: plot = self.singnal else: plot = None self.time_list.append(bar.datetime) self.open_list.append(bar.open_price) self.high_list.append(bar.high_price) self.low_list.append(bar.low_price) self.close_list.append(bar.close_price) self.volume_list.append(bar.volume) self.up_list.append(self.boll_up_current) self.down_list.append(self.boll_down_current) self.mid_list.append(self.boll_mid) self.singnal_plot.append(plot) self.plot_echarts = { "datetime": self.time_list, "open": self.open_list, "high": self.high_list, "low": self.low_list, "close": self.close_list, "volume": self.low_list, "boll_up": self.up_list, "boll_down": self.down_list, "boll_mid": self.mid_list, "signal": self.singnal_plot } self.singnal_list = self.singnal self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction.value == Direction.LONG.value: if trade.offset.value == Offset.OPEN.value: self.singnal = 1 elif trade.offset.value == Offset.CLOSE.value: self.singnal = 0 else: self.singnal = None elif trade.direction.value == Direction.SHORT.value: if trade.offset.value == Offset.OPEN.value: self.singnal = -1 elif trade.offset.value == Offset.CLOSE.value: self.singnal = 0 else: self.singnal = None def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass def boll_calculate(self): """ 计算布林 :return: """ if not self.boll_inited: self.boll_count += 1 if self.boll_count >= 6: self.boll_inited = True self.up_array[:-1] = self.up_array[1:] self.down_array[:-1] = self.down_array[1:] sma_array = self.am.sma(self.boll_length, True) std_array = self.am.std(self.boll_length, True) dev = abs(self.am.close[:-1] - sma_array[:-1]) / std_array[:-1] dev_max = dev[-self.boll_length:].max() up = sma_array[-1] + std_array[-1] * dev_max down = sma_array[-1] - std_array[-1] * dev_max self.up_array[-1] = up self.down_array[-1] = down
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 RsiDcVixStrategy(CtaTemplate): """ Rsi 原版逻辑 Rsi 值 上破临界值 80 时平空做多,下破临界值 20 时平多做空。 Rsi 策略优化思路: 一、指标计算方式 1、计算 N 周期 rsi 2、计算 N 周期 RSI 的最大值为上轨,最小值为下轨 3、rsi 上穿上轨,并且 rsi 大于 50 ,做多 3、rsi 下穿下轨,并且 rsi 小于 50 ,做空 """ author = "yunya" open_window = 45 rsi_window = 100 exit_window = 65 ema_window = 65 atr_window = 16 atr_window_ma = 10 atr_multiplier = 10.0 pos_trailing = 3.0 fixed_size = 1 exit_up = 0 exit_down = 0 atr_value = 0 atr_value_ma = 0 long_entry = 0 short_entry = 0 long_stop = 0 short_stop = 0 long_trade_stop = 0 short_trade_stop = 0 intra_trade_high = 0 intra_trade_low = 0 rsi_value_current = 0 rsi_value_last = 0 rsi_up_current = 0 rsi_up_last = 0 rsi_down_current = 0 rsi_down_last = 0 exit_long_nex = 0 exit_long_last = 0 exit_long = 0 exit_short_nex = 0 exit_short_last = 0 exit_short = 0 boll_mid = 0 boll_mid_new = 0 ema_window_new = 0 parameters = [ "open_window", "rsi_window", "exit_window", "ema_window", "atr_window", "atr_multiplier", "pos_trailing", "fixed_size", ] variables = [ "exit_up", "exit_down", "atr_value", "long_entry", "short_entry", "long_stop", "short_stop", "long_trade_stop", "short_trade_stop", "intra_trade_high", "intra_trade_low", "rsi_value_current", "rsi_value_last", "rsi_up_current", "rsi_up_last", "rsi_down_current", "rsi_down_last", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.open_window, self.on_15min_bar) self.am = ArrayManager(self.rsi_window * 2) self.count: int = 0 self.size: int = 4 self.rsi_inited: bool = False self.rsi_up_array: np.ndarray = np.zeros(self.size) self.rsi_down_array: np.ndarray = np.zeros(self.size) 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 tick data update. """ self.bg.update_bar(bar) def on_15min_bar(self, bar: BarData): """ Callback of new bar data update. """ self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # 计算 dev_max rsi_array = talib.RSI(self.am.close, self.rsi_window) if not self.rsi_inited: self.count += 1 if self.count >= self.size: self.rsi_inited = True # rsi 上下轨容器 self.rsi_up_array[:-1] = self.rsi_up_array[1:] self.rsi_down_array[:-1] = self.rsi_down_array[1:] rsi_up = rsi_array[-self.rsi_window:].max() rsi_down = rsi_array[-self.rsi_window:].min() self.rsi_up_array[-1] = rsi_up self.rsi_down_array[-1] = rsi_down if not self.rsi_inited: return rsi_value_array = am.rsi(self.rsi_window, True) self.rsi_value_current = rsi_value_array[-1] self.rsi_value_last = rsi_value_array[-2] # 取前一个值 self.rsi_up_current = self.rsi_up_array[-2] self.rsi_up_last = self.rsi_up_array[-3] self.rsi_down_current = self.rsi_down_array[-2] self.rsi_down_last = self.rsi_down_array[-3] self.exit_up, self.exit_down = self.am.donchian(self.exit_window) atr_value_array = am.atr(self.atr_window, True) self.atr_value = atr_value_array[-1] self.atr_value_ma = atr_value_array[-self.atr_window_ma:].mean() self.boll_mid = am.sma(self.ema_window) # 没有仓 if not self.pos: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price rsi_inited_up = self.rsi_value_current > self.rsi_up_current and self.rsi_value_last <= self.rsi_up_last rsi_inited_down = self.rsi_value_current < self.rsi_down_current and self.rsi_value_last >= self.rsi_down_last atr_inited = self.atr_value > self.atr_window_ma self.ema_window_new = self.ema_window if rsi_inited_up and atr_inited and self.rsi_value_current > 50: self.buy(bar.close_price + 5, self.fixed_size) elif rsi_inited_down and atr_inited and self.rsi_value_current < 50: self.short(bar.close_price - 5, self.fixed_size) # 有多仓 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.atr_multiplier self.long_stop = max(self.long_stop, self.exit_down) self.long_stop = max(self.long_stop, self.long_trade_stop) # 上涨或下跌时,布林中轨均值减1 close_long = am.close[-1] > am.close[-2] > am.close[-3] if close_long: self.ema_window_new -= 1 self.ema_window_new = max(self.ema_window_new, 10) # 计算新的布林带 self.boll_mid_new = am.sma(self.ema_window_new, True) # 仓位是long 时,如果价格上穿新布林中轨 con1 = am.close[-1] < self.boll_mid_new[-1] con2 = am.close[-2] >= self.boll_mid_new[-2] if con1 and con2: self.exit_long_nex = am.close[-1] # 保存当前收盘价 if self.exit_long_nex > self.exit_long_last or self.exit_long_last == 0: self.exit_long_last = self.exit_long_nex self.ema_window_new = self.ema_window # 下穿新均线,以原布林均线挂出停止单,避免快速下跌而无法止损 self.exit_long = self.boll_mid # print(f"我是多单,exitlast:{self.exit_short_last},重置布林中轨参数,止损挂{self.exit_long}:") else: # 收盘价在两条均线平均价上方,以当前收盘价挂出限价单 if self.am.close[-1] > ( (self.boll_mid + self.boll_mid_new[-1]) / 2): self.exit_long = bar.close_price # print(f"我是多单,收盘价在两个中轨均值上方,以收盘价挂止损单:{self.exit_long}") 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.long_stop = max(self.long_stop, self.exit_long) self.sell(self.long_stop, abs(self.pos), True) # 有空仓 elif self.pos < 0: self.intra_trade_high = bar.high_price self.intra_trade_low = min(self.intra_trade_low, bar.low_price) self.short_stop = self.intra_trade_low + self.atr_value * self.atr_multiplier self.short_stop = min(self.short_stop, self.exit_up) self.short_stop = min(self.short_stop, self.short_trade_stop) close_short = am.close[-1] < am.close[-2] < am.close[-3] if close_short: self.ema_window_new -= 1 self.ema_window_new = max(self.ema_window_new, 10) # 计算新的布林带 self.boll_mid_new = am.sma(self.ema_window_new, True) # 仓位是short 时,如果价格上穿新布林中轨 con3 = am.close[-1] > self.boll_mid_new[-1] con4 = am.close[-2] <= self.boll_mid_new[-2] if con3 and con4: self.exit_short_nex = am.close[-1] if self.exit_short_nex < self.exit_short_last or self.exit_short_last == 0: self.exit_short_last = self.exit_short_nex self.ema_window_new = self.ema_window self.exit_short = self.boll_mid else: if self.am.close[-1] < (self.boll_mid + self.boll_mid_new[-1] / 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.short_stop = min(self.short_stop, self.exit_short) self.cover(self.short_stop, abs(self.pos), True) self.put_event() self.sync_data() def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price # 成交最高价 self.long_trade_stop = self.long_entry * (1 - self.pos_trailing / 100) else: self.short_entry = trade.price self.short_trade_stop = self.short_entry * ( 1 + self.pos_trailing / 100) self.put_event() self.sync_data()
class EmaDifferenceStrategy(CtaTemplate): """ 策略逻辑: 1、计算两条不同周期均线的差离值,差离值二次求均值。 2、当差离值大于零做多,小于零做空。 3、成交价格回撤 2% 固定止损,当利润达到 5% 时,止损位移动到成本价。 """ author = "yunya" open_window = 15 express_length = 30 # 特快 fast_length = 60 # 快 slow_length = 150 # 慢 diff_ema_length = 30 # 差离ema atr_length = 6 atr_multiple = 2.0 # 成交价 2倍ATR为固定止损位 entry_mulitple = 5.0 # 当前价格超过成交价的5%时,止损价为成交价 pay_up = 5 fixed_size = 1 current_express_fast_diff = 0 last_express_fast_diff = 0 current_fast_slow_diff = 0 last_fast_slow_diff = 0 current_express_fast_ema = 0 last_express_fast_ema = 0 current_fast_slow_ema = 0 last_fast_slow_ema = 0 express_fast_inited = 0 fast_slow_inited = 0 price_tick = 0 atr_value = 0 long_entry = 0 long_stop = 0 short_entry = 0 short_stop = 0 exit_long = 0 exit_short = 0 parameters = [ "open_window", "express_length", "fast_length", "slow_length", "diff_ema_length", "atr_length", "atr_multiple", "entry_mulitple", "pay_up", "fixed_size", ] variables = [ "current_express_fast_diff", "last_express_fast_diff", "current_fast_slow_diff", "last_fast_slow_diff", "current_express_fast_ema", "last_express_fast_ema", "current_fast_slow_ema", "last_fast_slow_ema", "express_fast_inited", "fast_slow_inited", "price_tick", "atr_value", "long_entry", "long_stop", "short_entry", "short_stop", "exit_long", "exit_short", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.open_window, self.on_xmin_bar) self.am = ArrayManager(int(self.slow_length) * 100) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_xmin_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # 计算ema express_value = am.ema(self.express_length, True) fast_value = am.ema(self.fast_length, True) slow_value = am.ema(self.slow_length, True) # 计算差离值 express_fast_diff = express_value - fast_value fast_slow_diff = fast_value - slow_value # 计算差离均值 express_fast_ema = talib.EMA(express_fast_diff, self.diff_ema_length) fast_slow_ema = talib.EMA(fast_slow_diff, self.diff_ema_length) # print(f"express_fast_ema: {express_fast_ema[-10:]}" + "\n") # print(f"fast_slow_ema: {fast_slow_ema[-10:]}" + "\n") # 判断差离线交叉情况(上穿,下穿) self.current_express_fast_diff = express_fast_diff[-1] self.last_express_fast_diff = express_fast_diff[-2] self.current_fast_slow_diff = fast_slow_diff[-1] self.last_fast_slow_diff = fast_slow_diff[-2] self.current_express_fast_ema = express_fast_ema[-1] self.last_express_fast_ema = express_fast_ema[-2] self.current_fast_slow_ema = fast_slow_ema[-1] self.last_fast_slow_ema = fast_slow_ema[-2] # 计算上穿,下穿零轴 if self.current_express_fast_ema > 0 and self.last_express_fast_ema <= 0: self.express_fast_inited = 1 elif self.current_express_fast_ema < 0 and self.last_express_fast_ema >= 0: self.express_fast_inited = -1 else: self.express_fast_inited = 0 print(f"特慢:{self.express_fast_inited}" + "\n") if self.current_fast_slow_ema > 0 and self.last_fast_slow_ema <= 0: self.fast_slow_inited = 1 elif self.current_fast_slow_ema < 0 and self.last_fast_slow_ema >= 0: self.fast_slow_inited = -1 else: self.fast_slow_inited = 0 # 如果没有仓位,两条布林window一样 if self.pos == 0: # 判断是回测,还是实盘 engine_type = self.get_engine_type() if engine_type == EngineType.BACKTESTING: long_price = bar.close_price - 10 short_price = bar.close_price + 10 else: self.price_tick = self.get_pricetick() long_price = bar.close_price - self.price_tick * self.pay_up short_price = bar.close_price + self.price_tick * self.pay_up self.atr_value = self.am.atr(self.atr_length) if self.fast_slow_inited > 0: self.buy(long_price, self.fixed_size) elif self.fast_slow_inited < 0: self.short(short_price, self.fixed_size) elif self.pos > 0: long_stop_entry = bar.close_price * (1 - self.entry_mulitple / 100) self.exit_long = max(self.long_stop, long_stop_entry) if self.express_fast_inited < 0: # self.exit_long = bar.close_price - self.price_tick * self.pay_up self.exit_long = bar.close_price - 10 self.sell(self.exit_long, abs(self.pos), True) elif self.pos < 0: short_stop_entry = bar.close_price * (1 + self.entry_mulitple / 100) self.exit_short = min(self.short_stop, short_stop_entry) if self.express_fast_inited > 0: # self.exit_short = bar.close_price + self.price_tick * self.pay_up self.exit_short = bar.close_price + 10 self.cover(self.exit_short, abs(self.pos), True) self.put_event() self.sync_data() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price # 成交最高价 self.long_stop = self.long_entry - self.atr_multiple * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + self.atr_multiple * self.atr_value self.sync_data() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event() pass
class EmaDifferenceStrategy(CtaTemplate): """ 策略逻辑: 1、计算两条不同周期均线的差离值,差离值二次求均值。 2、当差离值大于零做多,小于零做空。 3、成交价格回撤 2% 固定止损,当利润达到 5% 时,止损位移动到成本价。 1、计算四条差离值线,并求30周期ema 如果所有差离线全部在零线附近(-0.1,+0.1), 2、如果所有线上穿大周期开多,所有线下穿大周期开空。 3、引入打分系统,各个指标计算,每个值为正向一分,分数达到N值开多,小于-N 开空。 小于N-时减部分仓位。 4、判断各线之间上穿和下穿来打分,短周期上穿长周期加1分,短周期下穿长周期减1分,长周期是否拐头,拐头向上加一分,向下减一分。 """ author = "yunya" open_window = 15 fastest_length = 10 # 最快 fast_length = 30 # 快 slow_length = 60 # 慢 slowest_length = 120 # 最慢 extremely_slow_length = 180 # 特慢 diff_ema_length = 30 # 差离ema diff_deviate = 0.2 # 零轴的偏离最 fixed_size = 1 fast_ema = 0 # 差离均值 slow_ema = 0 slowest_ema = 0 extremely_slow_ema = 0 fast_diff_deviate = 0 # 差离线与零轴的位置 slow_diff_deviate = 0 slowest_diff_deviate = 0 extremely_slow_diff_deviate = 0 fast_slow_to = 0 # 判断上穿,下穿,上穿1 下穿-1 fast_slowest_to = 0 fast_extremely_slow_to = 0 slow_slowest_to = 0 slow_extremely_to = 0 slowest_extremely_to = 0 parameters = [] variables = [] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.open_window, self.on_xmin_bar) self.am = ArrayManager(int(self.extremelyslow_length) * 100) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_xmin_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # 计算ema fastest_value = am.ema(self.fastest_length, True) fast_value = am.ema(self.fast_length, True) slow_value = am.ema(self.slow_length, True) slowest_value = am.ema(self.slowest_length, True) extremely_slow_value = am.ema(self.extremely_slow_length, True) # 计算差离值 fastest_fast_diff = fastest_value - fast_value fast_slow_diff = fast_value - slow_value slow_slowest_diff = slow_value - slowest_value slowest_extremely_slow_diff = slow_value - extremely_slow_value # 计算差离均值 self.fast_ema = talib.EMA(fastest_fast_diff, self.diff_ema_length) self.slow_ema = talib.EMA(fast_slow_diff, self.diff_ema_length) self.slowest_ema = talib.EMA(slow_slowest_diff, self.diff_ema_length) self.extremely_slow_ema = talib.EMA(slowest_extremely_slow_diff, self.diff_ema_length) # 判断差离线与零轴的位置(在零轴附近) self.fast_diff_deviate = self.on_diff_range(self.fast_ema, self.diff_deviate) self.slow_diff_deviate = self.on_diff_range(self.slow_ema, self.diff_deviate) self.slowest_diff_deviate = self.on_diff_range(self.slowest_ema, self.diff_deviate) self.extremely_slow_diff_deviate = self.on_diff_range( self.extremely_slow_ema, self.diff_deviate) # 判断差离线交叉情况(上穿,下穿) self.fast_slow_to = self.on_diff_to_up_down(self.fast_ema, self.slow_ema) self.fast_slowest_to = self.on_diff_to_up_down(self.fast_ema, self.slowest_ema) self.fast_extremely_slow_to = self.on_diff_to_up_down( self.fast_ema, self.extremely_slow_ema) self.slow_slowest_to = self.on_diff_to_up_down(self.slow_ema, self.slowest_ema) self.slow_extremely_to = self.on_diff_to_up_down( self.slow_ema, self.extremely_slow_ema) self.slowest_extremely_to = self.on_diff_to_up_down( self.slowest_ema, self.extremely_slow_ema) # 如果没有仓位,两条布林window一样 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 if self.cci_value > self.cci_exit: self.buy(self.boll_up, self.fixed_size, True) if self.cci_value < -self.cci_exit: self.short(self.boll_down, self.fixed_size, True) elif self.pos > 0: # 上涨或下跌时,布林中轨均值减1 close_long = am.close[-1] > am.close[-2] > am.close[-3] if close_long: self.boll_length_new -= 1 self.boll_length_new = max(self.boll_length_new, 10) # 计算新的布林带 self.boll_mid_new = am.sma(self.boll_length_new, True) # 仓位是long 时,如果价格上穿新布林中轨 con1 = am.close[-1] < self.boll_mid_new[-1] con2 = am.close[-2] >= self.boll_mid_new[-2] if con1 and con2: self.exit_long_nex = am.close[-1] # 保存当前收盘价 if self.exit_long_nex > self.exit_long_last or self.exit_long_last == 0: self.exit_long_last = self.exit_long_nex self.boll_length_new = self.boll_length # 下穿新均线,以原布林均线挂出停止单,避免快速下跌而无法止损 self.exit_long = self.boll_mid # print(f"我是多单,exitlast:{self.exit_short_last},重置布林中轨参数,止损挂{self.exit_long}:") else: # 收盘价在两条均线平均价上方,以当前收盘价挂出限价单 if self.am.close[-1] > ( (self.boll_mid + self.boll_mid_new[-1]) / 2): self.exit_long = bar.close_price # print(f"我是多单,收盘价在两个中轨均值上方,以收盘价挂止损单:{self.exit_long}") 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 # print(f"我是多单,收盘价在新中轨上方,以原中轨挂止损单:{self.exit_long}") self.sell(self.exit_long, abs(self.pos), True) elif self.pos < 0: close_short = am.close[-1] < am.close[-2] < am.close[-3] if close_short: self.boll_length_new -= 1 self.boll_length_new = max(self.boll_length_new, 10) # 计算新的布林带 self.boll_mid_new = am.sma(self.boll_length_new, True) # 仓位是short 时,如果价格上穿新布林中轨 con3 = am.close[-1] > self.boll_mid_new[-1] con4 = am.close[-2] <= self.boll_mid_new[-2] if con3 and con4: self.exit_short_nex = am.close[-1] if self.exit_short_nex < self.exit_short_last or self.exit_short_last == 0: self.exit_short_last = self.exit_short_nex self.boll_length_new = self.boll_length self.exit_short = self.boll_mid else: if self.am.close[-1] < (self.boll_mid + self.boll_mid_new[-1] / 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.put_event() self.sync_data() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event() pass def on_diff_range(self, diff_array, diff_deviate): """ 判断 diff 是否在一定范围内 :param diff_array: :param range: :return: """ for i in range(1, 6, 1): diff_up = diff_array[-i] > -diff_deviate diff_down = diff_array[-i] < diff_deviate if diff_up and diff_down: diff_range = True else: diff_range = False return diff_range def on_diff_to_up_down(self, fastdiffema, slowdiffema): """ 差离线上穿、下穿 :param diff_ema: :return: """ current_fast_diff = fastdiffema[-1] last_fast_diff = fastdiffema[-2] current_slow_diff = slowdiffema[-1] last_slow_diff = slowdiffema[-2] to_up_down = 0 if current_fast_diff > current_slow_diff and last_fast_diff <= last_slow_diff: to_up_down = 1 elif current_fast_diff < current_slow_diff and last_fast_diff >= last_slow_diff: to_up_down = -1 else: to_up_down = 0 return to_up_down
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 RisBollStrategy(CtaTemplate): """ 目前使用中轨加速,可以考虑使用另外一根均线来加速,这样可以避免在开仓时被平。 """ author = "yunya" open_window = 15 boll_length = 80 boll_dev = 2.0 rsi_window = 12 rsi_entry = 19 atr_window = 16 long_trailing = 4.0 short_trailing = 4.0 fixed_size = 1 rsi_long = 0 rsi_short = 0 rsi_value = 0 atr_value = 0 boll_up = 0 boll_down = 0 boll_mid = 0 boll_mid_new = 0 exit_long = 0 exit_short = 0 boll_length_new = 0 exit_long_nex = 0 exit_long_last = 0 exit_short_nex = 0 exit_short_last = 0 long_stop_trade = 0 short_stop_trade = 0 trade_price_long = 0 trade_price_short = 0 parameters = [ "open_window", "boll_length", "boll_dev", "rsi_window", "rsi_entry", "atr_window", "long_trailing", "short_trailing", "fixed_size", ] variables = [ "rsi_long", "rsi_short", "rsi_value", "atr_value", "boll_up", "boll_down", "boll_mid", "boll_mid_new", "exit_long", "exit_short", "boll_length_new", "exit_long_nex", "exit_long_last", "exit_short_nex", "exit_short_last", "long_stop_trade", "short_stop_trade", "trade_price_long", "trade_price_short", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.open_window, self.on_xmin_bar) self.am = ArrayManager(int(self.boll_length) + 100) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.rsi_long = 50 + self.rsi_entry self.rsi_short = 50 - self.rsi_entry self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_xmin_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # 计算原布林带 self.boll_up, self.boll_down = self.am.boll(self.boll_length, self.boll_dev) self.boll_mid = am.sma(self.boll_length) self.rsi_value = am.rsi(self.rsi_window) # 如果没有仓位,两条布林window一样 if self.pos == 0: self.atr_value = am.atr(self.atr_window) 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 if self.rsi_value > self.rsi_long: self.buy(self.boll_up, self.fixed_size, True) if self.rsi_value < self.rsi_short: self.short(self.boll_down, self.fixed_size, True) elif self.pos > 0: # 上涨或下跌时,布林中轨均值减1 close_long = am.close[-1] > am.close[-2] > am.close[-3] > am.close[-4] if close_long: self.boll_length_new -= 1 self.boll_length_new = max(self.boll_length_new, 10) # 计算新的布林带 self.boll_mid_new = am.sma(self.boll_length_new, True) # 仓位是long 时,如果价格上穿新布林中轨 con1 = am.close[-1] < self.boll_mid_new[-1] con2 = am.close[-2] >= self.boll_mid_new[-2] if con1 and con2: self.exit_long_nex = am.close[-1] # 保存当前收盘价 if self.exit_long_nex > self.exit_long_last or self.exit_long_last == 0: self.exit_long_last = self.exit_long_nex self.boll_length_new = self.boll_length # 下穿新均线,以原布林均线挂出停止单,避免快速下跌而无法止损 self.exit_long = self.boll_mid else: # 收盘价在两条均线平均价上方,以当前收盘价挂出限价单 if self.am.close[-1] > ((self.boll_mid + self.boll_mid_new[-1]) / 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 else: self.exit_long = self.boll_mid if bar.close_price < self.trade_price_long * (1 - self.long_trailing / 100): exit_long_price = self.trade_price_long * (1 - (self.long_trailing + 1) / 100) self.exit_long = max(exit_long_price, self.exit_long) self.exit_long = max(self.exit_long, self.long_stop_trade) self.sell(self.exit_long, abs(self.pos), True) elif self.pos < 0: close_short = am.close[-1] < am.close[-2] < am.close[-3] < am.close[-4] if close_short: self.boll_length_new -= 1 self.boll_length_new = max(self.boll_length_new, 10) # 计算新的布林带 self.boll_mid_new = am.sma(self.boll_length_new, True) # 仓位是short 时,如果价格上穿新布林中轨 con3 = am.close[-1] > self.boll_mid_new[-1] con4 = am.close[-2] <= self.boll_mid_new[-2] if con3 and con4: self.exit_short_nex = am.close[-1] if self.exit_short_nex < self.exit_short_last or self.exit_short_last == 0: self.exit_short_last = self.exit_short_nex self.boll_length_new = self.boll_length self.exit_short = self.boll_mid else: if self.am.close[-1] < (self.boll_mid + self.boll_mid_new[-1] / 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 # 如果 有3%以上的收益,止损价为买入成交价 if bar.close_price > self.trade_price_short * (1 + self.short_trailing / 100): exit_short_price = self.trade_price_short * (1 + (self.short_trailing + 1) / 100) self.exit_short = min(exit_short_price, self.exit_short) self.exit_short = min(self.exit_short, self.short_stop_trade) self.cover(self.exit_short, abs(self.pos), True) self.put_event() self.sync_data() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.trade_price_long = trade.price # 成交最高价 self.long_stop_trade = self.trade_price_long - 2 * self.atr_value else: self.trade_price_short = trade.price self.short_stop_trade = self.trade_price_short + 2 * self.atr_value self.sync_data() self.put_event()
class BollVixJStrategy(CtaTemplate): """ 一、灵感来源 我基于动量自适应布林短线策略的原始版本,做了非常小的修改,但回测效果惊人。 「gcouple.j」动量自适应布林短线策略v1 https://forum.quantclass.cn/d/1784-gcouplej-btc61eth1481 1.1 自适应布林的原理: 对于时间窗口参数是n1, 标准差倍数m的布林策略 close:每周期收盘价 ma(n1):时间窗口参数是n1的移动平均值 std(n1):时间窗口参数是n1的标准差 突破布林上轨的条件 close > ma(n1) + m*std(n1) 即:(close-ma(n1))/std(n1) > m 突破布林下轨条件 close < ma(n1) - m*std(n1) 即:-(close-ma(n1))/std(n1) > m 将布林突破上下轨的条件合并 abs((close-ma(n1))/std(n1)) > m 通过将m转为n的函数达到构建自适应布林的目的,即 令 m=max(abs((close-ma(n1))/std(n1))) 此处修改,令m=mean(abs((close-ma(n1))/std(n1))) 由此,只需一个参数即可完成布林通道的构建。 1.2 对指标构建自适应布林通道 通过对动量指标构建自适应布林通道,可以得到日内级别短线参数。 二、策略思路 将 df['m'] = df['z_score'].rolling(window=n1).max().shift(1) 改成 df['m'] = df['z_score'].rolling(window=n1).mean() 三、代码 3.1、策略代码 def adaptboll_with_mtm_v2(df, para=[90]): n1 = para[0] # 计算动量因子 df['mtm'] = df['close'] / df['close'].shift(n1) - 1 df['mtm_mean'] = df['mtm'].rolling(window=n1, min_periods=1).mean() # 基于价格atr,计算波动率因子wd_atr df['c1'] = df['high'] - df['low'] df['c2'] = abs(df['high'] - df['close'].shift(1)) df['c3'] = abs(df['low'] - df['close'].shift(1)) df['tr'] = df[['c1', 'c2', 'c3']].max(axis=1) df['atr'] = df['tr'].rolling(window=n1, min_periods=1).mean() df['avg_price'] = df['close'].rolling(window=n1, min_periods=1).mean() df['wd_atr'] = df['atr'] / df['avg_price'] # 参考ATR,对MTM指标,计算波动率因子 df['mtm_l'] = df['low'] / df['low'].shift(n1) - 1 df['mtm_h'] = df['high'] / df['high'].shift(n1) - 1 df['mtm_c'] = df['close'] / df['close'].shift(n1) - 1 df['mtm_c1'] = df['mtm_h'] - df['mtm_l'] df['mtm_c2'] = abs(df['mtm_h'] - df['mtm_c'].shift(1)) df['mtm_c3'] = abs(df['mtm_l'] - df['mtm_c'].shift(1)) df['mtm_tr'] = df[['mtm_c1', 'mtm_c2', 'mtm_c3']].max(axis=1) df['mtm_atr'] = df['mtm_tr'].rolling(window=n1, min_periods=1).mean() # 参考ATR,对MTM mean指标,计算波动率因子 df['mtm_l_mean'] = df['mtm_l'].rolling(window=n1, min_periods=1).mean() df['mtm_h_mean'] = df['mtm_h'].rolling(window=n1, min_periods=1).mean() df['mtm_c_mean'] = df['mtm_c'].rolling(window=n1, min_periods=1).mean() df['mtm_c1'] = df['mtm_h_mean'] - df['mtm_l_mean'] df['mtm_c2'] = abs(df['mtm_h_mean'] - df['mtm_c_mean'].shift(1)) df['mtm_c3'] = abs(df['mtm_l_mean'] - df['mtm_c_mean'].shift(1)) df['mtm_tr'] = df[['mtm_c1', 'mtm_c2', 'mtm_c3']].max(axis=1) df['mtm_atr_mean'] = df['mtm_tr'].rolling(window=n1, min_periods=1).mean() indicator = 'mtm_mean' # mtm_mean指标分别乘以三个波动率因子 df[indicator] = df[indicator] * df['mtm_atr'] df[indicator] = df[indicator] * df['mtm_atr_mean'] df[indicator] = df[indicator] * df['wd_atr'] # 对新策略因子计算自适应布林 df['median'] = df[indicator].rolling(window=n1).mean() df['std'] = df[indicator].rolling(n1, min_periods=1).std(ddof=0) # ddof代表标准差自由度 df['z_score'] = abs(df[indicator] - df['median']) / df['std'] # df['m'] = df['z_score'].rolling(window=n1).max().shift(1) df['m'] = df['z_score'].rolling(window=n1).mean() df['up'] = df['median'] + df['std'] * df['m'] df['dn'] = df['median'] - df['std'] * df['m'] # 突破上轨做多 condition1 = df[indicator] > df['up'] condition2 = df[indicator].shift(1) <= df['up'].shift(1) condition = condition1 & condition2 df.loc[condition, 'signal_long'] = 1 # 突破下轨做空 condition1 = df[indicator] < df['dn'] condition2 = df[indicator].shift(1) >= df['dn'].shift(1) condition = condition1 & condition2 df.loc[condition, 'signal_short'] = -1 # 均线平仓(多头持仓) condition1 = df[indicator] < df['median'] condition2 = df[indicator].shift(1) >= df['median'].shift(1) condition = condition1 & condition2 df.loc[condition, 'signal_long'] = 0 # 均线平仓(空头持仓) condition1 = df[indicator] > df['median'] condition2 = df[indicator].shift(1) <= df['median'].shift(1) condition = condition1 & condition2 df.loc[condition, 'signal_short'] = 0 # ===由signal计算出实际的每天持有仓位 # signal的计算运用了收盘价,是每根K线收盘之后产生的信号,到第二根开盘的时候才买入,仓位才会改变。 df['signal_short'].fillna(method='ffill', inplace=True) df['signal_long'].fillna(method='ffill', inplace=True) df['signal'] = df[['signal_long', 'signal_short']].sum(axis=1) df['signal'].fillna(value=0, inplace=True) # df['signal'] = df[['signal_long', 'signal_short']].sum(axis=1, min_count=1, # skipna=True) # 若你的pandas版本是最新的,请使用本行代码代替上面一行 temp = df[df['signal'].notnull()][['signal']] temp = temp[temp['signal'] != temp['signal'].shift(1)] df['signal'] = temp['signal'] df.drop(['signal_long', 'signal_short', 'atr', 'z_score'], axis=1, inplace=True) return df 3.2、策略参数组合 # 策略参数组合 def adaptboll_with_mtm_v2_para_list(m_list=range(1, 100, 1)): print('参数遍历范围:') print('m_list', list(m_list)) para_list = [] for m in m_list: para = [m] para_list.append(para) return para_list 4.2、策略总体评价 strategy_name symbol 年化收益回撤比 adaptboll_with_mtm_v2 BTC 14.415570606108213 adaptboll_with_mtm_v2 ETH 38.00534253439086 """ author = "yunya" open_window = 15 boll_length = 50 fixed_size = 1 atr_value = 0 mtm_ma_current = 0 mtm_ma_last = 0 boll_up_current = 0 boll_up_last = 0 boll_down_current = 0 boll_down_last = 0 boll_mid_current = 0 boll_mid_last = 0 bar_length = 8 parameters = [ "open_window", "boll_length", "fixed_size", ] variables = [ "atr_value", "mtm_ma_current", "mtm_ma_last", "boll_up_current", "boll_up_last", "boll_down_current", "boll_down_last", "boll_mid_current", "boll_mid_last", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.open_window, self.on_xmin_bar) self.am = ArrayManager(int(self.boll_length) * (self.bar_length * 2)) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(20) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_xmin_bar(self, bar: BarData): """ m=mean(abs((close-ma(n1))/std(n1))) :param bar: :return: """ self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # 计算动量因子 MTM mtm_array = radio_array(am.close, self.boll_length, self.bar_length) mtm_ma = talib.MA(mtm_array, self.boll_length) # 计算atr 相对emaatr的波动率 计算波动率因子wd_atr atr_array = am.atr(self.boll_length, array=True) self.atr_value = atr_array[-1] atr_ma = talib.MA(atr_array, self.boll_length) wd_atr = atr_array / atr_ma # 参考ATR,对MTM指标,计算波动率因子 mtm_high = radio_array(am.high, self.boll_length, self.bar_length) mtm_low = radio_array(am.low, self.boll_length, self.bar_length) mtm_close = radio_array(am.close, self.boll_length, self.bar_length) mtm_atr_array = talib.ATR(mtm_high, mtm_low, mtm_close, self.boll_length) mtm_atr_ma = talib.MA(mtm_atr_array, self.boll_length) # 参考ATR,对MTM mean指标,计算波动率因子 mtm_high_mean = talib.MA(mtm_high, self.boll_length) mtm_low_mean = talib.MA(mtm_low, self.boll_length) mtm_close_mean = talib.MA(mtm_close, self.boll_length) mtm_atr_mean_array = talib.ATR(mtm_high_mean, mtm_low_mean, mtm_close_mean, self.boll_length) mtm_atr_meam_ma = talib.MA(mtm_atr_mean_array, self.boll_length) # mtm_mean指标分别乘以三个波动率 mtm_ma = mtm_ma * wd_atr[-self.boll_length * self.bar_length:] mtm_ma = mtm_ma * mtm_atr_ma[-self.boll_length * self.bar_length:] mtm_ma = mtm_ma * mtm_atr_meam_ma[-self.boll_length * self.bar_length:] mtm_meam = talib.MA(mtm_ma, self.boll_length) mtm_std = talib.STDDEV(mtm_meam, self.boll_length) mtm_dev = abs(mtm_ma - mtm_meam) / mtm_std mtm_dev_me = talib.MA(mtm_dev, self.boll_length) boll_up = mtm_meam + mtm_std * mtm_dev_me boll_down = mtm_meam - mtm_std * mtm_dev_me # 值 self.mtm_ma_current = mtm_ma[-1] self.mtm_ma_last = mtm_ma[-2] self.boll_up_current = boll_up[-1] self.boll_up_last = boll_up[-2] self.boll_down_current = boll_down[-1] self.boll_down_last = boll_down[-2] self.boll_mid_current = mtm_meam[-1] self.boll_mid_last = mtm_meam[-2] # 如果没有仓位,两条布林window一样 if self.pos == 0: if self.mtm_ma_current > self.boll_up_current and self.mtm_ma_last <= self.boll_up_last: self.buy(bar.close_price, self.fixed_size) elif self.mtm_ma_current < self.boll_down_current and self.mtm_ma_last >= self.boll_down_last: self.short(bar.close_price, self.fixed_size) elif self.pos > 0: if self.mtm_ma_current < self.boll_mid_current and self.mtm_ma_last >= self.boll_mid_last: self.sell(bar.close_price, abs(self.pos)) # 要优化 elif self.pos < 0: if self.mtm_ma_current > self.boll_mid_current and self.mtm_ma_last <= self.boll_mid_last: self.cover(bar.close_price, abs(self.pos)) self.put_event() self.sync_data() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ pass
class AberrationBiasStrategy(CtaTemplate): """ 目前使用中轨加速,可以考虑使用另外一根均线来加速,这样可以避免在开仓时被平。 """ author = "yunya" open_window = 60 boll_length = 80 boll_dev = 2.0 bias = 1.0 cci_length = 6 cci_exit = 10.0 fixed_size = 1 boll_up = 0 boll_down = 0 boll_mid = 0 boll_mid_new = 0 boll_mid_array = 0 bias_value_array = 0 bias_value = 0 cci_value = 0 exit_long = 0 exit_short = 0 boll_length_new = 0 exit_long_nex = 0 exit_long_last = 0 exit_short_nex = 0 exit_short_last = 0 parameters = [ "open_window", "boll_length", "boll_dev", "bias", "cci_length", "cci_exit", "fixed_size", ] variables = [ "boll_up", "boll_down", "boll_mid", "bias_value", "cci_value", "exit_long", "exit_short", "boll_length_new", "exit_long_nex", "exit_long_last", "exit_short_nex", "exit_short_last", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(self.on_bar, self.open_window, self.on_xmin_bar) self.am = ArrayManager(int(self.boll_length) + 100) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_xmin_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # 计算原布林带 self.boll_up, self.boll_down = self.am.boll(self.boll_length, self.boll_dev) self.boll_mid_array = am.sma(self.boll_length, True) self.boll_mid = self.boll_mid_array[-1] self.bias_value_array = (self.am.close - self.boll_mid_array) / self.boll_mid_array self.bias_value = self.bias_value_array[-1] self.cci_value = am.cci(self.cci_length) # 如果没有仓位,两条布林window一样 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 if self.cci_value > self.cci_exit: self.buy(self.boll_up, self.fixed_size, True) if self.cci_value < -self.cci_exit: self.short(self.boll_down, self.fixed_size, True) elif self.pos > 0: # 上涨或下跌时,布林中轨均值减1 close_long = am.close[-1] > am.close[-2] > am.close[-3] if close_long: self.boll_length_new -= 1 self.boll_length_new = max(self.boll_length_new, 20) # 计算新的布林带 self.boll_mid_new = am.sma(self.boll_length_new, True) # 仓位是long 时,如果价格上穿新布林中轨 con1 = am.close[-1] < self.boll_mid_new[-1] con2 = am.close[-2] >= self.boll_mid_new[-2] if con1 and con2: self.exit_long_nex = am.close[-1] # 保存当前收盘价 if self.exit_long_nex > self.exit_long_last or self.exit_long_last == 0: self.exit_long_last = self.exit_long_nex self.boll_length_new = self.boll_length # 下穿新均线,以原布林均线挂出停止单,避免快速下跌而无法止损 self.exit_long = self.boll_mid # print(f"我是多单,exitlast:{self.exit_short_last},重置布林中轨参数,止损挂{self.exit_long}:") else: # 收盘价在两条均线平均价上方,以当前收盘价挂出限价单 if self.am.close[-1] > ( (self.boll_mid + self.boll_mid_new[-1]) / 2): self.exit_long = bar.close_price # print(f"我是多单,收盘价在两个中轨均值上方,以收盘价挂止损单:{self.exit_long}") 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 # print(f"我是多单,收盘价在新中轨上方,以原中轨挂止损单:{self.exit_long}") if self.bias_value > self.bias: self.exit_long = max(bar.close_price, self.exit_long) self.sell(self.exit_long, abs(self.pos), True) elif self.pos < 0: close_short = am.close[-1] < am.close[-2] < am.close[-3] if close_short: self.boll_length_new -= 1 self.boll_length_new = max(self.boll_length_new, 20) # 计算新的布林带 self.boll_mid_new = am.sma(self.boll_length_new, True) # 仓位是short 时,如果价格上穿新布林中轨 con3 = am.close[-1] > self.boll_mid_new[-1] con4 = am.close[-2] <= self.boll_mid_new[-2] if con3 and con4: self.exit_short_nex = am.close[-1] if self.exit_short_nex < self.exit_short_last or self.exit_short_last == 0: self.exit_short_last = self.exit_short_nex self.boll_length_new = self.boll_length self.exit_short = self.boll_mid else: if self.am.close[-1] < (self.boll_mid + self.boll_mid_new[-1] / 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 if self.bias_value < -self.bias: self.exit_short = min(self.exit_short, bar.close_price) self.cover(self.exit_short, abs(self.pos), True) self.put_event() self.sync_data() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() pass def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event() pass
class DudlThrustKkStrategy(CtaTemplate): """""" author = "yunyu" xminute_window = 1 rolling_period = 70 upper_open = 0.2 lower_open = 0.2 cci_window = 30 keltner_window = 24 keltner_dev = 1 fixed_size = 1 cci_value = 0 exit_kk_up = 0 exit_kk_down = 0 dualthrust_up = 0 dualthrust_down = 0 ask = 0 bid = 0 parameters = [ "xminute_window", "rolling_period", "upper_open", "lower_open", "cci_window", "keltner_window", "keltner_dev", "fixed_size", ] variables = [ "dualthrust_up", "dualthrust_down", "cci_value", "exit_kk_up", "exit_kk_down", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = NewBarGenerator(on_bar=self.on_bar, window=self.xminute_window, on_window_bar=self.on_min_bar, interval=Interval.MINUTE) 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) self.ask = tick.ask_price_1 # 卖一价 self.bid = tick.bid_price_1 # 买一价 def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_min_bar(self, bar: BarData): """ Callback of new bar data update. """ self.am.update_bar(bar) self.cancel_all() if not self.am.inited: return self.dualthrust_up, self.dualthrust_down = self.dualthrust( self.am.high, self.am.low, self.am.close, self.am.open, self.rolling_period, self.upper_open, self.lower_open) self.cci_value = self.am.cci(self.cci_window) print(self.cci_value) self.keltner_up, self.keltner_down = self.am.keltner( self.keltner_window, self.keltner_dev) if self.pos == 0: if self.cci_value > 0: self.buy(self.dualthrust_up, self.fixed_size, True) elif self.cci_value < 0: self.short(self.dualthrust_down, self.fixed_size, True) elif self.pos > 0: self.sell(self.exit_kk_down, self.fixed_size, True) elif self.pos < 0: self.cover(self.exit_kk_up, self.fixed_size, True) self.put_event() self.sync_data() self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass # self.put_event() def market_order(self): """""" pass # self.buy(self.last_tick.limit_up, 1) # self.write_log("执行市价单测试") def limit_order(self): """""" pass # self.buy(self.last_tick.limit_down, 1) # self.write_log("执行限价单测试") def stop_order(self): """""" pass # self.buy(self.last_tick.ask_price_1, 1, True) # self.write_log("执行停止单测试") def dualthrust(self, high, low, close, open, n, k1, k2): """ :param high: :param low: :param close: :return: """ #计算N日最高价的最高价,收盘价的最高价、最低价,最低价的最低价 hh = high[-n:].max() lc = close[-n:].min() hc = close[-n:].max() ll = low[-n:].min() #计算range,上下轨的距离前一根K线开盘价的距离 range = max(hh - lc, hc - ll) up = open[-2] + k1 * range down = open[-2] - k2 * range return up, down
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()
class MacdBollDcStrategy(CtaTemplate): """""" author = "云崖" open_window = 2 xminute_window = 15 xhour_window = 1 fast_length = 14 show_length = 28 boll_length = 20 boll_dev = 2.0 dc_length = 30 trailing_tax = 2.0 fixed_size = 1 macd_inited = 0 boll_up = 0 boll_down = 0 dc_up = 0 dc_down = 0 exit_long = 0 exit_short = 0 long_stop = 0 short_stop = 0 intra_trade_high = 0 intra_trade_low = 0 parameters = [ "open_window", "xminute_window", "xhour_window", "fast_length", "show_length", "boll_length", "boll_dev", "dc_length", "trailing_tax", "fixed_size", ] variables = [ "macd_inited", "boll_up", "boll_down", "dc_up", "dc_down", "exit_long", "exit_short", "long_stop", "short_stop", ] def __init__(self, cta_engine, strategy_nam_xminutee, vt_symbol, setting): """""" super().__init__(cta_engine, strategy_nam_xminutee, vt_symbol, setting) self.bg_open = NewBarGenerator(self.on_bar, self.open_window, self.on_open_bar) self.am_open = ArrayManager() self.bg_xminute = NewBarGenerator(self.on_bar, self.xminute_window, self.on_xminute_bar) self.am_xminute = ArrayManager(150) self.bg_xhour = NewBarGenerator(self.on_bar, self.xhour_window, self.on_xhour_bar, interval=Interval.HOUR) self.am_xhour = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg_xminute.update_tick(tick) self.ask = tick.ask_price_1 # 卖一价 self.bid = tick.bid_price_1 # 买一价 def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg_xhour.update_bar(bar) self.bg_xminute.update_bar(bar) self.bg_open.update_bar(bar) def on_open_bar(self, bar: BarData): """""" self.cancel_all() self.am_open.update_bar(bar) if not self.am_xminute.inited or not self.am_open.inited: return 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.macd_inited > 0: self.buy(self.boll_up, self.fixed_size, True) elif self.macd_inited < 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 long_high = self.intra_trade_high * (1 - self.trailing_tax / 100) self.long_stop = max(self.exit_long, long_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) stop_low = self.intra_trade_low * (1 + self.trailing_tax / 100) self.short_stop = min(self.exit_short, stop_low) self.cover(self.short_stop, abs(self.pos), True) self.put_event() def on_xminute_bar(self, bar: BarData): """""" self.am_xminute.update_bar(bar) if not self.am_xminute.inited: return self.boll_up, self.boll_down = self.am_xminute.boll( self.boll_length, self.boll_dev) self.exit_short, self.exit_long = self.am_xminute.donchian( self.dc_length) def on_xhour_bar(self, bar: BarData): """ :param bar: :type bar: :return: :rtype: """ self.am_xhour.update_bar(bar) if self.am_xhour.inited: return fast_ema_value = self.am_xhour.ema(self.fast_length, True) show_ema_value = self.am_xhour.ema(self.show_length, True) diff = fast_ema_value - show_ema_value macd_diff = (fast_ema_value - show_ema_value) / show_ema_value * 100 if diff[-2] > macd_diff[-2]: self.macd_inited = 1 elif diff[-2] < macd_diff[-2]: self.macd_inited = -1 def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() 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. """ self.put_event()
class Boll_Std_vix(CtaTemplate): """""" author = "yunya" win_open = 15 boll_window = 80 atr_window = 30 sl_multiplier = 10.0 fixed_size = 1 entry_crossover = 0 atr_value = 0 intra_trade_high = 0 intra_trade_low = 0 long_stop = 0 short_stop = 0 parameters = [ "win_open", "boll_window", "sl_multiplier", "fixed_size", ] variables = [ "entry_crossover", "atr_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) self.bg = NewBarGenerator(self.on_bar, self.win_open, self.on_xmin_bar) self.am = ArrayManager(self.boll_window + 100) def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") 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. """ self.bg.update_bar(bar) def on_xmin_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return # Calculate array 计算数组 self.sma_array = am.sma(self.boll_window, True) std_array = am.std(self.boll_window, True) dev = abs(self.am.close[:-1] - self.sma_array[:-1]) / std_array[:-1] dev_max = dev[-self.boll_window:].max() self.boll_up_array = self.sma_array + std_array * dev_max self.boll_down_array = self.sma_array - std_array * dev_max # Get current and last index current_sma = self.sma_array[-1] last_sma = self.sma_array[-2] last_close = self.am.close[-2] currnet_boll_up = self.boll_up_array[-1] last_boll_up = self.boll_up_array[-2] current_boll_down = self.boll_down_array[-1] last_boll_down = self.boll_down_array[-2] # Get crossover if (bar.close_price > currnet_boll_up and last_close <= last_boll_up): self.entry_crossover = 1 elif (bar.close_price < current_boll_down and last_close >= last_boll_down): self.entry_crossover = -1 self.atr_value = am.atr(self.atr_window) if not self.pos: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if self.entry_crossover > 0: self.buy(bar.close_price, self.fixed_size, True) elif self.entry_crossover < 0: self.short(bar.close_price, 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.long_stop, abs(self.pos), True) elif self.pos < 0: self.intra_trade_high = bar.high_price self.intra_trade_low = min(self.intra_trade_low, bar.low_price) self.short_stop = self.intra_trade_low + self.atr_value * self.sl_multiplier self.cover(self.short_stop, abs(self.pos), True) self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ self.put_event() pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ self.put_event() 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