pg. 161 from "Trading Evolved" by Andreas F. Clenow
"The rules of this first ETF model are the following. We will use five ETFs to allocate our assets to. Each ETF will have a target weight, and at the beginning of each month we will reset the allocation to this target weight."
25% SPY - S&P500 Index Tracker ETF 30% TLT - 20 Year Treasury ETF 30% IEF - 7-10 Year Treasury ETF 7.5% GLD - Gold Tracker ETF 7.5% DBC - General Commodity Tracker ETF
In [1]:
import pandas as pd
import matplotlib.pyplot as plt
import datetime
from talib.abstract import *
#import numpy as np
import pinkfish as pf
# format price data
pd.options.display.float_format = '{:0.2f}'.format
%matplotlib inline
In [2]:
# set size of inline plots
'''note: rcParams can't be in same cell as import matplotlib
or %matplotlib inline
%matplotlib notebook: will lead to interactive plots embedded within
the notebook, you can zoom and resize the figure
%matplotlib inline: only draw static images in the notebook
'''
plt.rcParams["figure.figsize"] = (10, 7)
Portfolios
In [3]:
# large diversified ETFs
large_diversified_weights = {
# stocks:US
'SPY': 0.20, #1993
'QQQ': 0.10, #1999
# stocks:global
'EFA': 0.05, #2001
# stocks:emerging markets
'EEM': 0.05, #2003
# 40% stocks
# bonds:treasuries
'TLT': 0.05, #2002
'IEF': 0.05, #2002
'TIP': 0.05, #2003
'BSV': 0.05, #2007
# bonds:corporate bonds
'LQD': 0.05, #2002
# bonds: fixed income
'AGG': 0.05, #2003
# 30% bonds
# metals
'GLD': 0.10, #2004
'SLV': 0.05, #2006
# 15% metals
# commodities 5%
'DBC': 0.05, #2006
# real estate 10%
'NLY': 0.10 #1997
}
# pinkfish portfolio
pinkfish_weights = \
{'SPY': 0.20, 'QQQ':0.20, 'TLT': 0.20, 'NLY': 0.20, 'GLD': 0.20}
# 50% S&P 500, 50% treasury
fifty_fifty_weights = \
{'SPY': 0.50, 'TLT': 0.50}
# ETF portfolio in "Trading Evolved"
trading_evolved_weights = \
{'SPY': 0.25, 'TLT': 0.30, 'IEF': 0.30, 'GLD': 0.075, 'DBC': 0.075}
# Dave Ramsey - 25% Growth and income, 25% Growth, 25% Aggressive growth, 25% International
dave_ramsey_weights = \
{'SPY': 0.25, 'VQNPX': 0.25, 'RPG': 0.25, 'EFA': 0.25}
# Warren Buffett Retirement Fund: 90% S&P500, 10% Short Term Treasuries
warren_buffett_weights = \
{'SPY': 0.90, 'SHY': 0.10}
# https://www.forbes.com/sites/baldwin/2016/07/25/eight-famous-portfolios/#42c50d7d5cce
# american households: 25% real estate, 30% stocks, 30% fixed income, 5% cash, 10% alternatives
american_households_weights = \
{'NLY': 0.25, 'SPY': 0.30, 'AGG': 0.30, 'GLD': 0.10}
# janet yellen: 50% fixed income, 40% S&P500, 10% cash
janet_yellen_weights = \
{'AGG': 0.50, 'SPY': 0.40}
Some global data
In [4]:
#select one of the above
weights = pinkfish_weights
symbols = list(weights.keys())
capital = 10000
margin = pf.Margin.CASH
start = datetime.datetime(1900, 1, 1)
end = datetime.datetime.now()
use_cache = True
In [5]:
# fetch timeseries
portfolio = pf.Portfolio()
ts = portfolio.fetch_timeseries(symbols, start, end, use_cache=use_cache)
ts
Out[5]:
In [6]:
# add calendar columns
ts = portfolio.calendar(ts)
In [7]:
ts, start = portfolio.finalize_timeseries(ts, start)
In [8]:
portfolio.init_trade_logs(ts, capital, margin)
pf.TradeLog.instance
Out[8]:
In [9]:
# trading algorithm
for i, row in enumerate(ts.itertuples()):
date = row.Index.to_pydatetime()
end_flag = pf.is_last_row(ts, i)
# rebalance on the first trading day of each month
if row.first_dotm or end_flag:
#portfolio.print_holdings(date, row)
#TODO: use share_percent() and adjust positions that need reducing first
for symbol in portfolio.symbols:
#print(symbol, portfolio.share_percent(row, symbol))
price = portfolio.get_row_column_price(row, symbol)
weight = 0 if end_flag else weights[symbol]
portfolio.adjust_percent(date, price, weight, symbol, row)
# record daily balance
portfolio.record_daily_balance(date, row)
In [10]:
# get logs
rlog, tlog, dbal = portfolio.get_logs()
In [11]:
rlog.head()
Out[11]:
In [12]:
tlog.tail()
Out[12]:
In [13]:
dbal.head()
Out[13]:
In [14]:
stats = pf.stats(ts, tlog, dbal, capital)
pf.print_full(stats)
In [15]:
totals = portfolio.performance_per_symbol(weights)
totals
Out[15]:
In [16]:
corr_df = portfolio.correlation_map(ts)
corr_df
Out[16]:
In [17]:
benchmark = pf.Benchmark('SPY', capital, start, end, use_adj=True)
benchmark.run()
In [18]:
benchmark.tlog, benchmark.dbal = benchmark.get_logs()
In [19]:
benchmark.stats = benchmark.get_stats()
In [20]:
pf.plot_equity_curve(dbal, benchmark=benchmark.dbal)
In [21]:
df = pf.summary(stats, benchmark.stats, metrics=pf.currency_metrics)
df
Out[21]:
In [22]:
df = pf.plot_bar_graph(stats, benchmark.stats)
df
Out[22]: