For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

# Run Calculations On Previous 100 day data

• I want to calculate a series of variables that I can manipulate based on rolling 100 day data.

``````lass SRT(bt.Indicator):
params = dict(period_100d = 100)

rolling_srt = ()

def log(self, txt, dt=None):
''' Logging function for this strategy'''
dt = dt or self.datas.datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))

def __init__(self):
#Everything to calculate this beast!
self.win = ()
self.lose = ()
self.dataclose = self.datas.close

# calculate returns each day, and log them as a win if positive, and a loss if negative.
for self.line in self.data.close.get(ago=-1, size = 100):
if self.dataclose > self.dataclose[-1]:
#store the values of the positive days.
self.win = float(self.dataclose - self.dataclose[-1])
else:
#store the values of the negative days
self.lose = float(self.dataclose - self.dataclose[-1])
# How many days were positive?
self.avg_win = bt.ind.Average(self.win)
# How many days were negative?
self.avg_loss = bt.ind.Average(self.lose)
# Average closing price over the 100days
self.avg_risk = bt.ind.Average(self.dataclose, period = self.p.period_100d)
# percentage of days resulting in win or loss.
self.prob_w = len(self.win)/(self.p.period_100d)
self.prob_l = (1 - self.prob_w)
``````

Errors:

``````Traceback (most recent call last):
line 23, in <module>
cerebro.run()
line 1127, in run
runstrat = self.runstrategies(iterstrat)
line 1217, in runstrategies
strat = stratcls(*sargs, **skwargs)
line 88, in __call__
_obj, args, kwargs = cls.doinit(_obj, *args, **kwargs)
line 78, in doinit
_obj.__init__(*args, **kwargs)
line 49, in __init__
self.my_srt = SRT(self.data.get(ago=0, size=100))
line 53, in __call__
return super(MetaIndicator, cls).__call__(*args, **kwargs)
line 88, in __call__
_obj, args, kwargs = cls.doinit(_obj, *args, **kwargs)
line 78, in doinit
_obj.__init__(*args, **kwargs)
line 19, in __init__
self.dataclose = self.datas.close
line 461, in __getattr__
return getattr(self.lines, name)
AttributeError: 'Lines_LineSeries_LineSeriesStub' object has no attribute 'close'
``````

Any help would seriously be appreciated. Veteran in finance, new to programming.

• self.my_srt = SRT(self.data.get(ago=0, size=100))

Just guessing your strategy code from the exception, it seems the problem is with the indicator initialization. You may probably want to initialize the SRT indicator with the `self.data` instead.

Probably worth to provide a full strategy code - so less guessing would be needed.

• Slicing and `[]` can be used in the `next()` only. Check out Docs - Platform Concepts

• In order to work with indicators you need to think of them as whole lines. Below I will create a new line by comparing data is greater at the current point less data shifted to the previous day.

This will create a new line of boolean 1 for greater and 0 for not.

To find how main wins over 100 days? Just add them up, all the wins are 1.

Then subtact from 100 to get all the losses.

Here's the code.

``````class BuyAndHold_More(bt.Strategy):

params = (
('period', 100),
)

def __init__(self):
self.win = self.data > self.data(-1)
self.win_100 = bt.ind.SumN(self.win, period=self.p.period)
self.lose_100 = self.p.period - self.win_100
``````

I will set the period to 5 days so you can see the results here. Note that the starting period adjust to allow the indicator to get going.

``````2005-01-10T00:00:00, o 13.32	h 13.45	l 13.17	c 13.19	v 47571800	win 0	win_100 3	lose_100 2
2005-01-11T00:00:00, o 13.09	h 13.39	l 13.06	c 13.20	v 63973000	win 1	win_100 4	lose_100 1
2005-01-12T00:00:00, o 13.26	h 13.49	l 13.24	c 13.48	v 53420800	win 1	win_100 4	lose_100 1
2005-01-13T00:00:00, o 13.38	h 13.67	l 13.34	c 13.48	v 56987700	win 0	win_100 3	lose_100 2
2005-01-14T00:00:00, o 13.56	h 13.76	l 13.49	c 13.63	v 42509100	win 1	win_100 3	lose_100 2
2005-01-18T00:00:00, o 13.59	h 13.90	l 13.52	c 13.78	v 60758900	win 1	win_100 4	lose_100 1
2005-01-19T00:00:00, o 13.66	h 13.80	l 13.45	c 13.47	v 51115100	win 0	win_100 3	lose_100 2
2005-01-20T00:00:00, o 13.44	h 13.68	l 13.28	c 13.28	v 45253200	win 0	win_100 2	lose_100 3
2005-01-21T00:00:00, o 13.35	h 13.49	l 13.28	c 13.31	v 40716100	win 1	win_100 3	lose_100 2
2005-01-24T00:00:00, o 13.36	h 13.50	l 13.21	c 13.24	v 37540700	win 0	win_100 2	lose_100 3
2005-01-25T00:00:00, o 13.49	h 13.74	l 13.46	c 13.59	v 48682500	win 1	win_100 2	lose_100 3
2005-01-26T00:00:00, o 13.96	h 14.01	l 13.61	c 13.62	v 78543500	win 1	win_100 3	lose_100 2
``````

