see: https://en.wikipedia.org/wiki/Sell_in_May
"Sell in May and go away" (aka the Halloween indicator) is an investment adage warning investors to divest their stock holdings in May and wait to reinvest in November.
In [1]:
import pandas as pd
import matplotlib.pyplot as plt
import datetime
from talib.abstract import *
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)
In [3]:
pf.DEBUG = False
Some global data
In [4]:
symbol = '^GSPC'
#symbol = 'SPY'
capital = 10000
start = datetime.datetime(1900, 1, 1)
#start = datetime.datetime.strptime(pf.SP500_BEGIN, '%Y-%m-%d')
end = datetime.datetime.now()
Define Strategy Class
In [5]:
class Strategy:
def __init__(self, symbol, capital, start, end):
self._symbol = symbol
self._capital = capital
self._start = start
self._end = end
def _algo(self):
pf.TradeLog.cash = capital
for i, row in enumerate(self._ts.itertuples()):
date = row.Index.to_pydatetime()
high = row.high; low = row.low; close = row.close;
end_flag = pf.is_last_row(self._ts, i)
shares = 0
# buy (at the open on first trading day in Nov)
if (self._tlog.shares == 0
and row.month == 11 and row.first_dotm):
# enter buy in trade log
shares = self._tlog.buy(date, row.open)
# sell
elif (self._tlog.shares > 0
and row.month == 5 and row.first_dotm
or end_flag):
# enter sell in trade log
shares = self._tlog.sell(date, row.open)
if shares > 0:
pf.DBG("{0} BUY {1} {2} @ {3:.2f}".format(
date, shares, self._symbol, row.open))
elif shares < 0:
pf.DBG("{0} SELL {1} {2} @ {3:.2f}".format(
date, -shares, self._symbol, row.open))
# record daily balance
self._dbal.append(date, high, low, close)
def run(self):
self._ts = pf.fetch_timeseries(self._symbol)
self._ts = pf.select_tradeperiod(self._ts, self._start, self._end,
use_adj=True)
# add calendar columns
self._ts = pf.calendar(self._ts)
self._tlog = pf.TradeLog(symbol)
self._dbal = pf.DailyBal()
self._ts, self._start = pf.finalize_timeseries(self._ts, self._start)
self._algo()
def get_logs(self):
""" return DataFrames """
self.rlog = self._tlog.get_log_raw()
self.tlog = self._tlog.get_log()
self.dbal = self._dbal.get_log(self.tlog)
return self.rlog, self.tlog, self.dbal
def get_stats(self):
stats = pf.stats(self._ts, self.tlog, self.dbal, self._capital)
return stats
Run Strategy
In [6]:
s = Strategy(symbol, capital, start, end)
s.run()
Retrieve log DataFrames
In [7]:
rlog, tlog, dbal = s.get_logs()
stats = s.get_stats()
In [8]:
rlog.tail()
Out[8]:
In [9]:
tlog.tail()
Out[9]:
In [10]:
dbal.tail()
Out[10]:
In [11]:
pf.print_full(stats)
Run Benchmark, Retrieve benchmark logs, and Generate benchmark stats
In [12]:
benchmark = pf.Benchmark(symbol, capital, s._start, s._end)
benchmark.run()
benchmark.tlog, benchmark.dbal = benchmark.get_logs()
benchmark.stats = benchmark.get_stats()
Plot Equity Curves: Strategy vs Benchmark
In [13]:
pf.plot_equity_curve(dbal, benchmark=benchmark.dbal)
Plot Trades
In [14]:
pf.plot_trades(dbal, benchmark=benchmark.dbal)
Bar Graph: Strategy vs Benchmark
In [15]:
df = pf.plot_bar_graph(stats, benchmark.stats)
df
Out[15]: