from vnpy_ctastrategy import ( CtaTemplate, TargetPosTemplate, StopOrder, TickData, BarData, TradeData, OrderData, BarGenerator, ArrayManager, ) import numpy as np class MoveSpaceStrategy(CtaTemplate): author = "Quant789.com" # 策略参数 periods = 85 multiplier = 2 grid_step = 16 grid_length = 16 ss = 1 zhiying_count = 5 # 策略变量 avg = 0 flag = 0 hl2 = 0 atr_value = 0 up = 0 dn = 0 kg = 1 midKG = 0 cur_grid_price = 0 tp_price = 0 re_price = 0 statprice = 0 orderprice = 0 hh = 0 ll = 0 lots_top = 1 ggprice = 0 lots_scale = 0 has_send_order = 0 trss = 0 krss = 0 lorder_ids = [] sorder_ids = [] lpoisout = [] spoisout = [] pc_short_lots = 0 pc_long_lots = 0 # 用于存储网格价格的字典 grid_prices = {} parameters = [ "periods", "multiplier", "grid_step", "grid_length", "ss", "zhiying_count" ] variables = [ "avg", "flag", "hl2", "atr_value", "up", "dn", "kg", "midKG", "cur_grid_price", "tp_price", "re_price", "statprice", "orderprice", "hh", "ll", "lots_top", "ggprice", "lots_scale", "has_send_order", "trss", "krss", "lorder_ids", "sorder_ids", "lpoisout", "spoisout", "pc_short_lots", "pc_long_lots" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.am = ArrayManager() def on_init(self): self.write_log("策略初始化") self.load_bar(10) def on_start(self): self.write_log("策略启动") self.put_event() def on_stop(self): self.write_log("策略停止") self.put_event() def on_tick(self, tick: TickData): pass def on_bar(self, bar: BarData): self.am.update_bar(bar) if not self.am.inited: return # 计算ATR值和HL2值 self.atr_value = self.am.atr(self.periods) self.hl2 = (self.am.high[-1] + self.am.low[-1]) / 2 # 计算上轨和下轨 self.up = self.hl2 - (self.multiplier * self.atr_value) self.dn = self.hl2 + (self.multiplier * self.atr_value) if self.am.close[-2] >= self.up: self.up = max(self.up, self.am.high[-2]) if self.am.close[-2] <= self.dn: self.dn = min(self.dn, self.am.low[-2]) # 更新趋势信号 if self.kg == -1 and self.am.close[-1] > self.dn: self.kg = 1 elif self.kg == 1 and self.am.close[-1] < self.up: self.kg = -1 # 趋势转变时平仓 if self.kg == 1 and self.am.close[-2] < self.up and self.am.close[-3] >= self.up: if self.pos < 0: self.cover(bar.close_price, abs(self.pos)) self.lorder_ids.clear() self.lpoisout.clear() else: self.lorder_ids.clear() self.lpoisout.clear() elif self.kg == -1 and self.am.close[-2] > self.dn and self.am.close[-3] <= self.dn: if self.pos > 0: self.sell(bar.close_price, abs(self.pos)) self.lorder_ids.clear() self.lpoisout.clear() else: self.lorder_ids.clear() self.lpoisout.clear() # 初始化中轨值 if not self.statprice: self.statprice = bar.open_price self.midKG = 0 # 计算网格线相关数值 hh = ll = self.statprice for i in range(1, int(self.grid_length / 2) + 1): a_intprice = self.statprice + (self.grid_step * i) hh = max(a_intprice, hh) b_intprice = self.statprice - (self.grid_step * i) ll = min(b_intprice, ll) # 中轨值迭代 if self.am.high[-1] >= hh: self.rstatprice = self.statprice self.statprice = hh self.midKG = 0 if self.pos < 0: self.cover(bar.close_price, abs(self.pos)) self.lorder_ids.clear() self.lpoisout.clear() else: self.sell(bar.close_price, abs(self.pos)) self.lorder_ids.clear() self.lpoisout.clear() if self.am.low[-1] <= ll: self.rstatprice = self.statprice self.statprice = ll self.midKG = 0 if self.pos > 0: self.sell(bar.close_price, abs(self.pos)) self.lorder_ids.clear() self.lpoisout.clear() else: self.cover(bar.close_price, abs(self.pos)) self.lorder_ids.clear() self.lpoisout.clear() # 计算网格价格并存储到字典 if self.midKG == 0: self.cur_grid_price = self.statprice + self.grid_step * (self.grid_length / 2) for i in range(1, self.grid_length + 1): ggprice = self.cur_grid_price - (i - 1) * self.grid_step self.grid_prices["price_" + str(i)] = ggprice self.midKG = 1 # 网格交易逻辑 if self.midKG == 1: for i in range(1, self.grid_length + 1): orderprice = self.grid_prices.get("price_" + str(i), None) if orderprice is None: continue if self.kg > 0 and self.am.close[-2] > orderprice > self.am.low[-1]: self.trss += 1 self.grid_prices["price_" + str(i)] = -999999 elif self.kg < 0 and self.am.close[-2] < orderprice < self.am.high[-1]: self.krss += 1 self.grid_prices["price_" + str(i)] = 999999 if self.pos >= 0 and self.trss > 0 and self.kg > 0: self.buy(bar.open_price, self.trss * self.ss) self.lorder_ids.append(self.trss * self.ss) self.lpoisout.append(bar.open_price + self.grid_step * self.zhiying_count) self.trss = 0 elif self.pos <= 0 and self.krss > 0 and self.kg < 0: self.short(bar.open_price, self.krss * self.ss) self.sorder_ids.append(self.krss * self.ss) self.spoisout.append(bar.open_price - self.grid_step * self.zhiying_count) self.krss = 0 # 多头仓位止盈逻辑 if self.pos > 0 and len(self.lorder_ids) > 0: for i in range(len(self.lorder_ids)): pc_long = self.lorder_ids[i] pc_long_price = self.lpoisout[i] if self.am.high[-1] >= pc_long_price: self.sell(bar.close_price, pc_long) self.lorder_ids[i] = 99999999 self.lpoisout[i] = 99999999 # 空头仓位止盈逻辑 if self.pos < 0 and len(self.sorder_ids) > 0: for i in range(len(self.sorder_ids)): pc_short = self.sorder_ids[i] pc_short_price = self.spoisout[i] if self.am.low[-1] <= pc_short_price: self.cover(bar.close_price, pc_short) self.sorder_ids[i] = -1 self.spoisout[i] = -1 # 清空持仓时重置订单ID和位置列表 if self.pos == 0: self.lorder_ids.clear() self.lpoisout.clear() self.sorder_ids.clear() self.spoisout.clear() self.put_event()