• @run-out this was a big help, much appreciated.
From here I was able to extrapolate the average win amounts.

``````class Win_Buy(bt.Strategy):
params = (
('period', 100),
)

def log(self, txt, dt=None):
''' Logging function fot this strategy'''
dt = dt or self.datas.datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))

def __init__(self):
self.dataclose = self.datas.close
# Win & Loss Data
self.win_record = []
self.win = self.data > self.data(-1)
self.win_100 = bt.ind.SumN(self.win, period=self.p.period)
self.lose_100 = self.p.period - self.win_100
self.prob_win = self.win_100/100
self.prob_lose = 1 - self.prob_win
if self.dataclose > self.dataclose[-1]:
self.win_record = self.dataclose - self.dataclose[-1]
else:
self.lose_record = self.dataclose - self.dataclose[-1]

#risk
self.risk = bt.ind.Average(self.dataclose*.1, period=self.p.period)
``````

• @dmeharchand @run-out
Second that I was not able to do that, everytime I try to store values it doesn't seem to work or the code will just freeze.

``````class Win_Buy(bt.Strategy):
params = (
('period', 100),
('test_period', 10),
)

def log(self, txt, dt=None):
''' Logging function fot this strategy'''
dt = dt or self.datas.datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))

def __init__(self):
# Win & Loss Data
self.dataclose = self.datas.close
self.win = self.data > self.data(-1)
self.win_100 = bt.ind.SumN(self.win, period=self.p.period)
self.lose_100 = self.p.period - self.win_100
self.prob_win = self.win_100/100
self.prob_lose = 1 - self.prob_win
self.diff = self.dataclose - self.dataclose[-1]
#THIS IS WHERE THE PROBLEM IS
if self.dataclose > self.dataclose[-1]:
self.win_record = (self.dataclose-self.dataclose[-1])
else:
self.lose_record = (self.dataclose - self.dataclose[-1])

self.avg_win = bt.ind.Average(self.win_record, period=self.win_100)

def next(self):
self.log('Win, %.2f' % self.win_100)
self.log('Close, %.2f' % self.dataclose)
self.log('Yesterday Close, %.2f' % self.dataclose[-1])
``````

When I run it the code says

``````AttributeError: 'Lines_LineSeries_LineIterator_DataAccessor_Strateg' object has no attribute 'win_record'
``````

Basically I am try to determine
if the today > yesterday,
store value
average(stored values/ len(stored Values)

Any help of reference you can provide would be amazing, again thank you so much for the input you have provided already

• if self.dataclose > self.dataclose[-1]:
self.win_record = (self.dataclose-self.dataclose[-1])
else:
self.lose_record = (self.dataclose - self.dataclose[-1])

It seems you are trying to get the `data.close` values in `__init__` method - where the data is not yet available. See the previous response from @ab_trader

• @dmeharchand
The way you have it, you've made a line out of the close value, which is good. self.datas represents the first datas value, and close is the close line of that datas.

``````self.dataclose = self.datas.close
``````

But you can't reference the values in init but using  and [-1]. These get used in next to say the value at the current date, and the value at the previous date. In next, there is a current date, in init, there isn't.

Try using this in init for example:

``````self.diff = self.dataclose(0) - self.dataclose(-1)
``````

Or if you like, you can drop the (0) as it's assumed.

``````self.diff = self.dataclose - self.dataclose(-1)
``````

Then when you wish to recall the indicator in next, you would use:

``````self.diff
``````

Or if you want the previous value of self.diff in next:

``````self.diff[-1]
``````

That's perfectly valid in next.

If we look at your problem code, it might look something like:

``````# The following line will result in a line object where wins are 1 and losses are 0
self.win_record = self.dataclose(0) > self.dataclose(-1)

# And I think this next line should work, change period.
self.avg_win = bt.ind.Average(self.win_record, period=self.p.period)
``````

Let us know how you get on.

• @run-out yes I've quickly discovered the () vs. [] delema.

So i've been able to store the values appropriately with .append() in my `self.win_record = pd.DataFrame({'Win': []})` and use them with the Average index ```self.avg_win = bt.ind.Average(self.win_record['Win'], period=self.p.period).

When I print the index I get

``````<backtrader.indicators.basicops.Average object at 0x000001DC76EDC808>
``````

The main problem now is that whenever try to manipulate this data I get an error

`````` line 163, in __getitem__
return self.array[self.idx + ago]
IndexError: array index out of range
``````

or the script wont run at all.

Here is what i've come up with:

``````class Win_Buy(bt.Strategy):
params = (
('period', 100),
('test_period', 10),
)

def log(self, txt, dt=None):
''' Logging function fot this strategy'''
dt = dt or self.datas.datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))

def __init__(self):
# Win & Loss Data
self.dataclose = self.datas.close
self.win = self.data > self.data(-1)
self.win_100 = bt.ind.SumN(self.win, period=self.p.period)
self.lose_100 = self.p.period - self.win_100
self.prob_win = self.win_100/100
self.prob_loss = 1 - self.prob_win
self.win_record = pd.DataFrame({'Win': []})
self.loss_record = pd.DataFrame({'Loss': []})

self.avg_risk = bt.ind.Average(self.dataclose, period=self.p.period)

#self.avg_loss = bt.ind.Average(self.loss_record, period=self.p.period)

def next(self):

if self.dataclose > self.dataclose[-1]:
self.diff = self.dataclose - self.dataclose[-1]
print(self.diff)
self.df = pd.DataFrame({'Win':[self.diff]})
self.win_record = self.win_record.append(self.df, ignore_index=True)
print(self.win_record['Win'])
else:
self.df = pd.DataFrame({'Win':})
self.win_record = self.win_record.append(self.df, ignore_index=True)

if self.dataclose > self.dataclose[-1]:
self.diff = self.dataclose - self.dataclose[-1]
self.df = pd.DataFrame({'Loss':[self.diff]})
self.loss_record = self.loss_record.append(self.df, ignore_index=True)
else:
self.df = pd.DataFrame({'Loss':})
self.loss_record = self.loss_record.append(self.df, ignore_index=True)

self.avg_win = bt.ind.Average(self.win_record, period=self.p.period)

print(self.avg_win)

self.dsharpe = self.avg_win/self.avg_risk
print(self.dsharpe)
``````

• The code you've shared looks highly unorthadox for backtrader. Could we take a step back and you tell us what you are trying to accomplish in general, without any solutions? We can then tell you if maybe there's a better way to handle things.

good polite definition. :)

I would recommend for TS to go thru the docs and quickstart before compiling that complex scripts.

• @run-out
Each day of a backtest I want to use the following 100 Days to calcuate/create specific variables:

• Prob_Win = How many days over the last 100 the market was up
• Prob_Loss = (1 - Prob_W)
• Avg_Win = The amount of each of the win days the market was up/ No. of days a win was recorded
• Avg_Loss =The amount of each of the lose days the market was down/ No. of days a win was recorded
• Avg_ risk = Average closing price across the 100 days * (a risk percentage)

Finally, I want to create a calculation dsharpe:
dsharpe = self.avg_win/self.avg_risk that recalculates everyday on past 100 days.

Then use this value to determine whether I should buy or sell a security
i.e If dsharpe > .4, purchase security

Hope thats clear?
Appologies for my unorthadox code, I am new to programming.
I greatly appreciate any suggestions/ help @run-out or @ab_trader can provide.

Please let me know if I can assist in anyway.
Thanks,
D

• @dmeharchand CORRECTION each day of the backtest I want to use the PREVIOUS 100 days to calculate specific variable.

• I've written out the bulk of the code for you. I'm going to leave you to calculate the dsharpe for practice.

``````
class Strategy(bt.Strategy):

params = (("period", 5),)

def __init__(self):

self.diff = self.data - self.data(-1)
self.win_record = self.data(0) > self.data(-1)

self.prob_win = bt.ind.SumN(self.win_record, period=self.p.period)
self.prob_loss = self.p.period - self.prob_win

self.wins = bt.ind.SumN(
bt.If(self.diff >= 0, self.diff, 0), period=self.p.period
)
self.losses = bt.ind.SumN(
bt.If(self.diff < 0, -self.diff, 0), period=self.p.period
)

self.ave_win = bt.DivByZero(self.wins, self.prob_win, 0)
self.ave_loss = bt.DivByZero(self.losses, self.prob_loss, 0)

self.ave_close = bt.ind.Average(self.data.close, period=self.p.period)

def log(self, txt, dt=None):
""" Logging function fot this strategy"""
dt = dt or self.data.datetime
if isinstance(dt, float):
dt = bt.num2date(dt)
print("%s, %s" % (dt.isoformat(), txt))

def next(self):

self.log(
"c {:5.2f}\tdiff {:5.2f}, \twinr {:5.2f}, \tpwin {:5.2f}, \tploss {:5.2f}, \t"
"wins {:5.2f}, \tplosses {:5.2f}, \tave_win {:5.2f}, \tave_loss {:5.2f},\tpav_close {:5.2f}".format(
self.datas.close,
self.diff,
self.win_record,
self.prob_win,
self.prob_loss,
self.wins,
self.losses,
self.ave_win,
self.ave_loss,
self.ave_close,
)
)

``````

• @run-out alright... I think I got it!

``````class Win_Buy(bt.Strategy):
params = (("period", 5),)

def log(self, txt, dt=None):
''' Logging function fot this strategy'''
dt = dt or self.datas.datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))

def __init__(self):
self.risk = 0.01
self.diff = self.data - self.data(-1)
self.win_record = self.data(0) > self.data(-1)

self.prob_win = bt.ind.SumN(self.win_record, period=self.p.period)
self.prob_loss = self.p.period - self.prob_win

self.wins = bt.ind.SumN(
bt.If(self.diff >= 0, self.diff, 0), period=self.p.period)

self.losses = bt.ind.SumN(
bt.If(self.diff <0, -self.diff,0), period=self.p.period)

self.avg_win = bt.DivByZero(self.wins, self.prob_win, 0)
self.avg_loss = bt.DivByZero(self.losses, self.prob_loss, 0)
self.avg_risk = bt.ind.Average(self.data.close*self.risk, period=self.p.period)

def next(self):

self.dsharpe = self.avg_win / (self.avg_risk)
if self.dsharpe > 1:
# previous close less than the previous close
else:
pass
``````

With Prints...

``````2018-01-09, c 24.37	diff  0.02, 	winr  1.00, 	pwin  3.00, 	ploss  2.00, 	wins  0.25, 	plosses  0.14, 	avg_win  0.08, 	avg_loss  0.07,	avg_risk  0.24,	DSHAREP  0.34
2018-01-10, c 24.25	diff -0.12, 	winr  0.00, 	pwin  2.00, 	ploss  3.00, 	wins  0.12, 	plosses  0.26, 	avg_win  0.06, 	avg_loss  0.09,	avg_risk  0.24,	DSHAREP  0.25
2018-01-11, c 24.32	diff  0.07, 	winr  1.00, 	pwin  2.00, 	ploss  3.00, 	wins  0.09, 	plosses  0.26, 	avg_win  0.05, 	avg_loss  0.09,	avg_risk  0.24,	DSHAREP  0.18
2018-01-12, c 24.34	diff  0.02, 	winr  1.00, 	pwin  3.00, 	ploss  2.00, 	wins  0.11, 	plosses  0.18, 	avg_win  0.04, 	avg_loss  0.09,	avg_risk  0.24,	DSHAREP  0.15
2018-01-15, c 24.40	diff  0.06, 	winr  1.00, 	pwin  4.00, 	ploss  1.00, 	wins  0.17, 	plosses  0.12, 	avg_win  0.04, 	avg_loss  0.12,	avg_risk  0.24,	DSHAREP  0.17
2018-01-16, c 24.31	diff -0.09, 	winr  0.00, 	pwin  3.00, 	ploss  2.00, 	wins  0.15, 	plosses  0.21, 	avg_win  0.05, 	avg_loss  0.11,	avg_risk  0.24,	DSHAREP  0.21
2018-01-17, c 24.35	diff  0.04, 	winr  1.00, 	pwin  4.00, 	ploss  1.00, 	wins  0.19, 	plosses  0.09, 	avg_win  0.05, 	avg_loss  0.09,	avg_risk  0.24,	DSHAREP  0.20
``````

Does this seem right?
Also if I just wanted to use DSharpe as a bt.Indicator would i just change the class from Strategy to Indicator? and the purchase metrics?

});