happydasch/btoandav20

Replay Feature is fetching higher timeframe instead of lower timeframe

edesmars opened this issue · 3 comments

Hi,

Thanks for the help on the previous issue. Works perfectly ;)
So going through my backtesting, I wanted to use the replay function to backtest a strategy based on 15Min candles using 1Min candles for the ticks.

Though when using the oandav20feed, the data retrieved is already the replay dataframe / compression. In my example, the data fetch was 15Min instead of 1Min. That means that the tick (calling next on strategy) are not using M1 data but M15 so the same as if i don't use replay.

I did a bit of debug and was able to find out that the replay filter will override self._timeframe and self._compression from the data feed. Though in my case a simple override of the replay function in the oandav20feed seems to have fixed the issue with the following code:

    def replay(self, **kwargs):
        # save original timeframe and compression to fetch data
        # they will be overriden when calling replay
        orig_timeframe = self._timeframe
        orig_compression = self._compression
        #setting up replay configuration
        super(DataBase, self).replay(**kwargs)
        #putting back original timeframe and compression to fetch correct data
        #the replay configuration will still use the correct dataframe and compression for strategy
        self._timeframe = orig_timeframe
        self._compression = orig_compression

You can reproduce the issue by using a modified replay sample files as below (fetch day data to use on a strategy for weeks):

#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
###############################################################################
#
# Copyright (C) 2015, 2016 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
import btoandav20
import datetime

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():

    # Create a cerebro entity
    cerebro = bt.Cerebro(stdstats=False)
    StoreCls = btoandav20.stores.OandaV20Store

    cerebro.addstrategy(SMAStrategy)

    # Load the Data
    storekwargs = dict(
        token="xxxxxxxxxxx",
        account="yyyyyyyyyyy",
        practice=True
    )

    store = StoreCls(**storekwargs)
    DataFactory = store.getdata
    dtformat = '%Y-%m-%dT%H:%M:%S'

    fromdate = datetime.datetime.strptime("2010-01-01T00:00:00", dtformat)
    todate = datetime.datetime.strptime("2010-01-31T00:00:00", dtformat)
    datakwargs = dict(
        timeframe=bt.TimeFrame.Days,
        compression=1,
        qcheck=0.5,
        historical=True,
        fromdate=fromdate,
        todate=todate,
        bidask=True,

    )
    data = DataFactory(dataname="EUR_USD", **datakwargs)
    # Prepare the data for replay at higher timeframe
    data.replay(
        timeframe=bt.TimeFrame.Weeks,
        compression=1)

    # First add the original data - smaller timeframe
    cerebro.adddata(data)

    # Run over everything
    cerebro.run(preload=False)

if __name__ == '__main__':
    runstrat()

Warning: With the fix proposed, on my system, the values don't correspond between oanda data and replaying the data. I believe it must be some timezone issues between the data coming back from Oanda and the timing of replayed data. But it could simply be another issue on replaying.

I have added your method to the repository. I did not have time to check the code, but will do so in a few days.

Thank you, let me know if you need any help when you are looking into it. ;)

seems to be working fine