In [1]:
import numpy as np
import pandas as pd
import bt
import matplotlib.pyplot as plt
%matplotlib inline
In [2]:
np.random.seed(0)
returns = np.random.normal(0.08/12,0.2/np.sqrt(12),12*10)
pdf = pd.DataFrame(
np.cumprod(1+returns),
index = pd.date_range(start="2008-01-01",periods=12*10,freq="m"),
columns=['foo']
)
pdf.plot()
Out[2]:
In [6]:
runMonthlyAlgo = bt.algos.RunMonthly()
rebalAlgo = bt.algos.Rebalance()
class Signal(bt.Algo):
"""
Mostly copied from StatTotalReturn
Sets temp['Signal'] with total returns over a given period.
Sets the 'Signal' based on the total return of each
over a given lookback period.
Args:
* lookback (DateOffset): lookback period.
* lag (DateOffset): Lag interval. Total return is calculated in
the inteval [now - lookback - lag, now - lag]
Sets:
* stat
Requires:
* selected
"""
def __init__(self, lookback=pd.DateOffset(months=3),
lag=pd.DateOffset(days=0)):
super(Signal, self).__init__()
self.lookback = lookback
self.lag = lag
def __call__(self, target):
selected = 'foo'
t0 = target.now - self.lag
if target.universe[selected].index[0] > t0:
return False
prc = target.universe[selected].loc[t0 - self.lookback:t0]
trend = prc.iloc[-1]/prc.iloc[0] - 1
signal = trend > 0.
if signal:
target.temp['Signal'] = 1.
else:
target.temp['Signal'] = 0.
return True
signalAlgo = Signal(pd.DateOffset(months=12),pd.DateOffset(months=1))
class WeighFromSignal(bt.Algo):
"""
Sets temp['weights'] from the signal.
Sets:
* weights
Requires:
* selected
"""
def __init__(self):
super(WeighFromSignal, self).__init__()
def __call__(self, target):
selected = 'foo'
if target.temp['Signal'] is None:
raise(Exception('No Signal!'))
target.temp['weights'] = {selected : target.temp['Signal']}
return True
weighFromSignalAlgo = WeighFromSignal()
In [7]:
s = bt.Strategy(
'example1',
[
runMonthlyAlgo,
signalAlgo,
weighFromSignalAlgo,
rebalAlgo
]
)
t = bt.Backtest(s, pdf, integer_positions=False, progress_bar=True)
res = bt.run(t)
In [8]:
res.plot_security_weights()
In [9]:
t.positions
Out[9]:
In [11]:
res.prices.tail()
Out[11]:
In [12]:
res.stats
Out[12]: