The moving average crossover strategy is a quantitative trading strategy based on simple moving averages (SMA). It generates buy and sell signals when different period SMA crossovers occur.
Specifically, this strategy calculates the 9-period and 45-period SMA. When the price crosses above both SMA lines, a buy signal is generated. When the price crosses below both lines, a sell signal is triggered.
The core logic of this strategy is based on the “golden cross” and “dead cross” principles of moving averages. Moving averages can effectively filter out market noise and indicate major trend changes. When the shorter-term MA crosses above the longer-term MA, it signals an upward trend reversal. The opposite crossover signals a downtrend.
In particular, this strategy uses the 9-period and 45-period simple moving averages. The 9-period line represents short-term trends while the 45-period line captures longer-term moves. When the price crosses above both SMA lines, it indicates the price is in upward channels both short-term and long-term, hence triggering a long entry. The opposite crossover suggests weakening upside momentum and prompts exit signals.
From the code perspective, the strategy first computes the 9-period and 45-period SMA values. It then uses the ta.crossover and ta.crossunder functions to detect golden crosses and dead crosses between the two MA lines. When buy and sell signals are triggered, plotshape functions draw triangles and inverted triangles on the price chart.
In addition, stop-loss logic is implemented to manage trade exits. Specifically, the high and low prices of the previous bar are extracted as the stop-loss price after opening new trades. This allows the strategy to lock in gains and prevent huge losses.
The dual moving average setup captures mid-to-long term trend shifts while filtering out short-term noises, improving signal quality.
The stop-loss mechanism effectively controls risks and locks in profits.
Simple and easy-to-implement logic, suitable for beginners.
High capital utilization for compounding gains.
Dual MA strategies tend to generate whipsaws and invalid signals during choppy markets.
Conservative stop loss placement unable to track trends effectively.
Suboptimal parameter selection may lead to overtrading or insufficient trade frequency.
Unable to adapt to huge trend reversals.
Solutions:
Optimize MA parameters to reduce false signals
Implement trend-following dynamic stops
Add filters using other indicators
Manual override around major reversals
Further improvements for the strategy:
Use adaptive or exponential MAs to better capture trends.
Add volatility filter to avoid false signals during ranging markets.
Perform parameter optimization for best parameter combinations.
Incorporate trend-following mechanisms into stop-loss logic.
Add support-resistance analysis to avoid signals around key levels.
Leverage machine learning to further filter signal quality.
The moving average crossover system is a simple yet effective trend following approach. By filtering out noise and tracking mid-term trends, it generates quality signals. With proper stop losses, it enables risk-managed trend trading. The simple logic also makes it ideal for beginners to put into practice. Further optimizations can integrate this strategy as an effective component of overall quant systems.
/*backtest start: 2022-12-15 00:00:00 end: 2023-12-21 00:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //@version=5 strategy("SMA Crossover Strategy", overlay=true) // Input parameters fast_length = input(9, title="Fast SMA Length") slow_length = input(45, title="Slow SMA Length") // Calculate moving averages fast_sma = ta.sma(close, fast_length) slow_sma = ta.sma(close, slow_length) // Buy condition buy_condition = ta.crossover(close, fast_sma) and ta.crossover(close, slow_sma) // Sell condition sell_condition = ta.crossunder(close, fast_sma) and ta.crossunder(close, slow_sma) // Calculate stop loss levels prev_low = request.security(syminfo.tickerid, "1D", low[1], lookahead=barmerge.lookahead_on) prev_high = request.security(syminfo.tickerid, "1D", high[1], lookahead=barmerge.lookahead_on) // Plot signals on the chart plotshape(buy_condition, style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small) plotshape(sell_condition, style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small) // Strategy exit conditions long_stop_loss = sell_condition ? prev_low : na short_stop_loss = buy_condition ? prev_high : na strategy.exit("Long Exit", from_entry="Long", when=sell_condition, stop=long_stop_loss) strategy.exit("Short Exit", from_entry="Short", when=buy_condition, stop=short_stop_loss) strategy.entry("Long", strategy.long, when=buy_condition) strategy.entry("Short", strategy.short, when=sell_condition)