Skip to content
All library documents

Double Moving Average Crossover Strategy With Position Reversals

Article Strategy library · Author: 用Python的交易员

Summary

This event-driven strategy compares a 10-period simple moving average with a 20-period simple moving average on each completed bar. When the faster average moves above the slower one, it opens a long position; if currently short, it covers and then buys. When the faster average moves below the slower one, it opens a short position or exits a long and reverses short. The framework loads historical bars for initialization and updates the averages as new bars arrive.

The document is source code for a trading framework and supplies no instrument, timeframe, backtest results, transaction costs, or evidence of profitability. Its crossover checks compare current and previous average values but use strict inequalities, so bars where the averages are exactly equal do not count as a crossover. Reversal orders are submitted at the bar close, and the excerpt does not explain fill handling or risk controls. The method illustrates a basic trend-following rule, but its performance and execution behavior require separate evaluation.

Key ideas

  • The strategy compares 10-period and 20-period simple moving averages on each bar.
  • A move of the faster average above the slower average triggers a long position.
  • A move below the slower average triggers a short position.
  • Signals reverse an existing position by submitting exit and entry orders.
  • The source gives no backtest results, transaction cost assumptions, or protective exits.

Tags

Full text
# DoubleMaStrategy


# DoubleMaStrategy









## Source (MIT)

```python
from howtrader.app.cta_strategy import (
    CtaTemplate,
    StopOrder
)

from howtrader.trader.object import TickData, BarData, TradeData, OrderData
from howtrader.trader.utility import BarGenerator, ArrayManager
from decimal import Decimal


class DoubleMaStrategy(CtaTemplate):
    author = "用Python的交易员"

    fast_window = 10
    slow_window = 20

    fast_ma0 = 0.0
    fast_ma1 = 0.0

    slow_ma0 = 0.0
    slow_ma1 = 0.0

    parameters = ["fast_window", "slow_window"]
    variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"]

    def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
        """"""
        super().__init__(cta_engine, strategy_name, vt_symbol, setting)

        self.bg = BarGenerator(self.on_bar)
        self.am = ArrayManager()

    def on_init(self):
        """
        Callback when strategy is inited.
        """
        self.write_log("策略初始化")
        self.load_bar(10)

    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.
        """

        am = self.am
        am.update_bar(bar)
        if not am.inited:
            return

        fast_ma = am.sma(self.fast_window, array=True)
        self.fast_ma0 = fast_ma[-1]
        self.fast_ma1 = fast_ma[-2]

        slow_ma = am.sma(self.slow_window, array=True)
        self.slow_ma0 = slow_ma[-1]
        self.slow_ma1 = slow_ma[-2]

        cross_over = self.fast_ma0 > self.slow_ma0 and self.fast_ma1 < self.slow_ma1
        cross_below = self.fast_ma0 < self.slow_ma0 and self.fast_ma1 > self.slow_ma1

        if cross_over:
            if self.pos == 0:
                self.buy(Decimal(bar.close_price), Decimal(1))
            elif self.pos < 0:
                self.cover(Decimal(bar.close_price), Decimal(1))
                self.buy(Decimal(bar.close_price), Decimal(1))

        elif cross_below:
            if self.pos == 0:
                self.short(Decimal(bar.close_price), Decimal(1))
            elif self.pos > 0:
                self.sell(Decimal(bar.close_price), Decimal(1))
                self.short(Decimal(bar.close_price), Decimal(1))

        self.put_event()

    def on_order(self, order: OrderData):
        """
        Callback of new order data update.
        """
        pass

    def on_trade(self, trade: TradeData):
        """
        Callback of new trade data update.
        """
        self.put_event()

    def on_stop_order(self, stop_order: StopOrder):
        """
        Callback of stop order update.
        """
        pass
```

Shown in full with attribution under the source's licence. Licence: MIT

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.