from vnpy_ctastrategy import ( CtaTemplate, StopOrder, Direction, TickData, BarData, TradeData, OrderData, BarGenerator, ArrayManager, ) class TurtleSignalStrategy(CtaTemplate): """""" author = "用Python的交易员" entry_window: int = 20 exit_window: int = 10 atr_window: int = 20 fixed_size: int = 1 entry_up: float = 0 entry_down: float = 0 exit_up: float = 0 exit_down: float = 0 atr_value: float = 0 long_entry: float = 0 short_entry: float = 0 long_stop: float = 0 short_stop: float = 0 parameters = ["entry_window", "exit_window", "atr_window", "fixed_size"] variables = ["entry_up", "entry_down", "exit_up", "exit_down", "atr_value"] def on_init(self) -> None: """ Callback when strategy is inited. """ self.write_log("策略初始化") self.bg: BarGenerator = BarGenerator(self.on_bar) self.am: ArrayManager = ArrayManager() self.load_bar(20) def on_start(self) -> None: """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self) -> None: """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData) -> None: """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData) -> None: """ Callback of new bar data update. """ self.cancel_all() self.am.update_bar(bar) if not self.am.inited: return # Only calculates new entry channel when no position holding if not self.pos: self.entry_up, self.entry_down = self.am.donchian( self.entry_window ) self.exit_up, self.exit_down = self.am.donchian(self.exit_window) if not self.pos: self.atr_value = self.am.atr(self.atr_window) self.long_entry = 0 self.short_entry = 0 self.long_stop = 0 self.short_stop = 0 self.send_buy_orders(self.entry_up) self.send_short_orders(self.entry_down) elif self.pos > 0: self.send_buy_orders(self.entry_up) sell_price: float = max(self.long_stop, self.exit_down) self.sell(sell_price, abs(self.pos), True) elif self.pos < 0: self.send_short_orders(self.entry_down) cover_price: float = min(self.short_stop, self.exit_up) self.cover(cover_price, abs(self.pos), True) self.put_event() def on_trade(self, trade: TradeData) -> None: """ Callback of new trade data update. """ if trade.direction == Direction.LONG: self.long_entry = trade.price self.long_stop = self.long_entry - 2 * self.atr_value else: self.short_entry = trade.price self.short_stop = self.short_entry + 2 * self.atr_value def on_order(self, order: OrderData) -> None: """ Callback of new order data update. """ pass def on_stop_order(self, stop_order: StopOrder) -> None: """ Callback of stop order update. """ pass def send_buy_orders(self, price: float) -> None: """""" t: float = self.pos / self.fixed_size if t < 1: self.buy(price, self.fixed_size, True) if t < 2: self.buy(price + self.atr_value * 0.5, self.fixed_size, True) if t < 3: self.buy(price + self.atr_value, self.fixed_size, True) if t < 4: self.buy(price + self.atr_value * 1.5, self.fixed_size, True) def send_short_orders(self, price: float) -> None: """""" t: float = self.pos / self.fixed_size if t > -1: self.short(price, self.fixed_size, True) if t > -2: self.short(price - self.atr_value * 0.5, self.fixed_size, True) if t > -3: self.short(price - self.atr_value, self.fixed_size, True) if t > -4: self.short(price - self.atr_value * 1.5, self.fixed_size, True)