Double Moving Average Crossover Strategy With Position Reversals
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.