csvanalyzerwriterbacktrader

backtrader how to use analyzer to access data?


I am very new to this. backtrader have a addwriter can write down some data,
cerebro.addwriter(bt.WriterFile, csv=True, out='outputfiles3\{}cerebro.csv'.format(ticker)) but buy and sell price always not match to the execute price.

so alternatively:

i did cerebro.addanalyzer(WritingAnalyzer) before cerebro.run()

so I am trying to build the csv file with 'datetime','open','close','cash','value','position size' but I don't know how to access those data. I can only point at current day close price with self.data[0]

I don't know how to do it right. I hope someone might able to give me some directions.

import backtrader as bt
from backtrader import Analyzer
import csv

class WritingAnalyzer(Analyzer):

    def __init__(self):

    def create_analysis(self):
        self.counter = 0
        print(self.counter)
        with open('demo1.csv',mode='w') as csv_file:
            fieldnames=['datetime','open','close','cash','value','position size']
            writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
            writer.writeheader()

    def next(self):
        self.counter += 1
        print('close price:',self.data[0], "counter:",self.counter,)
        #  the following line suppose to write into csv file but i dont know how to get most of the data.
        bt.writer.writerow({'datetime': '??', 'open': '??', 'close': self.data[0],'cash':'??','value':'??','position size':'??'})

    def stop(self):
        print("SSSSSSSSSSSSSTTTTTTOOOOOOOOOOOOPPPPPPPPPP")

        self.rets._close()

Solution

  • You need to handle your analyzer a bit differently. You can literally grab data at every bar and then have it available to you at the end.

    Create a new analyzer, in my case I made:

    class BarAnalysis(bt.analyzers.Analyzer):
    

    In your analyzer in start you will create a new list.

    def start(self):
        self.rets = list()
    

    Then in next you will add a list of data for each bar. I use a try statement just in case there are any data problems, but it's probably not necessary. Strategy is included as as subclass and you can use its methods by calling self.strategy.getvalue() as an example.

    def next(self):
        try:
            self.rets.append(
                [
                    self.datas[0].datetime.datetime(),
                    self.datas[0].open[0],
                    self.datas[0].high[0],
                    self.datas[0].low[0],
                    self.datas[0].close[0],
                    self.datas[0].volume[0],
                    self.strategy.getposition().size,
                    self.strategy.broker.getvalue(),
                    self.strategy.broker.getcash(),
                ]
            )
        except:
            pass
    

    Finally create a get_analysis method that you can use to get your results at the end.

    def get_analysis(self):
        return self.rets
    

    Add your analyzer to before running cerebro. You can name it whatever you want, we'll need the name to call the results.

    cerebro.addanalyzer(BarAnalysis, _name="bar_data")
    

    Make sure you provide a variable for the results of the cerebro.run() method so you can collect the results of the backtest.

    strat = cerebro.run()
    

    Finally, get the data out of strat and do as you wish with it. In this case I'm creating a dataframe and printing.

    bar_data_res = strat[0].analyzers.bar_data.get_analysis()
    df = pd.DataFrame(bar_data_res)
    print(df)
    

    And the printout looks like:

    /home/runout/projects/rb_master/venv/bin/python /home/runout/projects/scratch/20210424_analyzer.py
                                 0       1       2  ...  6         7         8
    0   2020-01-02 23:59:59.999989  212.70  213.36  ...  0  10000.00  10000.00
    1   2020-01-03 23:59:59.999989  210.81  213.28  ...  0  10000.00  10000.00
    2   2020-01-06 23:59:59.999989  210.18  213.59  ...  0  10000.00  10000.00
    3   2020-01-07 23:59:59.999989  213.11  214.13  ...  0  10000.00  10000.00
    4   2020-01-08 23:59:59.999989  212.43  216.47  ...  0  10000.00  10000.00
    ..                         ...     ...     ...  ... ..       ...       ...
    247 2020-12-23 23:59:59.999989  268.38  269.31  ...  1  10015.38   9747.25
    248 2020-12-24 23:59:59.999989  267.76  269.67  ...  1  10016.48   9747.25
    249 2020-12-28 23:59:59.999989  270.48  270.55  ...  1  10014.82   9747.25
    250 2020-12-29 23:59:59.999989  268.30  268.78  ...  1  10011.78   9747.25
    251 2020-12-30 23:59:59.999989  264.45  265.64  ...  1  10010.86   9747.25
    
    [252 rows x 9 columns]
    
    Process finished with exit code 0
    

    The whole code looks like this:

    import datetime
    import backtrader as bt
    import pandas as pd
    
    class BarAnalysis(bt.analyzers.Analyzer):
    
        def start(self):
            self.rets = list()
    
        def next(self):
            try:
                self.rets.append(
                    [
                        self.datas[0].datetime.datetime(),
                        self.datas[0].open[0],
                        self.datas[0].high[0],
                        self.datas[0].low[0],
                        self.datas[0].close[0],
                        self.datas[0].volume[0],
                        self.strategy.getposition().size,
                        self.strategy.broker.getvalue(),
                        self.strategy.broker.getcash(),
                    ]
                )
            except:
                pass
    
        def get_analysis(self):
            return self.rets
    
    
    class Strategy(bt.Strategy):
    
        params = (
            ("lowerband", 30),
            ("upperband", 70),
        )
    
        def __init__(self):
            self.rsi = bt.ind.RSI(period=10)
    
        def next(self):
            if not self.position:
                if self.rsi <= self.p.lowerband:
                    self.buy()
            elif self.rsi >= self.p.upperband:
                self.close()
    
    if __name__ == "__main__":
    
        cerebro = bt.Cerebro()
    
        ticker = "HD"
        data = bt.feeds.YahooFinanceData(
            dataname=ticker,
            timeframe=bt.TimeFrame.Days,
            fromdate=datetime.datetime(2020, 1, 1),
            todate=datetime.datetime(2020, 12, 31),
            reverse=False,
        )
    
        cerebro.adddata(data, name=ticker)
    
        cerebro.addanalyzer(BarAnalysis, _name="bar_data")
        cerebro.addstrategy(Strategy)
    
        # Execute
        strat = cerebro.run()
    
        bar_data_res = strat[0].analyzers.bar_data.get_analysis()
        df = pd.DataFrame(bar_data_res)
        print(df)