均线交叉策略、海龟策略:基于backtrader框架的实现

原创文章第74篇,专注“个人成长与财富自由、世界运作的逻辑, AI量化投资”。

前面系列文章,把backtrader的方方面面介绍了一下,如何使用,内部运作机制,如何扩展。

客观讲,熟悉了bt之后,发现这个框架着实易用,易扩展。更重要的是,对于实战有很多贴心的考量,是可以应用于生产环境的”工业级“应用。

我们今天来实战几个策略。

01 双均线——信号策略

自定义一个信号,这个信号比较简单,就是短周期与长周期两条均线”交叉“作为信号signal。

注意:这里包含”金叉“和”死叉“

import backtrader as bt


# 自定义信号指标
class SignalDoubleSMA(bt.Indicator):
    lines = ('signal',)  # 声明 signal 线,交易信号放在 signal line 上
    params = dict(
        short_period=5,
        long_period=20)

    def __init__(self):
        self.s_ma = bt.ind.SMA(period=self.p.short_period)
        self.l_ma = bt.ind.SMA(period=self.p.long_period)
        # 短期均线上穿长期均线,取值为1;反之,短期均线下穿长期均线,取值为-1
        self.lines.signal = bt.ind.CrossOver(self.s_ma, self.l_ma)

我们看下CrossOver这个指标,它是upcross -  downcross。也就是”上穿”值为1,下窗值为-1。

02 三均线多头策略

三条均线,短,中,长三期,短期>中期>长期,即呈现“多头排列”时买入,而短线下穿中线时平仓。

import backtrader as bt


# 自定义信号指标
class SignalTripleSMA(bt.Indicator):
    lines = ('signal',)  # 声明 signal 线,交易信号放在 signal line 上
    params = dict(
        short_period=5,
        median_period=20,
        long_period=60)

    def __init__(self):
        self.s_ma = bt.ind.SMA(period=self.p.short_period)
        self.m_ma = bt.ind.SMA(period=self.p.median_period)
        self.l_ma = bt.ind.SMA(period=self.p.long_period)

        # 短期均线在中期均线上方,且中期均线也在长期均线上方,三线多头排列,取值为1;反之,取值为0
        self.signal1 = bt.And(self.m_ma > self.l_ma, self.s_ma > self.m_ma)
        # 求上面 self.signal1 的环比增量,可以判断得到第一次同时满足上述条件的时间,第一次满足条件为1,其余条件为0
        self.buy_signal = bt.If((self.signal1 - self.signal1(-1)) > 0, 1, 0)
        # 短期均线下穿长期均线时,取值为1;反之取值为0
        self.sell_signal = bt.ind.CrossDown(self.s_ma, self.m_ma)
        # 将买卖信号合并成一个信号
        self.lines.signal = bt.Sum(self.buy_signal, self.sell_signal * (-1))

03 海龟策略

import backtrader as bt
from engine.strategy.strategy_base import StrategyBase


class TurtleTradingStrategy(StrategyBase):
    params = dict(
        N1=20,  # 唐奇安通道上轨的t
        N2=10,  # 唐奇安通道下轨的t
    )

    def __init__(self):
        self.order = None
        self.buy_count = 0  # 记录买入次数
        self.last_price = 0  # 记录买入价格
        # 准备第一个标的沪深300主力合约的close、high、low 行情数据
        self.close = self.datas[0].close
        self.high = self.datas[0].high
        self.low = self.datas[0].low
        # 计算唐奇安通道上轨:过去20日的最高价
        self.DonchianH = bt.ind.Highest(self.high(-1), period=self.p.N1, subplot=True)
        # 计算唐奇安通道下轨:过去10日的最低价
        self.DonchianL = bt.ind.Lowest(self.low(-1), period=self.p.N2, subplot=True)
        # 生成唐奇安通道上轨突破:close>DonchianH,取值为1.0;反之为 -1.0
        self.CrossoverH = bt.ind.CrossOver(self.close(0), self.DonchianH, subplot=False)
        # 生成唐奇安通道下轨突破:
        self.CrossoverL = bt.ind.CrossOver(self.close(0), self.DonchianL, subplot=False)
        # 计算 ATR
        self.TR = bt.ind.Max((self.high(0) - self.low(0)),  # 当日最高价-当日最低价
                             abs(self.high(0) - self.close(-1)),  # abs(当日最高价−前一日收盘价)
                             abs(self.low(0) - self.close(-1)))  # abs(当日最低价-前一日收盘价)
        self.ATR = bt.ind.SimpleMovingAverage(self.TR, period=self.p.N1, subplot=False)
        # 计算 ATR,直接调用 talib ,使用前需要安装 python3 -m pip install TA-Lib
        # self.ATR = bt.talib.ATR(self.high, self.low, self.close, timeperiod=self.p.N1, subplot=True)

    def next(self):
        # 如果还有订单在执行中,就不做新的仓位调整
        if self.order:
            return

            # 如果当前持有多单
        if self.position.size > 0:
            # 多单加仓:价格上涨了买入价的0.5的ATR且加仓次数少于等于3次
            if self.datas[0].close > self.last_price + 0.5 * self.ATR[0] and self.buy_count <= 4:
                print('if self.datas[0].close >self.last_price + 0.5*self.ATR[0] and self.buy_count <= 4:')
                print('self.buy_count', self.buy_count)
                # 计算建仓单位:self.ATR*期货合约乘数300*保证金比例0.1
                self.buy_unit = max((self.broker.getvalue() * 0.005) / (self.ATR * 300 * 0.1), 1)
                self.buy_unit = int(self.buy_unit)  # 交易单位为手
                # self.sizer.p.stake = self.buy_unit
                self.order = self.buy(size=self.buy_unit)
                self.last_price = self.position.price  # 获取买入价格
                self.buy_count = self.buy_count + 1
            # 多单止损:当价格回落2倍ATR时止损平仓
            elif self.datas[0].close < (self.last_price - 2 * self.ATR[0]):
                print('elif self.datas[0].close < (self.last_price - 2*self.ATR[0]):')
                self.order = self.sell(size=abs(self.position.size))
                self.buy_count = 0
            # 多单止盈:当价格突破10日最低点时止盈离场 平仓
            elif self.CrossoverL < 0:
                print('self.CrossoverL < 0')
                self.order = self.sell(size=abs(self.position.size))
                self.buy_count = 0

                # 如果当前持有空单
        elif self.position.size < 0:
            # 空单加仓:价格小于买入价的0.5的ATR且加仓次数少于等于3次
            if self.datas[0].close < self.last_price - 0.5 * self.ATR[0] and self.buy_count <= 4:
                print('self.datas[0].close<self.last_price-0.5*self.ATR[0] and self.buy_count <= 4')
                # 计算建仓单位:self.ATR*期货合约乘数300*保证金比例0.1
                self.buy_unit = max((self.broker.getvalue() * 0.005) / (self.ATR * 300 * 0.1), 1)
                self.buy_unit = int(self.buy_unit)  # 交易单位为手
                # self.sizer.p.stake = self.buy_unit
                self.order = self.sell(size=self.buy_unit)
                self.last_price = self.position.price  # 获取买入价格
                self.buy_count = self.buy_count + 1
                # 空单止损:当价格上涨至2倍ATR时止损平仓
            elif self.datas[0].close < (self.last_price + 2 * self.ATR[0]):
                print('self.datas[0].close < (self.last_price+2*self.ATR[0])')
                self.order = self.buy(size=abs(self.position.size))
                self.buy_count = 0
            # 多单止盈:当价格突破20日最高点时止盈平仓
            elif self.CrossoverH > 0:
                print('self.CrossoverH>0')
                self.order = self.buy(size=abs(self.position.size))
                self.buy_count = 0

        else:  # 如果没有持仓,等待入场时机
            # 入场: 价格突破上轨线且空仓时,做多
            if self.CrossoverH > 0 and self.buy_count == 0:
                print('if self.CrossoverH > 0 and self.buy_count == 0:')
                # 计算建仓单位:self.ATR*期货合约乘数300*保证金比例0.1
                self.buy_unit = max((self.broker.getvalue() * 0.005) / (self.ATR * 300 * 0.1), 1)
                self.buy_unit = int(self.buy_unit)  # 交易单位为手
                self.order = self.buy(size=self.buy_unit)
                self.last_price = self.position.price  # 记录买入价格
                self.buy_count = 1  # 记录本次交易价格
            # 入场: 价格跌破下轨线且空仓时,做空
            elif self.CrossoverL < 0 and self.buy_count == 0:
                print('self.CrossoverL < 0 and self.buy_count == 0')
                # 计算建仓单位:self.ATR*期货合约乘数300*保证金比例0.1
                self.buy_unit = max((self.broker.getvalue() * 0.005) / (self.ATR * 300 * 0.1), 1)
                self.buy_unit = int(self.buy_unit)  # 交易单位为手
                self.order = self.sell(size=self.buy_unit)
                self.last_price = self.position.price  # 记录买入价格
                self.buy_count = 1  # 记录本次交易价格

  • 指标计算:

    • 用 20 日的最高、最低、收盘价计算平均真实波幅 ATR;

    • 计算出近 20 日的最高与 20 日最低价,构建唐奇安通道。

  • 交易信号:

    • 入场:价格突破 20 日价格高点时,入场;

    • 加仓:价格继续上涨至 0.5 倍 ATR ,再次加仓,加仓次数不超过 3 次;

    • 止损:价格回落 2 倍 ATR 时止损离场;

    • 止盈:价格突破 10 日最低点时止盈离场;

    • 做空与做多的逻辑相反。

本篇主要演示bt框架里,指标如何计算,尤其是一些复合的向量计算,以及策略如何写,包括止损、止盈,仓位管理等。

传统量化策略其实就是一个小交易系统,包括了选股、择时与仓位管理。而机器学习模型应该更接近是一个择时过程,应当是系统中的一个环节。而qlib的TopK回测,分高就all in,显然是不够“科学”,只是一种学术上的论证。

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI量化投资实验室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值