see: https://en.wikipedia.org/wiki/Sell_in_May
algo - Sell short in May and go away, buy to cover in Nov
algo2 - first trading day of the month, adjust position to 50%
(select the one you want to call in the Strategy.run() function
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(2015, 10, 30)
#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 = self._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 to cover (at the open on first trading day in Nov)
if (self._tlog.shares > 0
and row.month == 11 and row.first_dotm or end_flag):
shares = self._tlog.buy2cover(date, row.open)
# sell short (at the open on first trading day in May)
elif (self._tlog.shares == 0
and row.month == 5 and row.first_dotm):
shares = self._tlog.sell_short(date, row.open)
if shares > 0:
pf.DBG("{0} SELL SHORT {1} {2} @ {3:.2f}".format(
date, shares, self._symbol, row.open))
elif shares < 0:
pf.DBG("{0} BUY TO COVER {1} {2} @ {3:.2f}".format(
date, -shares, self._symbol, row.open))
# record daily balance
self._dbal.append(date, high, low, close)
def _algo2(self):
pf.TradeLog.cash = self._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
# on the first day of the month, adjust short position to 50%
if (row.first_dotm or end_flag):
weight = 0 if end_flag else 0.5
self._tlog.adjust_percent(date, close, weight, pf.Direction.SHORT)
# 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(self._symbol)
self._dbal = pf.DailyBal()
self._ts, self._start = pf.finalize_timeseries(self._ts, self._start)
self._algo()
#self._algo2()
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.head(10)
Out[8]:
In [9]:
tlog.head(10)
Out[9]:
In [10]:
dbal.tail(10)
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]: