Replaying Market Data at a Higher Timeframe in Backtrader
Summary
This example shows how to replay lower-timeframe price data as daily, weekly, or monthly bars in Backtrader. A simple strategy calculates a configurable simple moving average and prints lifecycle messages as the replayed data advances. The script lets users select a timeframe and compression amount, and it can use either the current replay interface or an older DataReplayer object.
The key practical detail is that replaying differs from ordinary resampling: the higher-timeframe bar develops as smaller-timeframe observations arrive, so strategy callbacks may occur repeatedly while that bar is forming. The example disables preloading and plots the resulting bars, making it useful as a framework demonstration. It does not generate orders, define entry or exit rules, assess performance, or explain how to avoid acting on incomplete bars. Its moving average is illustrative rather than a validated trading signal, and the sample data path is only a default input.
Key ideas
- The script replays smaller-timeframe observations into daily, weekly, or monthly bars.
- A configurable simple moving average is calculated on the replayed data.
- The strategy prints callback counts to show how it advances during replay.
- The example contains no order logic or evidence that the indicator is profitable.
Tags
Full text
# data-replay.py
```py
#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
###############################################################################
#
# Copyright (C) 2015-2023 Daniel Rodriguez
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import argparse
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
class SMAStrategy(bt.Strategy):
params = (
('period', 10),
('onlydaily', False),
)
def __init__(self):
self.sma = btind.SMA(self.data, period=self.p.period)
def start(self):
self.counter = 0
def prenext(self):
self.counter += 1
print('prenext len %d - counter %d' % (len(self), self.counter))
def next(self):
self.counter += 1
print('---next len %d - counter %d' % (len(self), self.counter))
def runstrat():
args = parse_args()
# Create a cerebro entity
cerebro = bt.Cerebro(stdstats=False)
cerebro.addstrategy(
SMAStrategy,
# args for the strategy
period=args.period,
)
# Load the Data
datapath = args.dataname or '../../datas//2006-day-001.txt'
data = btfeeds.BacktraderCSVData(
dataname=datapath)
tframes = dict(
daily=bt.TimeFrame.Days,
weekly=bt.TimeFrame.Weeks,
monthly=bt.TimeFrame.Months)
# Handy dictionary for the argument timeframe conversion
# Resample the data
if args.oldrp:
data = bt.DataReplayer(
dataname=data,
timeframe=tframes[args.timeframe],
compression=args.compression)
else:
data.replay(
timeframe=tframes[args.timeframe],
compression=args.compression)
# First add the original data - smaller timeframe
cerebro.adddata(data)
# Run over everything
cerebro.run(preload=False)
# Plot the result
cerebro.plot(style='bar')
def parse_args():
parser = argparse.ArgumentParser(
description='Pandas test script')
parser.add_argument('--dataname', default='', required=False,
help='File Data to Load')
parser.add_argument('--oldrp', required=False, action='store_true',
help='Use deprecated DataReplayer')
parser.add_argument('--timeframe', default='weekly', required=False,
choices=['daily', 'weekly', 'monthly'],
help='Timeframe to resample to')
parser.add_argument('--compression', default=1, required=False, type=int,
help='Compress n bars into 1')
parser.add_argument('--period', default=10, required=False, type=int,
help='Period to apply to indicator')
return parser.parse_args()
if __name__ == '__main__':
runstrat()
```Shown in full with attribution under the source's licence. Licence: GPL-3.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.