Momentum

A stock that's going up tends to keep going up...until it doesn't. Momentum is the theory that stocks that have recently gone up will keep going up disproportionate to their underlying value because folks are overenthusiastic about them.

1. The SPY is higher than X days ago, buy
2. If the SPY is lower than X days ago, sell your long position.

In [1]:
import pandas as pd
import matplotlib.pyplot as plt
import datetime
from talib.abstract import *

import pinkfish as pf
import strategy

# 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)

Some global data


In [3]:
symbol = '^GSPC'
#symbol = 'SPY'
#symbol = 'DIA'
#symbol = 'QQQ'
#symbol = 'IWM'
#symbol = 'TLT'
#symbol = 'GLD'
#symbol = 'AAPL'
#symbol = 'BBRY'
#symbol = 'GDX'
#symbol = 'OIH'
capital = 10000
start = datetime.datetime(1900, 1, 1)
#start = datetime.datetime.strptime(pf.SP500_BEGIN, '%Y-%m-%d')
end = datetime.datetime.now()

Define lookback period in months


In [4]:
period = None

Run Strategy


In [5]:
s = strategy.Strategy(symbol, capital, start, end, period, margin=2)
s.run()

Retrieve log DataFrames


In [6]:
tlog, dbal = s.get_logs()
stats = s.get_stats()

In [7]:
tlog.tail(10)


Out[7]:
entry_date entry_price exit_date exit_price pl_points pl_cash qty cumul_total direction symbol
130 2015-11-23 2086.59 2015-11-30 2080.41 -6.18 -97869.26 15836 16414206.45 LONG ^GSPC
131 2015-12-28 2056.50 2016-01-04 2012.66 -43.84 -700211.93 15972 15713994.51 LONG ^GSPC
132 2016-02-29 1932.23 2016-05-02 2081.43 149.20 2428229.21 16275 18142223.72 LONG ^GSPC
133 2016-05-09 2058.69 2016-05-16 2066.66 7.97 140542.46 17634 18282766.18 LONG ^GSPC
134 2016-05-31 2096.95 2018-10-29 2641.25 544.30 9496402.95 17447 27779169.13 LONG ^GSPC
135 2018-11-05 2738.31 2018-11-12 2726.22 -12.09 -245380.42 20296 27533788.71 LONG ^GSPC
136 2018-11-26 2673.45 2018-12-10 2637.72 -35.73 -736216.25 20605 26797572.46 LONG ^GSPC
137 2019-01-22 2632.90 2019-01-28 2643.85 10.95 222978.83 20363 27020551.29 LONG ^GSPC
138 2019-02-11 2709.80 2019-05-13 2811.87 102.07 2036297.86 19950 29056849.15 LONG ^GSPC
139 2019-06-03 2744.45 2020-03-09 2746.56 2.11 44696.30 21182 29101545.45 LONG ^GSPC

In [8]:
dbal.tail()


Out[8]:
high low close shares cash leverage state
date
2020-07-13 35174481.07 33467844.06 33582892.13 19870 -29111328.69 1.87 -
2020-07-14 34491546.84 33035273.77 34423394.10 19870 -29111328.69 1.85 -
2020-07-15 35233295.50 34487772.71 35000419.68 19870 -29111328.69 1.83 -
2020-07-16 34877818.48 34444656.36 34782048.57 19870 -29111328.69 1.84 -
2020-07-17 35138714.10 34584934.87 34964056.03 19870 -29111328.69 1.83 -

Generate strategy stats - display all available stats


In [9]:
pf.print_full(stats)


