In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import ffn
import bt
%matplotlib inline
In [2]:
names = ['foo','bar','rf']
dates = pd.date_range(start='2017-01-01',end='2017-12-31', freq=pd.tseries.offsets.BDay())
n = len(dates)
rdf = pd.DataFrame(
np.zeros((n, len(names))),
index = dates,
columns = names
)
np.random.seed(1)
rdf['foo'] = np.random.normal(loc = 0.1/n,scale=0.2/np.sqrt(n),size=n)
rdf['bar'] = np.random.normal(loc = 0.04/n,scale=0.05/np.sqrt(n),size=n)
rdf['rf'] = 0.
pdf = 100*np.cumprod(1+rdf)
pdf.plot()
Out[2]:
In [3]:
# algo to fire on the beginning of every month and to run on the first date
runMonthlyAlgo = bt.algos.RunMonthly(
run_on_first_date=True
)
# algo to set the weights
# it will only run when runMonthlyAlgo returns true
# which only happens on the first of every month
weights = pd.Series([0.6,0.4,0.],index = rdf.columns)
weighSpecifiedAlgo = bt.algos.WeighSpecified(**weights)
# algo to rebalance the current weights to weights set by weighSpecified
# will only run when weighSpecifiedAlgo returns true
# which happens every time it runs
rebalAlgo = bt.algos.Rebalance()
# a strategy that rebalances monthly to specified weights
strat = bt.Strategy('static',
[
runMonthlyAlgo,
weighSpecifiedAlgo,
rebalAlgo
]
)
In [4]:
# set integer_positions=False when positions are not required to be integers(round numbers)
backtest = bt.Backtest(
strat,
pdf,
integer_positions=False
)
res = bt.run(backtest)
In [5]:
res.stats
Out[5]:
In [6]:
res.prices.head()
Out[6]:
In [7]:
res.plot_security_weights()
Strategy value over time
In [26]:
performanceStats = res['static']
#performance stats is an ffn object
res.backtest_list[0].strategy.values.plot()
Out[26]:
Strategy Outlays
Outlays are the total dollar amount spent(gained) by a purchase(sale) of securities.
In [28]:
res.backtest_list[0].strategy.outlays.plot()
Out[28]:
You can get the change in number of shares purchased a
In [34]:
security_names = res.backtest_list[0].strategy.outlays.columns
res.backtest_list[0].strategy.outlays/pdf.loc[:,security_names]
res.backtest_list[0].positions.diff(1)
res.backtest_list[0].positions
Out[34]: