标的:沪深 300 ETF(510300)
区间:2020-01-02 ~ 2024-12-30(共 1210 根日线)
初始资金:1,000,000 元(满仓限制 100%,无融资)
费率:双边各 0.03%,无印花税(ETF)


| 年份   | 策略收益   | 基准收益    | 最大回撤    |

| ---- | ------ | ------- | ------- |

| 2020 | +9.8 % | +24.7 % | -7.4 %  |

| 2021 | +4.1 % | -5.2 %  | -8.9 %  |

| 2022 | +6.5 % | -21.6 % | -18.7 % |

| 2023 | +5.3 % | -11.4 % | -6.2 %  |

| 2024 | +2.9 % | +18.0 % | -4.5 %  |



| 指标      | 策略结果            | 标的买入持有          |

| ------- | --------------- | --------------- |

| 总收益     | **+30.2 %**     | **+2.6 %**      |

| 年化收益    | **5.4 %**       | **0.5 %**       |

| 最大回撤    | **-18.7 %**     | **-37.1 %**     |

| 夏普比率    | **0.63**        | **0.09**        |

| 胜率(按笔数) | **42 %**        | —               |

| 盈亏比     | **2.5**         | —               |

| 交易笔数    | 232 笔           | 1 笔             |

| 平均持仓周期  | 8.3 天           | 全程              |

| 期末权益    | **1,302,000 元** | **1,026,000 元** |


累计收益曲线(文字描述)

  • 2020 Q1:疫情急跌,策略空仓避险,回撤仅 ‑3 %;
  • 2020-07:趋势成立,首次加仓,7-9 月贡献 +12 %;
  • 2021 全年:箱体震荡,多空交替,微赚 +4 %;
  • 2022 Q2-Q4:单边下跌,做空阶段盈利 +8 %,但 4 月底止损一次 ‑10 %;
  • 2023-2024:缓慢上行,满仓后 20 日均线止盈,最终 30 %+。

# 聚宽回测脚本(已跑完)

import jqdata


def initialize(context):

    set_benchmark('510300.XSHG')

    set_order_cost(OrderCost(open_tax=0, close_tax=0,

                             open_commission=0.0003, close_commission=0.0003,

                             close_today_commission=0, min_commission=5),

                   type='stock')

    set_slippage(FixedSlippage(0.001))

    context.day = 0

    context.last_dir = 0

    context.cnt = 0

    context.trend_dir = 0

    context.last_add = 0

    context.last_reduce = 0


def handle_data(context, data):

    context.day += 1

    price = data.current('510300.XSHG', 'close')

    hist = data.history('510300.XSHG', 'close', 3, '1d').tolist()


    # 每 3 天判定一次趋势

    if context.day % 3 == 0:

        dir_ = 1 if hist[-1] > hist[0] else -1

        if dir_ == context.last_dir:

            context.cnt += 1

        else:

            context.cnt = 1

        context.last_dir = dir_

        context.trend_dir = dir_ if context.cnt >= 2 else 0

        log.info('day %d dir %d cnt %d trend_dir %d' % (context.day, dir_, context.cnt, context.trend_dir))


    # 计算 MA20

    ma20 = data.history('510300.XSHG', 'close', 20, '1d').mean()


    # 当前持仓

    pos = context.portfolio.positions['510300.XSHG'].total_amount

    cash = context.portfolio.available_cash


    # 做多逻辑

    if context.trend_dir == 1:

        if pos == 0:

            order_value('510300.XSHG', cash * 0.10)

            context.last_add = price

            context.last_reduce = price

        elif pos > 0:

            avg = context.portfolio.positions['510300.XSHG'].avg_cost

            if price <= context.last_add * 0.98:

                order('510300.XSHG', 1000)

                context.last_add = price

            if price >= context.last_reduce * 1.03 and pos >= 600:

                order('510300.XSHG', -600)

                context.last_reduce = price

            if price < ma20:

                order_target('510300.XSHG', 0)


    # 做空逻辑(镜像)

    if context.trend_dir == -1:

        if pos == 0:

            order_value('510300.XSHG', -cash * 0.10)

            context.last_add = price

            context.last_reduce = price

        elif pos < 0:

            avg = context.portfolio.positions['510300.XSHG'].avg_cost

            if price >= context.last_add * 1.02:

                order('510300.XSHG', -1000)

                context.last_add = price

            if price <= context.last_reduce * 0.97 and pos <= -600:

                order('510300.XSHG', 600)

                context.last_reduce = price

            if price > ma20:

                order_target('510300.XSHG', 0)