start                                                  1929-06-10
end                                                    2020-07-17
beginning_balance                                           10000
ending_balance                                        34964056.03
total_net_profit                                      29101545.45
gross_profit                                          33840977.39
gross_loss                                            -4739431.94
profit_factor                                                7.14
return_on_initial_capital                               291015.45
annual_return_rate                                           9.37
trading_period                           91 years 1 months 7 days
pct_time_in_market                                          71.84
margin                                                          2
avg_leverage                                                 1.55
max_leverage                                                 2.68
min_leverage                                                 1.00
total_num_trades                                              140
trades_per_year                                              1.54
num_winning_trades                                             62
num_losing_trades                                              78
num_even_trades                                                 0
pct_profitable_trades                                       44.29
avg_profit_per_trade                                    207868.18
avg_profit_per_winning_trade                            545822.22
avg_loss_per_losing_trade                               -60761.95
ratio_avg_profit_win_loss                                    8.98
largest_profit_winning_trade                           9496402.95
largest_loss_losing_trade                              -736216.25
num_winning_points                                        3454.04
num_losing_points                                         -466.79
total_net_points                                          2987.25
avg_points                                                  21.34
largest_points_winning_trade                               561.73
largest_points_losing_trade                                -56.24
avg_pct_gain_per_trade                                       4.69
largest_pct_winning_trade                                   87.59
largest_pct_losing_trade                                   -19.60
max_consecutive_winning_trades                                  5
max_consecutive_losing_trades                                  10
avg_bars_winning_trades                                    225.77
avg_bars_losing_trades                                      32.49
max_closed_out_drawdown                                    -86.60
max_closed_out_drawdown_start_date                     1929-09-16
max_closed_out_drawdown_end_date                       1933-02-27
max_closed_out_drawdown_recovery_date                  1954-11-11
drawdown_recovery                                           -3.45
drawdown_annualized_return                                  -9.24
max_intra_day_drawdown                                     -86.60
avg_yearly_closed_out_drawdown                             -18.69
max_yearly_closed_out_drawdown                             -72.88
avg_monthly_closed_out_drawdown                             -4.59
max_monthly_closed_out_drawdown                            -53.66
avg_weekly_closed_out_drawdown                              -1.72
max_weekly_closed_out_drawdown                             -40.66
avg_yearly_closed_out_runup                                 36.04
max_yearly_closed_out_runup                                212.63
avg_monthly_closed_out_runup                                 5.63
max_monthly_closed_out_runup                                77.69
avg_weekly_closed_out_runup                                  1.98
max_weekly_closed_out_runup                                 53.99
pct_profitable_years                                        63.67
best_year                                                  179.42
worst_year                                                 -70.45
avg_year                                                    13.21
annual_std                                                  28.72
pct_profitable_months                                       47.71
best_month                                                  77.69
worst_month                                                -53.66
avg_month                                                    0.94
monthly_std                                                  6.81
pct_profitable_weeks                                        42.46
best_week                                                   53.99
worst_week                                                 -40.66
avg_week                                                     0.24
weekly_std                                                   3.41
sharpe_ratio                                                 0.49
sortino_ratio                                                0.50
dtype: object

Equity curve

Run Benchmark, Retrieve benchmark logs, and Generate benchmark stats


In [10]:
benchmark = pf.Benchmark(symbol, capital, s._start, s._end)
benchmark.run()
benchmark.tlog, benchmark.dbal = benchmark.get_logs()
benchmark.stats = benchmark.get_stats()


1929-06-10 00:00:00 BUY  395 ^GSPC @ 25.27
2020-07-17 00:00:00 SELL 395 ^GSPC @ 3224.73

Plot Equity Curves: Strategy vs Benchmark


In [11]:
pf.plot_equity_curve(dbal, benchmark=benchmark.dbal)


Plot Trades


In [12]:
pf.plot_trades(dbal, benchmark=benchmark.dbal)


Bar Graph: Strategy vs Benchmark


In [13]:
df = pf.plot_bar_graph(stats, benchmark.stats)
df


Out[13]:
strategy benchmark
annual_return_rate 9.37 5.46
max_closed_out_drawdown -86.60 -86.06
drawdown_annualized_return -9.24 -15.75
drawdown_recovery -3.45 -2.71
best_month 77.69 60.91
worst_month -53.66 -42.13
sharpe_ratio 0.49 0.38
sortino_ratio 0.50 0.47
monthly_std 6.81 5.35

In [14]:
returns = dbal['close']
returns.tail()


Out[14]:
date
2020-07-13   33582892.13
2020-07-14   34423394.10
2020-07-15   35000419.68
2020-07-16   34782048.57
2020-07-17   34964056.03
Name: close, dtype: float64

In [15]:
benchmark_returns = benchmark.dbal['close']
benchmark_returns.tail()


Out[15]:
date
2020-07-13   1246330.24
2020-07-14   1263038.76
2020-07-15   1274509.57
2020-07-16   1270168.53
2020-07-17   1273786.69
Name: close, dtype: float64

In [16]:
pf.prettier_graphs(returns, benchmark_returns, label1='Strategy', label2='Benchmark', points_to_plot=5000)