MULTI-STRATEGY


In [1]:
import pandas as pd
import itable
import ffn
import talib

%matplotlib inline

def side_by_side(*objs, **kwds):
    from pandas.formats.printing import adjoin
    space = kwds.get('space', 4)
    reprs = [repr(obj).split('\n') for obj in objs]
    print (adjoin(space, *reprs))
    
import os
os.chdir('C:\\users\\Dave\\pycharmprojects\\simplebacktester')
os.getcwd()


Out[1]:
'C:\\users\\Dave\\pycharmprojects\\simplebacktester'

In [31]:
import pandas as pd
import ffn

%matplotlib inline

from backtest_helpers.compute_weights_RS_DM import compute_weights_RS_DM
from backtest_helpers.compute_weights_PMA import compute_weights_PMA
from backtest_helpers.monthly_return_table import monthly_return_table
from backtest_helpers.endpoints import endpoints
from backtest_helpers.backtest import backtest

strategies = {
    'RS0001': { 'symbols': ['VCVSX','VWEHX','VFIIX','FGOVX','VWAHX'], 'prices': 'yahoo',  
               'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 2, 'frequency': 'M',
              'cash_proxy': 'CASHX', 'risk_free': 0},
    'RS0002': {'symbols': ['MMHYX','FAGIX','VFIIX'],  'prices': 'yahoo', 
               'rs_lookback': 3, 'risk_lookback': 2, 'n_top': 1, 'frequency': 'M',
              'cash_proxy': 'CASHX', 'risk_free': 0},
    'RS0003': {'symbols': ['MMHYX','FAGIX','VFIIX'], 'prices': 'yahoo', 
               'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 1, 'frequency': 'Q',
              'cash_proxy': 'CASHX', 'risk_free': 0},    
    'DM0001': {'symbols': ['VCVSX','VWINX','VWEHX','VGHCX','VUSTX','VFIIX','VWAHX','FGOVX','FFXSX'],
                'prices': 'yahoo', 
               'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 3, 'frequency': 'M',
              'cash_proxy': 'CASHX', 'risk_free': 'FFXSX'},
    'DM0002': {'symbols': ['VCVSX','VUSTX','VWEHX','VFIIX','VGHCX','FRESX'], 'prices': 'yahoo', 
               'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 5, 'frequency': 'M',
              'cash_proxy': 'VFIIX', 'risk_free': 'FFXSX'},
    'PMA001': {'symbols': ['VCVSX', 'VFIIX'],  'prices': 'yahoo', 
               'risk_lookback': 3, 'frequency': 'M', 'allocations': [0.6, 0.4],
              'cash_proxy': 'VUSTX'},
    'PMA002': {'symbols': ['VCVSX', 'VWINX', 'VWEHX'], 'prices': 'yahoo', 
               'risk_lookback': 3, 'frequency': 'M', 'allocations': [0.6, 0.2, 0.2],
              'cash_proxy': 'VUSTX'},
    'PMA003': {'symbols': ['VCVSX', 'FAGIX', 'VGHCX'], 'prices': 'yahoo',  
               'risk_lookback': 2, 'frequency': 'M', 'allocations': [1./3., 1./3., 1./3.],
              'cash_proxy': 'VUSTX'},    
}

strategy_values = pd.DataFrame(columns=strategies.keys())
security_weights = {}
security_holdings = {}
security_prices = {}

for name in strategies :
    if 'PMA' in name :
        s_value, s_holdings, s_weights, s_prices =  compute_weights_PMA (name, strategies[name])
    else :
        s_value, s_holdings, s_weights, s_prices =  compute_weights_RS_DM (name, strategies[name])
    
    strategy_values[name] = s_value
    security_weights[name] = s_weights
    security_holdings[name] = s_holdings
    security_prices[name] = s_prices


Strategy : RS0003
MMHYX
FAGIX
VFIIX
FIRST BUY DATE = 1984-05-31 00:00:00

Strategy : DM0001
FFXSX
FGOVX
VGHCX
VCVSX
VWEHX
VWAHX
VUSTX
VFIIX
VWINX
FIRST BUY DATE = 1986-12-31 00:00:00

PMA001
VUSTX
VCVSX
VFIIX
FIRST BUY DATE = 1986-08-29 00:00:00

Strategy : RS0001
VCVSX
VWEHX
VFIIX
FGOVX
VWAHX
FIRST BUY DATE = 1986-07-31 00:00:00

PMA002
VUSTX
VWINX
VCVSX
VWEHX
FIRST BUY DATE = 1986-08-29 00:00:00

Strategy : DM0002
FRESX
FFXSX
VGHCX
VCVSX
VWEHX
VUSTX
VFIIX
FIRST BUY DATE = 1986-12-31 00:00:00

PMA003
VUSTX
FAGIX
VCVSX
VGHCX
FIRST BUY DATE = 1986-07-31 00:00:00

Strategy : RS0002
MMHYX
FAGIX
VFIIX
FIRST BUY DATE = 1984-05-31 00:00:00


In [32]:
pd.Panel(security_weights)


Out[32]:
<class 'pandas.core.panel.Panel'>
Dimensions: 8 (items) x 8268 (major_axis) x 13 (minor_axis)
Items axis: DM0001 to RS0003
Major_axis axis: 1984-02-23 00:00:00 to 2016-12-06 00:00:00
Minor_axis axis: CASHX to VWINX

In [58]:
# save results so don't have to recalculate

strategy_values.to_pickle('C:\\Notebooks\\backtesting\\strategy_values.pkl')
pd.Panel(security_weights).to_pickle('C:\\Notebooks\\backtesting\\security_weights.pkl')
pd.Panel(security_holdings).to_pickle('C:\\Notebooks\\backtesting\\security_holdings.pkl')
pd.Panel(security_prices).to_pickle('C:\\Notebooks\\backtesting\\security_prices.pkl')

# strategy_values = pd.read_pickle('C:\\Notebooks\\backtesting\\strategy_values.pkl')
# security_weights = pd.read_pickle('C:\\Notebooks\\backtesting\\security_weights.pkl').fillna(0)
# security_holdings = pd.read_pickle('C:\\Notebooks\\backtesting\\security_holdings.pkl').fillna(0)
# security_prices = pd.read_pickle('C:\\Notebooks\\backtesting\\security_prices.pkl').fillna(0)

In [61]:
s_weights = dict()
s_holdings = dict()
s_prices = dict()
for f in ['security_weights', 'security_holdings', 'security_prices']:
    for name in strategies:
        df = pd.read_pickle('C:\\Notebooks\\backtesting\\' + f + '.pkl')[name]
        index = (df.sum() != 0)
        if f == 'security_weights':
            s_weights[name] = df[index[index==True].index]
        if f == 'security_holdings':
            s_holdings[name] = df[index[index==True].index]
        if f == 'security_prices':
            s_prices[name] = df[index[index==True].index]

In [68]:
strategy_values = pd.read_pickle('C:\\Notebooks\\backtesting\\strategy_values.pkl')
security_weights = s_weights.copy()
security_holdings = s_holdings.copy()
security_prices = s_prices.copy()

In [69]:
name = 'RS0001'
strategy_values[name].plot(figsize=(15, 10), grid=True)


Out[69]:
<matplotlib.axes._subplots.AxesSubplot at 0xb3d21d0>

In [70]:
index = strategy_values.dropna().index
rebalance_dates = endpoints(period='M', trading_days=index)

# find the set of all portfolio symbols
n = len(strategies)
l = [list(security_weights[name].columns) for name in strategies]
s = []
for i in range(n) :
    s = s + l[i]
    
aggregated_weights = pd.DataFrame(0, index=rebalance_dates, columns=list(set(s)))
all_prices = pd.DataFrame(0, index=index, columns=list(set(s)))

# for equally weighted strategies
strategy_weights = pd.Series([1. / n for i in range(n)], index=list(strategies.keys()))

prices = security_prices.copy()
for name in strategies :
    aggregated_weights[security_weights[name].columns] += security_weights[name].loc[rebalance_dates] * strategy_weights[name]
    all_prices = prices[name].loc[index].combine_first(all_prices)

In [71]:
all_prices[:15]


Out[71]:
CASHX FAGIX FFXSX FGOVX FRESX MMHYX VCVSX VFIIX VGHCX VUSTX VWAHX VWEHX VWINX
Date
1986-12-31 1.0 0.758814 2.379192 1.876035 2.116003 1.553293 1.209364 1.692999 2.687786 1.349658 1.849020 0.728181 2.085360
1987-01-02 1.0 0.759595 2.379192 1.881510 2.137291 1.553444 1.215611 1.694684 2.725879 1.357559 1.849020 0.728973 2.099459
1987-01-05 1.0 0.761156 2.379192 1.885159 2.167093 1.554963 1.228104 1.696368 2.782255 1.360192 1.850753 0.730556 2.119966
1987-01-06 1.0 0.762718 2.379192 1.885159 2.173480 1.558000 1.234351 1.696368 2.786826 1.362826 1.861151 0.732930 2.123811
1987-01-07 1.0 0.765060 2.379192 1.886984 2.186252 1.561037 1.236850 1.699737 2.818824 1.366776 1.864617 0.734513 2.132783
1987-01-08 1.0 0.768182 2.379192 1.890634 2.196896 1.562556 1.240598 1.703106 2.849297 1.370726 1.869815 0.736888 2.152009
1987-01-09 1.0 0.768963 2.379192 1.890634 2.194768 1.562556 1.243096 1.703106 2.861487 1.369409 1.871548 0.737679 2.146882
1987-01-12 1.0 0.769744 2.379192 1.890634 2.199025 1.564074 1.245595 1.704791 2.881295 1.374676 1.873281 0.739262 2.152009
1987-01-13 1.0 0.769744 2.379192 1.888809 2.201154 1.564074 1.245595 1.704791 2.882819 1.370726 1.875014 0.740054 2.149446
1987-01-14 1.0 0.769744 2.379192 1.886984 2.201154 1.565593 1.251842 1.706475 2.914816 1.368093 1.876747 0.740845 2.152009
1987-01-15 1.0 0.770524 2.379192 1.886984 2.194768 1.567111 1.261837 1.706475 2.940719 1.365459 1.876747 0.741637 2.158418
1987-01-16 1.0 0.771305 2.379192 1.888809 2.192639 1.567111 1.260587 1.709845 2.934624 1.368093 1.880213 0.742428 2.162263
1987-01-19 1.0 0.771305 2.379192 1.888809 2.203283 1.570148 1.263086 1.709845 2.952908 1.365459 1.881946 0.742428 2.167390
1987-01-20 1.0 0.772866 2.379192 1.892459 2.196896 1.571667 1.265585 1.713214 2.943766 1.374676 1.883679 0.743220 2.171235
1987-01-21 1.0 0.773647 2.379192 1.890634 2.194768 1.573185 1.263086 1.709845 2.939195 1.375993 1.888877 0.744803 2.169953

In [72]:
aggregated_weights.round(3)[:15]


Out[72]:
FFXSX FGOVX FRESX MMHYX VGHCX VCVSX VWAHX VWEHX VUSTX FAGIX VFIIX CASHX VWINX
1986-12-31 0.000 0.000 0.000 0.125 0.000 0.000 0.000 0.154 0.367 0.000 0.354 0.000 0.000
1987-01-30 0.000 0.000 0.025 0.125 0.108 0.321 0.062 0.050 0.000 0.042 0.200 0.000 0.067
1987-02-27 0.000 0.000 0.025 0.000 0.108 0.321 0.000 0.154 0.025 0.292 0.050 0.000 0.025
1987-03-31 0.042 0.000 0.025 0.000 0.108 0.279 0.000 0.154 0.025 0.292 0.075 0.000 0.000
1987-04-30 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.375 0.125 0.125 0.375 0.000
1987-05-29 0.042 0.000 0.000 0.000 0.108 0.000 0.000 0.000 0.333 0.000 0.100 0.417 0.000
1987-06-30 0.000 0.000 0.025 0.125 0.108 0.279 0.104 0.050 0.025 0.042 0.050 0.125 0.067
1987-07-31 0.000 0.000 0.000 0.125 0.108 0.321 0.104 0.050 0.042 0.000 0.100 0.125 0.025
1987-08-31 0.000 0.000 0.000 0.250 0.000 0.321 0.000 0.154 0.092 0.042 0.075 0.000 0.067
1987-09-30 0.000 0.000 0.000 0.125 0.000 0.000 0.000 0.000 0.375 0.000 0.125 0.375 0.000
1987-10-30 0.000 0.104 0.000 0.125 0.000 0.000 0.000 0.000 0.392 0.000 0.379 0.000 0.000
1987-11-30 0.000 0.000 0.025 0.000 0.000 0.000 0.104 0.154 0.283 0.042 0.392 0.000 0.000
1987-12-31 0.000 0.000 0.025 0.000 0.108 0.321 0.000 0.154 0.067 0.000 0.300 0.000 0.025
1988-01-29 0.000 0.000 0.025 0.000 0.108 0.217 0.062 0.025 0.067 0.042 0.388 0.000 0.067
1988-02-29 0.000 0.000 0.025 0.000 0.108 0.321 0.000 0.154 0.025 0.042 0.300 0.000 0.025

In [73]:
# equally weighted
from backtest_helpers.backtest import backtest
p_value, p_holdings, p_weights = backtest(all_prices, aggregated_weights, 10000., offset=0, commission=10.)

p_value.plot(figsize=(15, 10), grid=True)


FIRST BUY DATE = 1986-12-31 00:00:00

Out[73]:
<matplotlib.axes._subplots.AxesSubplot at 0xb933630>

In [74]:
ffn.calc_perf_stats(p_value).display()


Stats for None from 1986-12-31 00:00:00 - 2016-12-06 00:00:00
Annual risk-free rate considered: 0.00%
Summary:
Total Return      Sharpe  CAGR    Max Drawdown
--------------  --------  ------  --------------
2800.85%            2.26  11.91%  -6.09%

Annualized Returns:
mtd    3m      6m      ytd    1y     3y     5y     10y     incep.
-----  ------  ------  -----  -----  -----  -----  ------  --------
0.07%  -4.60%  -2.80%  3.98%  4.10%  6.97%  8.09%  11.60%  11.91%

Periodic:
        daily    monthly    yearly
------  -------  ---------  --------
sharpe  2.26     2.10       1.55
mean    11.38%   11.42%     12.13%
vol     5.04%    5.45%      7.82%
skew    -0.03    0.19       1.57
kurt    4.83     0.94       3.73
best    3.12%    6.78%      38.82%
worst   -2.85%   -3.52%     0.02%

Drawdowns:
max     avg       # days
------  ------  --------
-6.09%  -0.68%     15.58

Misc:
---------------  -------
avg. up month    1.62%
avg. down month  -0.99%
up year %        100.00%
12m up %         98.57%
---------------  -------

Now apply Dual Momentum


In [75]:
strategy_prices = strategy_values.dropna().copy()
strategy_prices[:3]


Out[75]:
RS0003 DM0001 PMA001 RS0001 PMA002 DM0002 PMA003 RS0002
Date
1986-12-31 14659.459302 10000.000000 10039.994842 10285.878930 9883.509662 10000.000000 10152.482090 13600.274821
1987-01-02 14660.884389 10026.456642 10079.256799 10296.591246 9931.946656 10019.855086 10211.915488 13613.810838
1987-01-05 14675.220203 10043.521506 10095.003452 10312.887136 9951.668939 10034.072743 10231.721606 13627.338822

In [76]:
# need to add prices for cash_proxy and, if necessary, risk_free

from backtest_helpers.get_yahoo_data import get_yahoo_data

strategy_prices['FFXSX'] = get_yahoo_data(['FFXSX']).loc[index]
strategy_prices[:1]


FFXSX
Out[76]:
RS0003 DM0001 PMA001 RS0001 PMA002 DM0002 PMA003 RS0002 FFXSX
Date
1986-12-31 14659.459302 10000.0 10039.994842 10285.87893 9883.509662 10000.0 10152.48209 13600.274821 2.379192

In [78]:
strategies1 = {
    'MUTLTI-RS': { 'symbols': list(strategies.keys()), 'prices': strategy_prices,  
               'rs_lookback': 1, 'risk_lookback': 1, 'n_top': 8, 'frequency': 'M',
              'cash_proxy': 'FFXSX', 'risk_free': 0}}

for name in strategies1 :
    s_value, s_holdings, s_weights, s_prices =  compute_weights_RS_DM (name, strategies1[name])


Strategy : MUTLTI-RS
FIRST BUY DATE = 1987-01-30 00:00:00


In [79]:
s_value.plot(figsize=(15, 10), grid=True)


Out[79]:
<matplotlib.axes._subplots.AxesSubplot at 0xb472320>

In [80]:
# poorer return but lower drawdown and better SR
ffn.calc_perf_stats(s_value).display()


Stats for None from 1987-01-30 00:00:00 - 2016-12-06 00:00:00
Annual risk-free rate considered: 0.00%
Summary:
Total Return      Sharpe  CAGR    Max Drawdown
--------------  --------  ------  --------------
1882.70%            2.29  10.52%  -4.78%

Annualized Returns:
mtd    3m      6m      ytd    1y     3y     5y     10y    incep.
-----  ------  ------  -----  -----  -----  -----  -----  --------
0.00%  -2.48%  -2.10%  3.63%  3.66%  4.51%  5.47%  9.35%  10.52%

Periodic:
        daily    monthly    yearly
------  -------  ---------  --------
sharpe  2.29     2.10       1.44
mean    10.10%   10.14%     10.90%
vol     4.40%    4.83%      7.55%
skew    -0.07    0.57       1.59
kurt    5.49     1.83       3.51
best    2.10%    6.78%      36.37%
worst   -2.85%   -2.79%     0.28%

Drawdowns:
max     avg       # days
------  ------  --------
-4.78%  -0.64%     17.45

Misc:
---------------  -------
avg. up month    1.36%
avg. down month  -0.85%
up year %        100.00%
12m up %         98.28%
---------------  -------

In [81]:
def highlight_pos_neg (s) :
    is_positive = s > 0    
    return ['background-color : rgb(127,255,0)' if v else 'background-color : rgb(255,99,71)' for v in is_positive]

df = monthly_return_table (s_value)

df.style.\
    apply(highlight_pos_neg)


Out[81]:
Data Data Data Data Data Data Data Data Data Data Data Data Annual Returns
1 2 3 4 5 6 7 8 9 10 11 12
Year
1987 0 2.32 0.68 -2.21 0.29 1 1.17 0.71 -2.53 1.38 0.67 1.54 10.42
1988 5.15 2.81 -0.62 0.07 -0.22 1.25 -0.28 0.09 1.63 1.9 -1.41 0.24 8.18
1989 2.52 -0.07 0.14 2.54 2.8 1.35 2.09 0.74 -0.07 1.49 0.96 0.72 10.5
1990 -2.54 0.49 0.56 -0.8 1.51 1.12 0.86 -2.51 0.69 1.4 3.93 2.36 13.76
1991 3.52 3.05 3.69 2.75 1.54 -1.38 1.51 2.46 1.37 1.78 -1.01 2.07 21.28
1992 1.73 1.57 0.46 1.06 1.73 0.07 1.61 0.14 1.54 -0.23 0.83 1.25 13.12
1993 2.4 1.42 1.25 -0.15 0.66 1.52 0.6 1.5 0.92 2.43 -0.17 0.82 13.72
1994 2.16 -1.12 -1.67 -0.51 0.11 -0.66 1.11 2.16 -0.62 0.19 -1.08 0.29 0.22
1995 2.09 2.6 1.29 0.82 3.01 1.18 2.04 0.37 1.51 0.38 0.94 1.24 17.86
1996 1.18 0.66 0.29 1.01 0.82 -0.52 0.35 0.27 2.26 0.17 1.52 0.16 7.85
1997 0.61 0.68 -1.81 1.02 1.99 2.49 3.44 -0.53 1.6 -1.33 0.31 1.32 10.72
1998 1.19 2.31 2.77 0.47 0.17 0.96 -0.04 -0.65 1.89 0.16 1.02 2.03 14.36
1999 2.47 -2.38 0.54 1.73 -0.54 0.68 -0.84 0.18 0.94 0.2 2.87 2.74 7.14
2000 0.9 4.5 1.71 -0.77 0.47 2.47 -0.26 1.12 -0.27 0.75 1.52 2.32 16.41
2001 1.84 -1.2 -0.86 0.11 0.63 -0.36 1.59 1.27 0.1 2.14 0.43 -0.11 3.88
2002 0.13 0.81 -1.53 1.29 0.47 0.81 1.86 2.34 1.31 -0.64 0.18 0.54 9.03
2003 1.29 1.2 1.31 4.14 3.33 1.74 -0.32 0.22 2.5 1.64 1.29 3.14 25.18
2004 2.58 0.26 0.38 -2.39 -0.23 0.1 -0.33 1.4 0.79 1.29 1.07 1.5 2.8
2005 -1 -0.43 -0.72 0.74 1.32 1.3 1.85 0.65 -0.37 -0.5 0.36 1.14 7.89
2006 2.33 0.55 0.67 -0.06 -0.04 0.06 1.34 1.91 1.08 1.48 1.66 0.32 10.07
2007 0.69 0.93 0.3 1.62 1.35 -1 0.9 1.18 1.5 1.82 -0.32 0.4 10.83
2008 1.7 0.46 0.5 -0.63 -0.09 -1.9 0.35 1.16 -1.92 -0.61 2.04 4.48 3.56
2009 -0.16 -0.68 1.57 6.78 5.17 1.86 6.4 2.58 5.08 -1.32 1.38 3.17 36.01
2010 -0.42 0.55 3.41 1.24 -2.79 0.89 0.9 -0.34 0.39 1.53 -1.09 -0.2 6.29
2011 1.75 2.11 0.38 2.08 0.62 -0.85 0.91 3.06 4.56 -1.36 0.15 0.61 15.19
2012 2.12 1.56 0.71 0.1 -0.45 -0.57 0.78 0.61 1.64 0.03 0.52 0.14 7.07
2013 1.81 0.58 1.65 1.62 -0.11 -1.01 0.13 -1.05 0.53 1.24 0.62 0.54 5.54
2014 0.71 2.8 -0.18 0.13 1.97 1.02 -0.9 0.54 -1.89 0.46 1.1 0.89 10.68
2015 4.41 -1.24 0.55 0.1 0.49 -1.4 0.26 -1.21 0.57 0.16 -0.07 -0.07 -1.64
2016 0.24 1.19 1.11 1.4 1.06 0.37 0.29 0.13 0.44 -1.61 -0.99 0 3.38

