Hi,
From the trading ideas post I am working on "buy on last day of month and sell first day of month end of day".
I used zipline to set it up since open price cannot be retrieved in Quantopian. I want to implement this still in Quantopian. For the moment I just want to share the code of the date calculations, which are a bit more work than in .NET.
For the iteration I would like to show the results in a heatmap. But no clue so far how that works.
It seems the maximum profit is about 22K over more than 10 years with 50K investment.
J.
from zipline import TradingAlgorithm
from zipline.transforms import MovingAverage
from zipline.utils.factory import load_from_yahoo
#from zipline.utils.factory import load_bars_from_yahoo
import zipline as zp
import zipline.finance.performance as pf
from zipline.finance import trading
from datetime import datetime
from datetime import timedelta
from dateutil.relativedelta import relativedelta
from dateutil.rrule import DAILY, rrule, MO, TU, WE, TH, FR
import pytz
import matplotlib.pyplot as plt
import pandas as pd
from pandas.io.data import *
from pandas import Panel, DataFrame, Series, read_csv, concat
import numpy as np
import math
import sys
class BuyLastDayOfMonthSellFirstDayOfMonth(TradingAlgorithm):
"""Buy the last day of the month and sell the first month, the end of the day"""
def initialize(self, stock, buyDaysBeforeEndOfMonth=0, sellDayAfterFirstOfMonth=0):
self.max_notional = self.capital_base*.50
self.STK = stock
self.invested = False
self.set_commission(zp.finance.commission.PerTrade(cost=6.00))
self.investment = 0
self.scheduled_sell_date = None
self.profit = None
self.totalProfit = 0
def handle_data(self, data):
current_date = data['Open'].dt # data[self.STK]['date']
open_price = data['Open'].price # data[self.STK]['open']
close_price = data['Close'].price #data[self.STK]['close']
buy = False
sell = False
#current_STK_shares = self.portfolio.positions[self.STK].amount
#current_STK_value = self.portfolio.positions_value
#current_accountvalue = self.portfolio.cash + self.portfolio.positions_value
# Has short mavg crossed long mavg?
if(not self.invested):
if(current_date.month == 12):
last_day_of_month = datetime(current_date.year+1, 1, 1, 0, 0, 0, 0, pytz.utc) - timedelta(days=1)
else:
last_day_of_month = datetime(current_date.year, current_date.month+1, 1, 0, 0, 0, 0, pytz.utc) - timedelta(days=1)
last_day_of_month_minus_days_before = last_day_of_month - timedelta(days=buyDaysBeforeEndOfMonth)
if(current_date.day >= last_day_of_month_minus_days_before.day): # buy
self.invested = True;
self.scheduled_sell_date = rrule(DAILY, dtstart=last_day_of_month, byweekday=(MO,TU,WE,TH,FR))[1+sellDayAfterFirstOfMonth]
print 'buy on %s day: %s.' % (current_date, current_date.strftime('%A'))
print 'sell planned for: %s day %s.' % (self.scheduled_sell_date, self.scheduled_sell_date.strftime('%A'))
self.num_shares = math.floor(self.max_notional / open_price)
self.order(self.STK, self.num_shares)
buy = True
self.investment = self.num_shares * open_price
elif(self.invested and current_date >= self.scheduled_sell_date):
self.invested = False;
print 'sold on %s day: %s.' % (current_date, current_date.strftime('%A'))
#self.num_shares = math.floor(self.max_notional / close_price)
self.order(self.STK, -1*self.num_shares)
sell = True
self.profit = (self.num_shares * close_price) - self.investment
self.totalProfit = self.totalProfit + self.profit
print 'profit %f on investment of %f. Total: %f' % (self.profit, self.investment, self.totalProfit)
self.investment = 0
self.record(open_price=open_price,
close_price=close_price,
buy=buy,
sell=sell,
investment=self.investment,
num_shares=self.portfolio.positions[self.STK].amount,
profit = self.profit)
def daterange(start_date, end_date):
return rrule(DAILY, dtstart=start_date, until=end_date, byweekday=(MO,TU,WE,TH,FR))
#start of main()
SYMBOL = 'SPY'
buyDaysBeforeEndOfMonth=1
sellDayAfterFirstOfMonth=0
start = datetime(2000, 1, 1, 0, 0, 0, 0, pytz.utc)
end = datetime(2013, 12, 1, 0, 0, 0, 0, pytz.utc)
date_range = daterange(start, end)
#data = pd.io.data.get_data_yahoo(SYMBOL,start=start, end=end, adjust_price=True)
#data.to_csv('c:\\data\\test-long.csv', encoding='utf-8')
data = pd.DataFrame.from_csv('c:\\data\\test-long.csv', index_col=0, parse_dates=True, encoding='utf-8')
#print data.head()
#print data[['Open', 'Close']].head()
#close_key = 'Close'
#df = pd.DataFrame({key: d[close_key] for key, d in data.iteritems()})
data.index = data.index.tz_localize(pytz.utc)
#data = load_from_yahoo(stocks={SYMBOL}, indexes={}, start=start, end=end, adjusted=True)
#print df.head()
#print df[['Open', 'Close']].head()
buyDay = np.arange(0,25,1)
sellDay = np.arange(0,25,1)
SH = np.zeros((len(buyDay),len(sellDay)))
maxSH = 0
for i, smi in enumerate(buyDay):
for j, lmi in enumerate(sellDay):
print smi, lmi
if smi==lmi:
continue
dma = BuyLastDayOfMonthSellFirstDayOfMonth(SYMBOL, buyDaysBeforeEndOfMonth=buyDaysBeforeEndOfMonth, sellDayAfterFirstOfMonth=sellDayAfterFirstOfMonth)
perf = dma.run(data)
print dma.totalProfit
#sharpe = [risk['sharpe'] for risk in dma.risk_report['twelve_month']]
#print "Monthly Sharpe ratios:", sharpe
SH[i,j] = dma.totalProfit#dma.portfolio.portfolio_value#max(sharpe)
#print "portfolio value:", dma.portfolio.portfolio_value
if SH[i,j] > maxSH:
maxSH = SH[i,j]
print 'maxSH:', maxSH
else:
print 'SH[i,j]:', SH[i,j]
#pnl = backtest(ohlc, ccThresh=cc, coThresh=co)
#SH[i,j] = sharpe(pnl)
print 'maxSH:', maxSH
i,j = np.unravel_index(SH.argmax(), SH.shape)
print "value", SH[i,j]
print 'Optimum buyDay %.2f' % buyDay[i]
print 'Optimum sellDay %.2f' % sellDay[j]
input('wait for user key...')