math.log with linebuffer._LineDelay object
-
Hello!
This is my indicator:
class weightedlogmeanInd(bt.Indicator): lines = ('mean',) # output line (array) params = ( ('speed', 4), ('tau',0.01), ) def __init__(self): weights = findweights(self.p.speed,self.p.tau) #this is an array change_sum = 0 period = len(weights) for day in range(0,-period,-1): change = self.data.close(0-day) - ( self.data.close(-1-day)) # change = math.log(self.data.close(0-day)) - math.log( self.data.close(-1-day)) weighted_change = change * weights[-day] change_sum = change_sum + weighted_change self.lines.mean = change_sum / period
I would like to change this line:
change = self.data.close(0-day) - ( self.data.close(-1-day))
into the line below, which is now commented out:
change = math.log(self.data.close(0-day)) - math.log( self.data.close(-1-day))
When I do it, I get the following error message:
TypeError: must be real number, not _LineDelay
Basically, I would like to use the logarithm to get the price change from yesterday to today. What would be the best way to do it?
Thanks a lot!
-
@marsario There's a built in Log function in backtrader. It will provide you with the log of a single number in next, not for a whole line in init.
All of this:
for day in range(0,-period,-1):
change = self.data.close(0-day) - ( self.data.close(-1-day))
change = math.log(self.data.close(0-day)) - math.log( self.data.close(-1-day))
weighted_change = change * weights[-day]
change_sum = change_sum + weighted_changeNeeds to move into next, and you don't need range.
I haven't tested the following, but generally it should look something like:def next(self): self.close_log[0] = bt.Log(self.datas[0].close[0]) self.change[0] = self.close_log[0] - self.close_log[-1] self.weighted_change[0] = self.change[0] * self.weights[0] self.change_sum[0] = self.change_sum[-1] + self.weighted_change[0]
With respect to indexing, you don't have to go back the extra
[-1]
since backtrader sees the bar at[0]
as closed. -
@run-out said in math.log with linebuffer._LineDelay object:
def next(self):
self.close_log[0] = bt.Log(self.datas[0].close[0])
self.change[0] = self.close_log[0] - self.close_log[-1]
self.weighted_change[0] = self.change[0] * self.weights[0]
self.change_sum[0] = self.change_sum[-1] + self.weighted_change[0]Hi, thanks for your suggestion!
I'm getting AttributeError that backtrader doesn't have a Log method. That's suppose to be an indicator, isn't it?
If so I should be able to recreate it.
-
I'm trying to implement the indicator with a different logic. And I don't understand what happens.
class weightedlogmeanInd(bt.Indicator): lines = ('mean',) # output line (array) params = ( ('speed', 4), ('tau',0.01), ) weights = [] def __init__(self): self.weights = findweights(self.p.speed,self.p.tau) today=self.data.get(ago=0,size=len(self.weights)) yesterday=self.data.get(ago=-1,size=len(self.weights)) print("len(today):",len(today)) print("len(yesterday):",len(yesterday)) print("What is happening in today?", (today) ) print("What is happening in yesterday?",(yesterday) ) growth = np.log(today)-np.log(yesterday) print("data close:",self.data.close(0)) print("What is happening in growth?", growth )
The printout and error message:
(base) Simones-Air:Learning Backtrader simoneromeo$ python 26\ onestock\ strategy.py Launching the strategy Starting logmean strategy len(today): 0 len(yesterday): 27 What is happening in today? array('d') What is happening in yesterday? array('d', [133.74, 137.18, 136.76, 136.91, 136.01, 135.39, 135.13, 135.37, 133.19, 130.84, 129.71, 129.87, 126.0, 125.86, 125.35, 120.99, 121.26, 127.79, 125.12, 122.06, 120.13, 121.42, 116.36, 121.09, 119.98, 121.96, 121.03]) Traceback (most recent call last): File "26 onestock strategy.py", line 150, in <module> cerebro.run() ... File "26 onestock strategy.py", line 46, in __init__ growth = np.log(today)-np.log(yesterday) ValueError: operands could not be broadcast together with shapes (0,) (27,)
I don't undestand: why does
self.data.get(ago=0,size=len(self.weights)
return an empty array andself.data.get(ago=-1,size=len(self.weights)
return an array with the right length? -
After some unsuccessful attempts, i came back to the strategy you recommended. I defined log like this:
from backtrader.functions import MultiLogic class Log(MultiLogic): flogic = math.log
Also, added one more line to the code you recommended so that I passed the mean to the line object:
class weightedlogmeanInd(bt.Indicator): lines = ('mean',) # output line (array) params = ( ('speed', 4), ('tau',0.01), ) def next(self): self.close_log[0] = Log(self.datas[0].close[0]) self.change[0] = self.close_log[0] - self.close_log[-1] self.weighted_change[0] = self.change[0] * self.weights[0] self.change_sum[0] = self.change_sum[-1] + self.weighted_change[0] self.lines.mean[0]= bt.Sum(self.change_sum)/len(self.weights)
This doesn't send an error, but doesn't behave as I wished (ideally, it should create a Mean line for each day of the datafeed. I realize that I don't understand how to use Indicators' Next method (I have created indicators but always inside Init). I wish I could find more resources to learn – Platform concepts and Indicators Development don't help me enough apparently. Do you have recommendations of how I could learn to build this indicator?
-
@marsario said in math.log with linebuffer._LineDelay object:
I'm getting AttributeError that backtrader doesn't have a Log method. That's suppose to be an indicator, isn't it?
i think @run-out used the log function implemented in
backtrader2
. if you use baselinebt
package, than it is not there. -
@ab_trader Is there a way still to find the logarithm inside an indicator? The solution that I thought I found is a mess and it won't work.
-
@ab_trader woops!
-
@marsario said in math.log with linebuffer._LineDelay object:
self.lines.mean[0]= bt.Sum(self.change_sum)/len(self.weights)
I think you are close. This line:
self.lines.mean[0]= bt.Sum(self.change_sum)/len(self.weights)
The self.change_sum is already a sum from the previous line. It's cummulative. So I think this line should read:
self.lines.mean[0]= self.change_sum[0]/len(self.weights)
Also, in your first line.
self.close_log[0] = math.log(self.datas[0].close[0])
Import math and try that.
self.datas[0].close[0]
is a scalar andmath.log
should work.