Skip to content
All library documents

Dual Moving Average Crossover for Long-Only Trend Following

Article Strategy library · Author: QuantRocket

Summary

This example implements a long-only moving average crossover strategy in Backtrader. It calculates short and long simple moving averages, with default windows of 100 and 300 periods, and generates a long signal when the short average crosses above the long average. The example also shows how to load daily stock data into a backtest and plot the result.

The document provides implementation details but no performance results, benchmark, or risk analysis. It does not specify an exit rule beyond the signal setup, nor does it discuss position sizing, transaction costs, or robustness across assets and time periods. The example therefore illustrates a basic trend-following signal and workflow, not evidence that the strategy is profitable.

Key ideas

  • The strategy enters long when the short simple moving average crosses above the long simple moving average.
  • The example uses 100-period and 300-period moving averages by default.
  • It demonstrates loading daily equity data and running the strategy in Backtrader.
  • The document reports no backtest results or analysis of costs and risk.

Tags

Full text
# DualMovingAverageStrategy


# DualMovingAverageStrategy









## Source (Apache-2.0)

```python
# Copyright QuantRocket LLC - All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import backtrader as bt
import backtrader.feeds as btfeeds
from quantrocket.history import download_history_file

class DualMovingAverageStrategy(bt.SignalStrategy):

    params = (
        ('smavg_window', 100),
        ('lmavg_window', 300),
    )

    def __init__(self):

        # Compute long and short moving averages
        smavg = bt.ind.SMA(period=self.p.smavg_window)
        lmavg = bt.ind.SMA(period=self.p.lmavg_window)

        # Go long when short moving average is above long moving average
        self.signal_add(bt.SIGNAL_LONG, bt.ind.CrossOver(smavg, lmavg))

def run():

    cerebro = bt.Cerebro()

    # Create data feed using QuantRocket data and add to backtrader
    # (Put files in /tmp to have QuantRocket automatically clean them out after
    # a few hours)
    download_history_file(
        'usstock-free-1d',
        sids=['FIBBG000B9XRY4'],
        filepath_or_buffer='/tmp/backtrader-demo-1d.csv',
        fields=['Sid','Date','Open','Close','High','Low','Volume'])

    data = btfeeds.GenericCSVData(
        dataname='/tmp/backtrader-demo-1d.csv',
        dtformat=('%Y-%m-%d'),
        datetime=1,
        open=2,
        close=3,
        high=4,
        low=5,
        volume=6
    )
    cerebro.adddata(data)

    cerebro.addstrategy(DualMovingAverageStrategy)
    cerebro.run()

    # Save the plot to PDF so the satellite service can return it
    cerebro.plot(savefig=True, figfilename='/tmp/backtrader-plot.pdf')

```

Shown in full with attribution under the source's licence. Licence: Apache-2.0

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