Indicator for Log Returns of data feeds
-
Dear Community, dear @backtrader
I try to create an indicator that lets me calculate the log-returns for a given period for each "data". The following code failed, I assume that I made a mistake with ApplyN?
class LogReturns(bt.Indicator): lines = ('logreturns',) def __init__(self): self.lines.logreturns = bt.ind.ApplyN(bt.ind.PercentChange(self.data, period=1) + 1, func=lambda x: math.log(x[0]))
Can you kindly show me how I can correctly calculate a log-return indicator?
Thanks!
J -
This analyzer exists if you are ok using an analyzer.
https://www.backtrader.com/docu/analyzers-reference/#logreturnsrolling
Which means you can look at the code for creating the log return analyzer to help making your own:
https://github.com/backtrader2/backtrader/blob/master/backtrader/analyzers/logreturnsrolling.py -
Thanks for pointing this out. I also came across the analyzer, but as far as I understand the backtrader platform this approach doesn't work as analyzers are "a different type of animal" when compared to indicators. Or have you been able to use an analyzer as an input inside next?
-
I took the liberty of writing up the code.
import datetime import backtrader as bt import math class LogReturns(bt.Indicator): params = ( ("log_period", 1), ) lines = ('logreturns',) def next(self): # This makes sure enough bars have passed before trying to calcualte the log return. if len(self) < self.p.log_period: return self.l.logreturns[0] = (math.log(self.datas[0].close[0] / self.datas[0].close[-1]) / self.p.log_period) * 100 class Strat(bt.Strategy): params = dict(log_period=1) def log(self, txt, dt=None): """ Logging function fot this strategy""" dt = dt or self.data.datetime[0] if isinstance(dt, float): dt = bt.num2date(dt) print("%s, %s" % (dt.date(), txt)) # Added log return to the signal printout. def print_signal(self): self.log( "o {:7.2f}\th {:7.2f}\tl {:7.2f}\tc {:7.2f}\tlog_return {:3.3f}".format( self.datas[0].open[0], self.datas[0].high[0], self.datas[0].low[0], self.datas[0].close[0], self.lr[0], ) ) def __init__(self): self.lr = LogReturns(log_period=self.p.log_period) def next(self): self.print_signal() if __name__ == "__main__": cerebro = bt.Cerebro() for s in ['AAPL']: data = bt.feeds.YahooFinanceData( dataname=s, timeframe=bt.TimeFrame.Days, fromdate=datetime.datetime(2019, 11, 4), todate=datetime.datetime(2020, 11, 4), reverse=False, ) cerebro.adddata(data) cerebro.addstrategy(Strat) # Execute cerebro.run()
Which prints out something like:
2019-11-04, o 63.07 h 63.20 l 62.60 c 63.12 log_return -55.771 2019-11-05, o 63.01 h 63.29 l 62.83 c 63.03 log_return -0.143 2019-11-06, o 62.94 h 63.11 l 62.59 c 63.05 log_return 0.032 2019-11-07, o 63.61 h 64.01 l 63.46 c 63.78 log_return 1.151 2019-11-08, o 63.60 h 64.03 l 63.15 c 63.95 log_return 0.266 2019-11-11, o 63.50 h 64.53 l 63.50 c 64.46 log_return 0.794
-
@run-out Amazing, thanks a lot! Your help in this regard is highly appreciated!