Created
December 16, 2013 23:20
-
-
Save yanofsky/7996646 to your computer and use it in GitHub Desktop.
This is the code I used for the calculations in this story http://qz.com/157404/how-you-could-have-turned-1000-into-billions-of-dollars-by-perfectly-trading-the-sp-500-this-year/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# encoding: utf-8 | |
import sys | |
import os | |
import csv | |
import datetime | |
#define market holidays | |
marketHolidays = ["2013-01-21","2013-02-18","2013-03-29","2013-05-27","2013-07-04","2013-09-02","2013-11-28","2013-12-25"] | |
def main(): | |
data = [] | |
#this is a spreadsheet with all of the data | |
#the first column is dates, every subsiquent column is the closing price of a stock (the ticker is the header) | |
#i.e. every row is a day of data | |
with open("perfectsp500raw.csv","rb") as f: | |
#open the file turn every row into a dict with the tickers as the keys | |
reader = csv.DictReader(f) | |
#cache the tickers to make things easier | |
headers = reader.fieldnames | |
rawdata = [] | |
#put the data into a list to make it easier to work with | |
for row in reader: | |
rawdata.append(row) | |
for i in range(1,len(rawdata)): | |
#loop through all of the data | |
thenrow = rawdata[i] | |
nowrow = rawdata[i-1] | |
#convert the date column into a native date object | |
nowdate = datetime.datetime.strptime(nowrow["date"],"%Y-%m-%d") | |
#skip the day if it's a weekday or a market holiday | |
if nowdate.weekday() > 4 or nowrow["date"] in marketHolidays: | |
continue | |
#initialize a dummy row of data to fill in later | |
data_row = {"date":nowrow["date"],"max": DayInfo("NADA",float("-inf"),float("-inf"))} | |
#loop through every ticker (the first one is the date) | |
for j in range(1,len(headers)): | |
ticker = headers[j] | |
#some days don't have data (they weren't listed then or didn't trade that day or otherwise) | |
#set the price on that day to 0 (0's are ignored) | |
try: | |
now = float(nowrow[ticker]) | |
except: | |
now = 0 | |
try: | |
then = float(thenrow[ticker]) | |
except: | |
then = 0 | |
#create a DayInfo object using the ticker and the one day close to close change | |
data_row[ticker] = DayInfo(ticker,now,pctChange(now,then)) | |
#if the the current company has the largest pct change set it as the max for the day | |
data_row["max"] = max(data_row["max"],data_row[ticker]) | |
#add the row to the cleaned data list | |
data.append(data_row) | |
#set a amount of money to start with | |
val = 1000 | |
#set a trading fee | |
fee = 0 | |
data = reversed(data) | |
for row in data: | |
#convert the pct change into a factor to multiply the running total by | |
factor = row["max"].pctChng + 1 | |
#calculate the effect of the trade on the running total | |
val = val*factor - (fee * 2) #this isn't exactly right, on the first day there is only the buy fee and on the last day there is only the sell fee | |
#print out the date, a the running value as formatted number, the change, and the Day info object for the max (ticker + price) | |
print "%s\t%s\t%s\t%s" % (row["date"], "{:,}".format(val/1000), float(round(row["max"].pctChng*10000))/100, row["max"]) | |
pass | |
def pctChange(now,then): | |
if now == 0 or then == 0: | |
#this effectively ignores 0 prices | |
return float("-inf") | |
return (now-then)/then | |
class DayInfo(): | |
"""dayInfo is a custom class i created so I could use the max function and not have to keep track separately of the ticker""" | |
def __init__(self, ticker, val,pctChng): | |
self.ticker = ticker | |
self.val = val | |
self.pctChng = pctChng | |
def __cmp__(self, other): | |
#on comparison, use pctChng to compare | |
if self.pctChng == other.pctChng: | |
return 0 | |
elif self.pctChng > other.pctChng: | |
return 1 | |
return -1 | |
def __repr__(self): | |
#on print use ticker {tab} price | |
return "%s\t%s" % (self.ticker,self.val) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment