230 lines
7.4 KiB
Python
230 lines
7.4 KiB
Python
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() |