In [82]:
frame = df['Annual Returns'].to_frame()
frame['positive'] = df['Annual Returns'] >= 0
frame['Annual Returns'].plot(figsize=(15,10),kind='bar',color=frame.positive.map({True: 'g', False: 'r'}), grid=True)


Out[82]:
<matplotlib.axes._subplots.AxesSubplot at 0xb557710>

Need to determine the holdings of each security


In [83]:
s_weights.loc[rebalance_dates].round(3)[:15]


Out[83]:
RS0003 DM0001 PMA001 RS0001 PMA002 DM0002 PMA003 RS0002 FFXSX
Date
1986-12-31 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
1987-01-30 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.000
1987-02-27 0.000 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125
1987-03-31 0.125 0.125 0.000 0.125 0.000 0.125 0.125 0.125 0.250
1987-04-30 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 1.000
1987-05-29 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 1.000
1987-06-30 0.000 0.125 0.125 0.000 0.125 0.125 0.125 0.125 0.250
1987-07-31 0.000 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125
1987-08-31 0.000 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125
1987-09-30 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 1.000
1987-10-30 0.000 0.000 0.125 0.000 0.125 0.125 0.125 0.000 0.500
1987-11-30 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.000
1987-12-31 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.000
1988-01-29 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.000
1988-02-29 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.000

In [84]:
# get weights from backtest
strategy_weights = s_weights.loc[rebalance_dates].copy()
strategy_weights.round(3)[:15]


Out[84]:
RS0003 DM0001 PMA001 RS0001 PMA002 DM0002 PMA003 RS0002 FFXSX
Date
1986-12-31 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
1987-01-30 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.000
1987-02-27 0.000 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125
1987-03-31 0.125 0.125 0.000 0.125 0.000 0.125 0.125 0.125 0.250
1987-04-30 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 1.000
1987-05-29 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 1.000
1987-06-30 0.000 0.125 0.125 0.000 0.125 0.125 0.125 0.125 0.250
1987-07-31 0.000 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125
1987-08-31 0.000 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125
1987-09-30 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 1.000
1987-10-30 0.000 0.000 0.125 0.000 0.125 0.125 0.125 0.000 0.500
1987-11-30 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.000
1987-12-31 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.000
1988-01-29 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.000
1988-02-29 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.000

In [85]:
aggregated_weights = pd.DataFrame(0, index=rebalance_dates, columns=list(set(s + ['FFXSX'])))
all_prices = pd.DataFrame(0, index=index, columns=list(set(s + ['FFXSX'])))

# get weights from backtest
strategy_weights = s_weights.loc[rebalance_dates].copy()

prices = security_prices.copy()
for name in strategies :
    aggregated_weights[security_weights[name].columns] += security_weights[name].loc[rebalance_dates].mul(strategy_weights[name],axis=0)
    all_prices = prices[name].loc[index].combine_first(all_prices)
    
# need to add in the cash_proxy weights
aggregated_weights['FFXSX'] = aggregated_weights['FFXSX'].add(strategy_weights['FFXSX'], axis=0)
aggregated_weights.round(3)[:15]


Out[85]:
FFXSX FGOVX FRESX MMHYX VGHCX VCVSX VWAHX VWEHX VUSTX FAGIX VFIIX CASHX VWINX
1986-12-31 0.000 0.0 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.0 0.000
1987-01-30 0.000 0.0 0.025 0.125 0.108 0.321 0.062 0.050 0.000 0.042 0.200 0.0 0.067
1987-02-27 0.125 0.0 0.025 0.000 0.108 0.321 0.000 0.154 0.025 0.167 0.050 0.0 0.025
1987-03-31 0.292 0.0 0.025 0.000 0.108 0.129 0.000 0.129 0.000 0.292 0.025 0.0 0.000
1987-04-30 1.000 0.0 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.0 0.000
1987-05-29 1.000 0.0 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.0 0.000
1987-06-30 0.250 0.0 0.025 0.125 0.108 0.217 0.042 0.050 0.025 0.042 0.050 0.0 0.067
1987-07-31 0.125 0.0 0.000 0.125 0.108 0.321 0.104 0.050 0.042 0.000 0.100 0.0 0.025
1987-08-31 0.125 0.0 0.000 0.125 0.000 0.321 0.000 0.154 0.092 0.042 0.075 0.0 0.067
1987-09-30 1.000 0.0 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.0 0.000
1987-10-30 0.500 0.0 0.000 0.000 0.000 0.000 0.000 0.000 0.350 0.000 0.150 0.0 0.000
1987-11-30 0.000 0.0 0.025 0.000 0.000 0.000 0.104 0.154 0.283 0.042 0.392 0.0 0.000
1987-12-31 0.000 0.0 0.025 0.000 0.108 0.321 0.000 0.154 0.067 0.000 0.300 0.0 0.025
1988-01-29 0.000 0.0 0.025 0.000 0.108 0.217 0.063 0.025 0.067 0.042 0.388 0.0 0.067
1988-02-29 0.000 0.0 0.025 0.000 0.108 0.321 0.000 0.154 0.025 0.042 0.300 0.0 0.025

In [86]:
all_prices[:15]


Out[86]:
CASHX FAGIX FFXSX FGOVX FRESX MMHYX VCVSX VFIIX VGHCX VUSTX VWAHX VWEHX VWINX
Date
1986-12-31 1.0 0.758814 2.379192 1.876035 2.116003 1.553293 1.209364 1.692999 2.687786 1.349658 1.849020 0.728181 2.085360
1987-01-02 1.0 0.759595 2.379192 1.881510 2.137291 1.553444 1.215611 1.694684 2.725879 1.357559 1.849020 0.728973 2.099459
1987-01-05 1.0 0.761156 2.379192 1.885159 2.167093 1.554963 1.228104 1.696368 2.782255 1.360192 1.850753 0.730556 2.119966
1987-01-06 1.0 0.762718 2.379192 1.885159 2.173480 1.558000 1.234351 1.696368 2.786826 1.362826 1.861151 0.732930 2.123811
1987-01-07 1.0 0.765060 2.379192 1.886984 2.186252 1.561037 1.236850 1.699737 2.818824 1.366776 1.864617 0.734513 2.132783
1987-01-08 1.0 0.768182 2.379192 1.890634 2.196896 1.562556 1.240598 1.703106 2.849297 1.370726 1.869815 0.736888 2.152009
1987-01-09 1.0 0.768963 2.379192 1.890634 2.194768 1.562556 1.243096 1.703106 2.861487 1.369409 1.871548 0.737679 2.146882
1987-01-12 1.0 0.769744 2.379192 1.890634 2.199025 1.564074 1.245595 1.704791 2.881295 1.374676 1.873281 0.739262 2.152009
1987-01-13 1.0 0.769744 2.379192 1.888809 2.201154 1.564074 1.245595 1.704791 2.882819 1.370726 1.875014 0.740054 2.149446
1987-01-14 1.0 0.769744 2.379192 1.886984 2.201154 1.565593 1.251842 1.706475 2.914816 1.368093 1.876747 0.740845 2.152009
1987-01-15 1.0 0.770524 2.379192 1.886984 2.194768 1.567111 1.261837 1.706475 2.940719 1.365459 1.876747 0.741637 2.158418
1987-01-16 1.0 0.771305 2.379192 1.888809 2.192639 1.567111 1.260587 1.709845 2.934624 1.368093 1.880213 0.742428 2.162263
1987-01-19 1.0 0.771305 2.379192 1.888809 2.203283 1.570148 1.263086 1.709845 2.952908 1.365459 1.881946 0.742428 2.167390
1987-01-20 1.0 0.772866 2.379192 1.892459 2.196896 1.571667 1.265585 1.713214 2.943766 1.374676 1.883679 0.743220 2.171235
1987-01-21 1.0 0.773647 2.379192 1.890634 2.194768 1.573185 1.263086 1.709845 2.939195 1.375993 1.888877 0.744803 2.169953

In [87]:
from backtest_helpers.backtest import backtest

aggregated_weights = aggregated_weights[aggregated_weights.sum(1) > 0]
values, holdings, weights = backtest(all_prices, aggregated_weights, 10000., offset=0, commission=10.)


FIRST BUY DATE = 1987-01-30 00:00:00


In [88]:
# just to check nothing changed
values.plot(figsize=(15, 10), grid=True)


Out[88]:
<matplotlib.axes._subplots.AxesSubplot at 0xb4e6588>

