`from datetime import datetime
from typing import Any
import time
import numpy as np
from sqlalchemy import false
from vnpy.trader.constant import Offset, Direction, Status
from vnpy_ctastrategy import (
CtaTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
class Macd_Ma_sjc_tick(CtaTemplate):
""""""
#开发都姓名
author = "LI CHUNBAO"
strategy_name = "MACD双金叉"
#定义参数
fast_window = 20
slow_window = 40
fixed_size = 1 #交易手数
period = 5
#定义变量
open_pos = None
shut_pos = None
buy_price = 0
sell_price = 0
short_price = 0
cover_price = 0
Stop_loss_long = 0 # 多头止损价格
Stop_loss_short = 0 # 空头止损价格
profit_loss = 0
#添加参数和变量到对应的列表
parameters = [
"fast_window",
"slow_window",
"fixed_size",
"period",
]
variables = [
"buy_price",
"sell_price",
"short_price",
"cover_price",
"profit_loss"
]
def __init__(
self,
cta_engine: Any,
strategy_name: str,
vt_symbol: str,
setting: dict,
):
""""""
super().__init__(cta_engine,strategy_name,vt_symbol,setting)
self.bid_price1 = 0
self.ask_price1 = 0
self.buy_vt_orderids = []
self.sell_vt_orderids = []
self.short_vt_orderids = []
self.cover_vt_orderids = []
self.buy_signal = False
self.sell_signal = False
self.short_signal = False
self.cover_signal = False
self.active_order = False
self.cha_array: np.ndarray = np.zeros(2)
self.bg = BarGenerator(self.on_bar,self.period,self.on_period_min_bar)
self.am = ArrayManager()
def on_init(self):
"""
Callback when strategy is inited.
"""
self.write_log("策略初始化")
self.load_bar(30)
if not self.am.inited:
self.write_log("数据不足,未能完成策略初始化")
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)
if self.pos == 0:
# 检查之前委托都已经结束
if not self.buy_vt_orderids:
# 检查存在信号
if self.buy_signal:
self.buy_vt_orderids = self.buy(bar.open_price + 5, self.fixed_size) #买入开仓
self.write_log(f"开多")
# print(f"开多{bar.datetime}")
self.buy_signal = False
else:
# 遍历委托号列表撤单
for vt_orderid in self.buy_vt_orderids:
self.cancel_order(vt_orderid)
if not self.short_vt_orderids:
if self.short_signal:
self.short_vt_orderids = self.short(bar.open_price - 5,self.fixed_size) #卖出开仓
self.write_log(f"开空")
# print(f"开空{bar.datetime}")
self.short_signal = False
else:
for vt_orderid in self.short_vt_orderids:
self.cancel_order(vt_orderid)
elif self.pos > 0:
if not self.sell_vt_orderids:
if self.sell_signal:
self.sell_vt_orderids = self.sell(bar.open_price - 5, abs(self.pos)) #卖出平仓
self.write_log(f"卖平")
self.sell_signal = False
self.short_vt_orderids = self.short(bar.open_price - 5,self.fixed_size) #卖出开仓
self.write_log(f"反手开空")
else:
for vt_orderid in self.sell_vt_orderids:
self.cancel_order(vt_orderid)
elif self.pos < 0:
if not self.cover_vt_orderids:
if self.cover_signal:
self.cover_vt_orderids = self.cover(bar.open_price + 5, abs(self.pos)) #买入平仓
self.write_log(f"买平")
self.cover_signal = False
self.buy_vt_orderids = self.buy(bar.open_price + 5, self.fixed_size) #买入开仓
self.write_log(f"反手开多")
else:
for vt_orderid in self.cover_vt_orderids:
self.cancel_order(vt_orderid)
if abs(self.pos)>1:
print(f"{bar.datetime} 仓位:{self.pos}")
self.put_event()
def on_period_min_bar(self,bar:BarData):
"""period回调函数"""
self.am.update_bar(bar)
if not self.am.inited:
return
# 判断MA交叉
fast_ma = self.am.sma(self.fast_window,array=True)
fast_ma_1 =fast_ma[-1]
fast_ma_0 =fast_ma[-2]
slow_ma = self.am.sma(self.slow_window,array=True)
slow_ma_1 =slow_ma[-1]
slow_ma_0 =slow_ma[-2]
cross_over_ma = (fast_ma_1 >= slow_ma_1 and fast_ma_0 < slow_ma_0) #金叉
cross_below_ma = (fast_ma_1 <= slow_ma_1 and fast_ma_0 > slow_ma_0)#死叉
# 判断MACD交叉
DIFF,DEA,MACD= self.am.macd(12,26,9,array=True)
DIFF_1 = DIFF[-1]
DIFF_0 = DIFF[-2]
DEA_1 = DEA[-1]
DEA_0 = DEA[-2]
cross_over_macd = (DIFF_1 >= DEA_1 and DIFF_0 < DEA_0) #金叉
cross_below_macd = (DIFF_1 <= DEA_1 and DIFF_0 > DEA_0)#死叉
# 统计macd和ma双交叉情况
if cross_over_ma:
self.cha_array[:-1] = self.cha_array[1:]
self.cha_array[-1] = 1
elif cross_below_ma:
self.cha_array[:-1] = self.cha_array[1:]
self.cha_array[-1] = -1
if cross_over_macd:
self.cha_array[:-1] = self.cha_array[1:]
self.cha_array[-1] = 1
elif cross_below_macd:
self.cha_array[:-1] = self.cha_array[1:]
self.cha_array[-1] = -1
# print(f"时间:{bar.datetime} {self.cha_array}")
# 生成开平仓交易信号
if self.cha_array.sum()>= 2:
# print(f"{bar.datetime}两金叉")
#缓存止损价格
self.Stop_loss_long = bar.low_price
if self.pos == 0:
self.buy_signal = True
self.sell_signal = False
self.short_signal = False
self.cover_signal = False
elif self.pos < 0:
self.buy_signal = False
self.sell_signal = False
self.short_signal = False
self.cover_signal = True
self.cha_array = np.zeros(2)
elif self.cha_array.sum() <= -2:
# print(f"{bar.datetime}双死叉")
#缓存止损价格
self.Stop_loss_short = bar.high_price
if self.pos == 0:
self.buy_signal = False
self.sell_signal = False
self.short_signal = True
self.cover_signal = False
elif self.pos > 0:
self.buy_signal = False
self.sell_signal = True
self.short_signal = False
self.cover_signal = False
self.cha_array = np.zeros(2)
self.put_event()
def on_trade(self, trade: TradeData):
"""
Callback of new trade data update.
"""
#记录开平仓价格,并统计利润点数。
if trade.offset == Offset.OPEN:
if trade.direction == Direction.LONG:
self.buy_price = trade.price
self.sell(self.Stop_loss_long,abs(self.pos),stop=True)
elif trade.direction == Direction.SHORT:
self.short_price = trade.price
self.cover(self.Stop_loss_short,abs(self.pos),stop=True)
elif trade.offset == Offset.CLOSETODAY or trade.offset == Offset.CLOSEYESTERDAY or trade.offset == Offset.CLOSE:
if trade.direction == Direction.LONG:
self.cover_price = trade.price
a = self.short_price - self.cover_price
self.profit_loss += a
elif trade.direction == Direction.SHORT:
self.sell_price = trade.price
b = self.sell_price - self.buy_price
self.profit_loss += b
# self.active_order = False
# msg = f"新的成交, 策略{self.strategy_name}, 方向{trade.direction}, 开平{trade.offset}, 当前仓位{self.pos},当前盈亏{self.profit_loss}"
# self.send_email(msg)
self.put_event()
def on_order(self, order: OrderData):
"""
Callback of new order data update.
"""
if order.status == Status.SUBMITTING:
# self.active_order = True
return
for buf_orderids in [
self.buy_vt_orderids,
self.sell_vt_orderids,
self.short_vt_orderids,
self.cover_vt_orderids
]:
if order.vt_orderid in buf_orderids:
buf_orderids.remove(order.vt_orderid)
# self.active_order = False
self.put_event()
def on_stop_order(self, stop_order: StopOrder):
"""
Callback of stop order update.
"""
pass`
以上是策略的完整代码,为什么我使用停止单后,仓位出现了这个结果(如下图所示)
逻辑上我的仓位只有三种可能:0、1、-1,加上停止单止损后,却出现了2和-2的情况。这是为什么?