策略思想
指标
使用SMA和收盘价
买入信号
价格出现连续4根k线的收盘价下跌,并且收盘价突破sma50
订单
出现交易信号后,价格回调2%,添加买入订单,止损价格当前价格×(1-0.05),止盈价格当前价格×(1+0.1)
回测结果
回测 | Value |
---|---|
初始资金 | 10000 |
期货品种 | ETH |
时间级别 | 1H |
回测时间 | 2017.7.15 - 2022.7.24 |
倍数 | 1 |
手续费 | 1% |
总盈利 | -8624.11 |
核心代码
加载数据
def load_csv_data(data_path, size=None, start=None, end=None):
return bt.feeds.GenericCSVData(
dataname=data_path,
nullvalue=0.0,
fromdate=start,
todate=end,
dtformat="%Y-%m-%d %H:%M:%S",
timeframe=bt.TimeFrame.Minutes,
datetime=0,
high=1,
low=2,
open=3,
close=4,
volume=5,
openinterest=-1
)
def create_cerebro(cash=10000.0, commission=0.01, stake=1, strategy=None):
"""
:param data: 数据
:param cash: 初始资金
:param commission: 佣金率
:param stake: 交易单位大小
:param strategy: 交易策略
:return:
"""
cerebro = bt.Cerebro()
# 设置启动资金
cerebro.broker.setcash(cash)
# 设置交易单位大小
cerebro.addsizer(bt.sizers.FixedSize, stake=stake)
# 设置佣金率为千分之一
cerebro.broker.setcommission(commission)
# 显示回测过程中的买入和卖出信号
cerebro.addobserver(bt.observers.Value)
# 显示了回测过程中的买入和卖出信号
cerebro.addobserver(bt.observers.BuySell)
return cerebro
策略
import datetime
import backtrader as bt
from utils import load_csv_data
class BreakthroughStrategy(bt.Strategy):
"""
突破策略
价格出现连续4根k线的收盘价下跌,并且收盘价突破sma50
"""
params = dict(
break_through=0.03,
callback=0.02, # 价格回调比例
period=50, # sma周期
down_day=4, # 连续下跌天数
stop_loss=0.05, # 止损比例
take_profit=0.1, # 止盈比例
validity_day=3, # 订单有效期
expired_day=1000, # 订单失效期
)
def notify_order(self, order):
if order.status == order.Completed:
self.holdstart = len(self)
if not order.alive() and order.ref in self.orefs:
self.orefs.remove(order.ref)
def __init__(self):
self.holdstart = None
self.dataclose = self.datas[0].close # 收盘价
self.sma = bt.ind.SMA(period=self.p.period, plot=True) # SMA
self.orefs = list() # order列表,用于存储尚未执行完成的订单
def next(self):
# 有尚未执行的订单
if self.orefs:
return
# 尚未进场
if not self.position:
# 获取近几日收盘价用于判断是否连续下跌
last_closes = list()
for i in range(1, self.p.down_day + 1):
last_closes.append(self.dataclose[-i])
# 连续N日下跌 在 sma上方
if last_closes == sorted(last_closes, reverse=True) and self.dataclose[0] > self.sma[0]:
p1 = self.dataclose[0] * (1.0 - self.p.callback)
p2 = p1 - self.p.stop_loss * p1
p3 = p1 + self.p.take_profit * p1
# 计算订单有效期
validity_day = datetime.timedelta(self.p.validity_day)
expired_day = valid3 = datetime.timedelta(self.p.expired_day)
size = self.broker.getcash() / self.data.high[0]
# 使用bracket orders设置买入卖出
if size is None:
size = 1
os = self.buy_bracket(size=size,
price=p1, valid=validity_day,
stopprice=p2, stopargs=dict(valid=expired_day),
limitprice=p3, limitargs=dict(valid=valid3), )
# 保存激活的的订单
self.orefs = [o.ref for o in os]
主程序
if __name__ == '__main__':
path = "D:\\work\\git\\Tools\\static\\data\\ETHUSDT_1h.csv"
data = load_csv_data(path)
cerebro = create_cerebro()
cerebro.adddata(data)
cerebro.addstrategy(BreakthroughStrategy)
cerebro.run()
cerebro.plot()
总结
目前从回测结果来看,该策略在破产的的边缘试探,表现结果十分糟糕。下一篇文章会对该策略进行优化,使策略可持续盈利,加油!!!!