In [89]:
transactions = (holdings - holdings.shift(1).fillna(0))
transactions = transactions[transactions.sum(1) != 0]
transactions.round(0)[:15]


Out[89]:
CASHX FAGIX FFXSX FGOVX FRESX MMHYX VCVSX VFIIX VGHCX VUSTX VWAHX VWEHX VWINX
Date
1987-01-30 0.0 531.0 0.0 0.0 113.0 793.0 2530.0 1165.0 350.0 0.0 328.0 671.0 306.0
1987-02-27 0.0 1623.0 532.0 0.0 1.0 -793.0 -79.0 -870.0 4.0 186.0 -328.0 1406.0 -188.0
1987-03-31 0.0 1608.0 715.0 0.0 -1.0 0.0 -1458.0 -146.0 -10.0 -186.0 0.0 -337.0 -117.0
1987-04-30 0.0 -3762.0 2966.0 0.0 -113.0 0.0 -993.0 -149.0 -344.0 0.0 0.0 -1740.0 0.0
1987-06-30 0.0 541.0 -3160.0 0.0 114.0 822.0 1711.0 303.0 329.0 198.0 237.0 682.0 322.0
1987-07-31 0.0 -541.0 -524.0 0.0 -114.0 3.0 820.0 307.0 -14.0 139.0 359.0 6.0 -200.0
1987-08-31 0.0 546.0 3.0 0.0 0.0 2.0 -36.0 -145.0 -314.0 422.0 -596.0 1436.0 203.0
1987-09-30 0.0 -546.0 3621.0 0.0 0.0 -827.0 -2495.0 -465.0 0.0 -759.0 0.0 -2125.0 -325.0
1987-10-30 0.0 0.0 -2076.0 0.0 0.0 0.0 0.0 911.0 0.0 2809.0 0.0 0.0 0.0
1987-11-30 0.0 572.0 -2076.0 0.0 136.0 0.0 0.0 1462.0 0.0 -531.0 616.0 2203.0 0.0
1987-12-31 0.0 -572.0 0.0 0.0 -2.0 0.0 3165.0 -552.0 436.0 -1742.0 -616.0 -13.0 128.0
1988-01-29 0.0 597.0 0.0 0.0 -2.0 0.0 -1009.0 546.0 -25.0 2.0 371.0 -1830.0 210.0
1988-02-29 0.0 0.0 0.0 0.0 -1.0 0.0 938.0 -500.0 -12.0 -333.0 -371.0 1860.0 -210.0
1988-03-31 0.0 -598.0 4370.0 0.0 -132.0 0.0 -3094.0 -1867.0 -399.0 -205.0 0.0 -2220.0 -129.0
1988-04-29 0.0 1781.0 -1092.0 0.0 0.0 0.0 718.0 0.0 0.0 211.0 0.0 357.0 0.0

In [90]:
def generate_orders(transactions, prices) :
    orders = pd.DataFrame()
    for i in range(len(transactions)):
        for j in range(len(transactions.columns)):
            t = transactions.ix[i]
            qty = abs(t[j])
            if qty >= 1.:
                if transactions.ix[i][j] < 0 :
                    orders = orders.append([[t.name.date().year, t.name.date().month, t.name.date().day, t.index[j],\
                                             'Sell', -abs(t[j]), prices.ix[t.name][t.index[j]]]])
                if transactions.ix[i][j] > 0 :
                    orders = orders.append([[t.name.date().year, t.name.date().month, t.name.date().day, t.index[j],\
                                             'Buy', abs(t[j]), prices.ix[t.name][t.index[j]]]])
    orders.columns = ['Year', 'Month', 'Day', 'Symbol', 'Action', 'Qty', 'Price']
    orders
    return orders

In [91]:
# del transactions['CASHX']
orders = generate_orders(transactions, all_prices)
orders[:10]


Out[91]:
Year Month Day Symbol Action Qty Price
0 1987 1 30 FAGIX Buy 531.127243 0.784495
0 1987 1 30 FRESX Buy 113.139117 2.209669
0 1987 1 30 MMHYX Buy 793.035499 1.576222
0 1987 1 30 VCVSX Buy 2530.065724 1.268083
0 1987 1 30 VFIIX Buy 1165.497090 1.716006
0 1987 1 30 VGHCX Buy 349.898610 3.096135
0 1987 1 30 VWAHX Buy 327.713957 1.907151
0 1987 1 30 VWEHX Buy 670.674618 0.745518
0 1987 1 30 VWINX Buy 305.601663 2.181489
0 1987 2 27 FAGIX Buy 1623.141794 0.791576

In [ ]: