pmorissette / bt

bt - flexible backtesting for Python
http://pmorissette.github.io/bt
MIT License
2.23k stars 427 forks source link

class bt.algos.RunOnDate(*dates) #68

Closed AnthonyFJGarner closed 7 years ago

AnthonyFJGarner commented 8 years ago

s = bt.Strategy('s1', [bt.algos.RunOnDate(my_dates), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance()])

test = bt.Backtest(s, data) res = bt.run(test)

Here are the dates I am trying to pass: ['2016-01-04', '2016-02-01', '2016-02-29', '2016-03-28', '2016-04-25', '2016-05-23', '2016-06-20', '2016-07-18', '2016-08-15', '2016-09-12', '2016-10-10', '2016-11-07', '2016-12-05']

And here is the error:

`--------------------------------------------------------------------------- ValueError Traceback (most recent call last)

in () 1 test = bt.Backtest(s, data) ----> 2 res = bt.run(test) C:\Anaconda\envs\BT\lib\site-packages\bt\backtest.py in run(_backtests) 24 # run each backtest 25 for bkt in backtests: ---> 26 bkt.run() 27 28 return Result(_backtests) C:\Anaconda\envs\BT\lib\site-packages\bt\backtest.py in run(self) 163 self.strategy.update(dt) 164 if not self.strategy.bankrupt: --> 165 self.strategy.run() 166 # need update after to save weights, values and such 167 self.strategy.update(dt) C:\Anaconda\envs\BT\lib\site-packages\bt\core.cp35-win_amd64.pyd in bt.core.Strategy.run (bt/core.c:14718)() C:\Anaconda\envs\BT\lib\site-packages\bt\core.cp35-win_amd64.pyd in bt.core.AlgoStack.**call** (bt/core.c:14120)() C:\Anaconda\envs\BT\lib\site-packages\bt\algos.py in **call**(self, target) 333 334 def **call**(self, target): --> 335 return target.now in self.dates 336 337 ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() `
AnthonyFJGarner commented 8 years ago

No doubt I will work it out but if anyone has played with bt.algos.RunOnDate(*dates) they might be able to save me a bit of time.

AnthonyFJGarner commented 8 years ago

return pd.np.any(self.dates == target.now ) instead of return target.now in self.dates removes the error but .....

ceaza commented 8 years ago

I get the same error with the RunOnDate algo. I passed in a list of TimeStamps.

Problem it seems is that self.dates is a DatetimeIndex within a single element list:

[DatetimeIndex(['2009-01-01', '2009-04-01', '2009-07-01', '2009-10-01',
'2010-01-01', '2010-04-01', '2010-07-01', '2010-10-01',
'2011-01-03', '2011-04-01', '2011-07-01', '2011-10-03',
'2012-01-02', '2012-04-02', '2012-07-02', '2012-10-01',
'2013-01-01', '2013-04-01', '2013-07-01', '2013-10-01',
'2014-01-01', '2014-04-01', '2014-07-01', '2014-10-01',
'2015-01-01', '2015-04-01', '2015-07-01', '2015-10-01',
'2016-01-01', '2016-04-01'],
dtype='datetime64[ns]', freq=None)]

so replacing this:

return target.now in self.dates

with this:

return target.now in self.dates[0]

will correct the problem.

I am using winpython 3.5.1.3 with pandas 0.18.0 and also had same issue on anaconda 3.5 running on Linux

AnthonyFJGarner commented 8 years ago

Charles I am very grateful to you indeed. I am passing a strings list (rather unnecessarily but I wanted to keep consistency so I could pass a smaller list easily).

In case it is of any interest to you, I split my asset allocation systems into 4 parts each trading monthly but on a different day of the month. Each system trades the identical portfolio.

I then combine systems. This means you have the advantages of monthly re-allocation but you are not so exposed to particular dates and crises with the combined portfolio.

Thus each week one quarter of the total portfolio value turns over or at least re-allocates.

Hope this might be of some use to you as a quid pro quo!

algoParams.week_list1 = 1,5,9,13,17,21,25,29,33,37,41,45,49 algoParams.week_list2 = 2,6,10,14,18,22,26,30,34,38,42,46,50 algoParams.week_list3 = 3,7,11,15,19,23,27,31,35,39,43,47,51 algoParams.week_list4 = 4,8,12,16,20,24,28,32,36,40,44,48,52

start='1970-01-01' end = '2017-12-31' my_dates = bt.TAA.date_list(start, end,algoParams.week_list1) my_dates

def date_list(start, end,my_weeks,freq='W-MON' ): df = pd.DataFrame({'date':pd.bdate_range(start=start, end=end, freq=freq)}) df['orig week'] = df['date'].dt.week df['date'] = df['date'].dt.date df = df[df['orig week'].isin(my_weeks)] df = ([str(x) for x in df['date']]) return df

ceaza commented 8 years ago

Glad I could help, and your approach is an interesting one. Has it added value?

AnthonyFJGarner commented 8 years ago

Certainly physchologically. It's comforting to know you get in an out in increments. As to whether over time it proves worthwhile......

pmorissette commented 7 years ago

Hey @AnthonyFJGarner, @ceaza,

Sorry I took so long to respond.

This is a simple fix. The algo expects a (dates), as such, when using an array, you must add the ''. From the original example:

bt.algos.RunOnDate(*my_dates)

Hope this helps, Phil