Introduction

In the previous Notebook, we created a dataset of performances by ETF. In this Notebook, we will start to create a very simple model to at least validate that this method works.

Simulator

In [1]:
import pandas as pd
import numpy as np

import matplotlib.pyplot as plt

import datetime
In [2]:
df = pd.read_csv("F:/data/trading/perfs.csv", index_col = 0)
df.index = pd.to_datetime(df.index, format="%Y-%m-%d")
In [3]:
df.info()
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 262 entries, 2013-11-04 to 2018-11-05
Columns: 156 entries, AIA to YLCO
dtypes: float64(156)
memory usage: 321.4 KB
In [4]:
df.head()
Out[4]:
AIA ALTY BBH BND BNDX BOTZ CACG CATH CFO CIBR ... VGSH VIDI VIGI VMBS VNQI VUSE VWOB VYMI XT YLCO
date
2013-11-04 1.000000 NaN 1.000000 1.000000 1.000000 NaN NaN NaN NaN NaN ... 1.000000 1.000000 NaN 1.000000 1.000000 NaN 1.000000 NaN NaN NaN
2013-11-11 0.986157 NaN 0.974592 0.996934 0.997845 NaN NaN NaN NaN NaN ... 0.999969 0.992490 NaN 0.997100 0.987288 NaN 0.992161 NaN NaN NaN
2013-11-18 0.988175 NaN 0.990123 0.996630 0.997840 NaN NaN NaN NaN NaN ... 1.000328 0.975841 NaN 0.996904 0.989034 NaN 0.983264 NaN NaN NaN
2013-11-25 1.010869 NaN 1.027741 0.997411 0.997802 NaN NaN NaN NaN NaN ... 1.000810 0.985741 NaN 0.998178 0.983724 NaN 0.988082 NaN NaN NaN
2013-12-02 1.016058 NaN 1.061193 0.998075 0.998993 NaN NaN NaN NaN NaN ... 1.000607 0.988227 NaN 0.994878 0.975501 NaN 0.988906 NaN NaN NaN

5 rows × 156 columns

For this model we will use an history of 6 months (=26 weeks) and update our portfolio every 4 weeks. We won't consider any taxes.

In [36]:
history_used = 26         # 6 months
steps = 4                 # change etf every 4 weeks
benefits = 1              # starting performance
current_ETF = None
results = []              # Store our current porfolio performance by 4 weeks
posX = []                 # Dates for the plot
ETF_list = []             # list of ETFs

for week in range(history_used, len(df), steps):
    posX.append(df.index[week])
    
    # get the benefits of the last 4 weeks
    if current_ETF is not None:
        benefits *= (df.iloc[week][current_ETF] / df.iloc[week-4][current_ETF])
    results.append(benefits)
    
    # get the trend over the last 26 weeks
    trend = df.iloc[week-1]/df.iloc[week-history_used]
    to_buy = trend.argmax()
    date = df.index[week]
    if current_ETF != to_buy:
        print("{} - Buy {} - R {:.3f}".format(date, to_buy, benefits))
        current_ETF = to_buy
    else:
        print("{} - Keep {} - R {:.3f}".format(date, to_buy, benefits))
    ETF_list.append(current_ETF)
2014-05-05 00:00:00 - Buy PPH - R 1.000
2014-06-02 00:00:00 - Keep PPH - R 0.998
2014-06-30 00:00:00 - Buy SILJ - R 1.031
2014-07-28 00:00:00 - Buy TUR - R 1.053
2014-08-25 00:00:00 - Buy HEWG - R 0.961
2014-09-22 00:00:00 - Buy TUR - R 0.994
2014-10-20 00:00:00 - Buy BBH - R 0.948
2014-11-17 00:00:00 - Keep BBH - R 1.091
2014-12-15 00:00:00 - Keep BBH - R 1.137
2015-01-12 00:00:00 - Keep BBH - R 1.125
2015-02-09 00:00:00 - Keep BBH - R 1.142
2015-03-09 00:00:00 - Keep BBH - R 1.233
2015-04-06 00:00:00 - Buy HEWG - R 1.224
2015-05-04 00:00:00 - Buy MCHI - R 1.177
2015-06-01 00:00:00 - Keep MCHI - R 1.141
2015-06-29 00:00:00 - Buy QQQC - R 1.078
2015-07-27 00:00:00 - Buy SYBT - R 0.939
2015-08-24 00:00:00 - Keep SYBT - R 0.903
2015-09-21 00:00:00 - Buy KBWP - R 0.900
2015-10-19 00:00:00 - Buy SYBT - R 0.925
2015-11-16 00:00:00 - Keep SYBT - R 0.981
2015-12-14 00:00:00 - Buy PSCU - R 0.960
2016-01-11 00:00:00 - Keep PSCU - R 0.976
2016-02-08 00:00:00 - Keep PSCU - R 1.021
2016-03-07 00:00:00 - Buy RING - R 1.036
2016-04-04 00:00:00 - Buy SILJ - R 1.061
2016-05-02 00:00:00 - Keep SILJ - R 1.608
2016-05-30 00:00:00 - Keep SILJ - R 1.486
2016-06-27 00:00:00 - Keep SILJ - R 1.668
2016-07-25 00:00:00 - Keep SILJ - R 2.013
2016-08-22 00:00:00 - Keep SILJ - R 2.315
2016-09-19 00:00:00 - Keep SILJ - R 1.968
2016-10-17 00:00:00 - Buy EWZS - R 1.685
2016-11-14 00:00:00 - Keep EWZS - R 1.584
2016-12-12 00:00:00 - Buy SYBT - R 1.484
2017-01-09 00:00:00 - Keep SYBT - R 1.587
2017-02-06 00:00:00 - Keep SYBT - R 1.502
2017-03-06 00:00:00 - Keep SYBT - R 1.502
2017-04-03 00:00:00 - Buy KBWB - R 1.359
2017-05-01 00:00:00 - Buy FTXL - R 1.369
2017-05-29 00:00:00 - Buy EMQQ - R 1.401
2017-06-26 00:00:00 - Keep EMQQ - R 1.386
2017-07-24 00:00:00 - Buy TUR - R 1.462
2017-08-21 00:00:00 - Buy EMQQ - R 1.471
2017-09-18 00:00:00 - Buy TUR - R 1.575
2017-10-16 00:00:00 - Buy GAMR - R 1.439
2017-11-13 00:00:00 - Buy BOTZ - R 1.479
2017-12-11 00:00:00 - Keep BOTZ - R 1.441
2018-01-08 00:00:00 - Keep BOTZ - R 1.520
2018-02-05 00:00:00 - Keep BOTZ - R 1.609
2018-03-05 00:00:00 - Buy IBUY - R 1.505
2018-04-02 00:00:00 - Keep IBUY - R 1.480
2018-04-30 00:00:00 - Keep IBUY - R 1.485
2018-05-28 00:00:00 - Buy PXI - R 1.540
2018-06-25 00:00:00 - Buy PTH - R 1.469
2018-07-23 00:00:00 - Keep PTH - R 1.484
2018-08-20 00:00:00 - Buy JSML - R 1.415
2018-09-17 00:00:00 - Buy PTH - R 1.480
2018-10-15 00:00:00 - Buy FINX - R 1.300

Now let's plot the resulting perf in comparison of all other ETFs.

In [37]:
used = np.unique(ETF_list)
not_used = np.setdiff1d(df.columns, used)
In [38]:
fig, ax1 = plt.subplots(1, 1, figsize=(20,12))
ax1.plot(posX, results, linewidth=5.0)
df.plot(ax=ax1, linewidth=0.5, legend=False)
plt.title("Performance of Momentum vs all ETFs")
plt.show()

We can see that the performance is not that good. To understand it, we can plot it only with used ETFs

In [39]:
fig, ax1 = plt.subplots(1, 1, figsize=(20,12))
ax1.plot(posX, results, linewidth=5.0)
df[used].plot(ax=ax1, linewidth=0.5, legend=False)
plt.title("Performance of Momentum vs used ETFs")
plt.show()