As I was taking the Computational Investing Part I course in 2012 I had to work on a set of assignments and for some of them I used PyAlgoTrade.
For this assignment I had to pick 4 stocks, invest a total of $100000 during 2011, and calculate:
- Final portfolio value
- Anual return
- Average daily return
- Std. dev. of daily returns
- Sharpe ratio
Although the deliverable was an Excel spreadsheet, I validated the results using this piece of code:
from pyalgotrade import strategy
from pyalgotrade.barfeed import yahoofeed
from pyalgotrade.stratanalyzer import returns
from pyalgotrade.stratanalyzer import sharpe
from pyalgotrade import broker
from pyalgotrade.utils import stats
class MyStrategy(strategy.Strategy):
def __init__(self, feed):
strategy.Strategy.__init__(self, feed, 1000000)
# We wan't to use adjusted close prices instead of close.
self.getBroker().setUseAdjustedValues(True)
# Place the orders to get them processed on the first bar.
orders = {
"aeti": 297810,
"egan": 81266,
"glng": 11095,
"simo": 17293,
}
for instrument, quantity in orders.items():
o = self.getBroker().createMarketOrder(broker.Order.Action.BUY, instrument, quantity, onClose=True)
self.getBroker().placeOrder(o)
def onBars(self, bars):
pass
# Load the yahoo feed from CSV files.
feed = yahoofeed.Feed()
feed.addBarsFromCSV("aeti", "aeti-2011-yahoofinance.csv")
feed.addBarsFromCSV("egan", "egan-2011-yahoofinance.csv")
feed.addBarsFromCSV("glng", "glng-2011-yahoofinance.csv")
feed.addBarsFromCSV("simo", "simo-2011-yahoofinance.csv")
# Evaluate the strategy with the feed's bars.
myStrategy = MyStrategy(feed)
# Attach returns and sharpe ratio analyzers.
retAnalyzer = returns.Returns()
myStrategy.attachAnalyzer(retAnalyzer)
sharpeRatioAnalyzer = sharpe.SharpeRatio()
myStrategy.attachAnalyzer(sharpeRatioAnalyzer)
# Run the strategy
myStrategy.run()
# Print the results.
print "Final portfolio value: $%.2f" % myStrategy.getResult()
print "Anual return: %.2f %%" % (retAnalyzer.getCumulativeReturns()[-1] * 100)
print "Average daily return: %.2f %%" % (stats.mean(retAnalyzer.getReturns()) * 100)
print "Std. dev. daily return: %.4f" % (stats.stddev(retAnalyzer.getReturns()))
print "Sharpe ratio: %.2f" % (sharpeRatioAnalyzer.getSharpeRatio(0, 252))
The results were:
Final portfolio value: $2917766.47
Anual return: 191.78 %
Average daily return: 0.44 %
Std. dev. daily return: 0.0186
Sharpe ratio: 3.78
For these assignments I had to build a market simulation tool that loads orders from a file, executes those, and prints the results for each day.
The orders file for homework 3 look like this:
2011,1,10,AAPL,Buy,1500,
2011,1,13,AAPL,Sell,1500,
2011,1,13,IBM,Buy,4000,
2011,1,26,GOOG,Buy,1000,
2011,2,2,XOM,Sell,4000,
2011,2,10,XOM,Buy,4000,
2011,3,3,GOOG,Sell,1000,
2011,3,3,IBM,Sell,2200,
2011,6,3,IBM,Sell,3300,
2011,5,3,IBM,Buy,1500,
2011,6,10,AAPL,Buy,1200,
2011,8,1,GOOG,Buy,55,
2011,8,1,GOOG,Sell,55,
2011,12,20,AAPL,Sell,1200,
This is the market simulation tool that I built:
import csv
import datetime
import os
from pyalgotrade.barfeed import yahoofeed
from pyalgotrade.barfeed import csvfeed
from pyalgotrade import strategy
from pyalgotrade import broker
from pyalgotrade.utils import stats
from pyalgotrade.stratanalyzer import returns
from pyalgotrade.stratanalyzer import sharpe
class OrdersFile:
def __init__(self, ordersFile):
self.__orders = {}
self.__firstDate = None
self.__lastDate = None
self.__instruments = []
# Load orders from the file.
reader = csv.DictReader(open(ordersFile, "r"), fieldnames=["year", "month", "day", "symbol", "action", "qty"])
for row in reader:
dateTime = datetime.datetime(int(row["year"]), int(row["month"]), int(row["day"]))
self.__orders.setdefault(dateTime, [])
order = (row["symbol"], row["action"], int(row["qty"]))
self.__orders[dateTime].append(order)
# As we process the file, store instruments, first date, and last date.
if row["symbol"] not in self.__instruments:
self.__instruments.append(row["symbol"])
if self.__firstDate == None:
self.__firstDate = dateTime
else:
self.__firstDate = min(self.__firstDate, dateTime)
if self.__lastDate == None:
self.__lastDate = dateTime
else:
self.__lastDate = max(self.__lastDate, dateTime)
def getFirstDate(self):
return self.__firstDate
def getLastDate(self):
return self.__lastDate
def getInstruments(self):
return self.__instruments
def getOrders(self, dateTime):
return self.__orders.get(dateTime, [])
class MyStrategy(strategy.Strategy):
def __init__(self, feed, cash, ordersFile, useAdjustedClose):
# Suscribe to the feed bars event before the broker just to place the orders properly.
feed.getNewBarsEvent().subscribe(self.__onBarsBeforeBroker)
strategy.Strategy.__init__(self, feed, cash)
self.__ordersFile = ordersFile
self.getBroker().setUseAdjustedValues(useAdjustedClose)
# We will allow buying more shares than cash allows.
self.getBroker().setAllowNegativeCash(True)
def __onBarsBeforeBroker(self, bars):
for instrument, action, quantity in self.__ordersFile.getOrders(bars.getDateTime()):
if action.lower() == "buy":
action = broker.Order.Action.BUY
else:
action = broker.Order.Action.SELL
o = self.getBroker().createMarketOrder(action, instrument, quantity, onClose=True)
self.getBroker().placeOrder(o)
def onOrderUpdated(self, order):
execInfo = order.getExecutionInfo()
if not execInfo:
raise Exception("Order canceled. Ran out of cash ?")
def onBars(self, bars):
portfolioValue = self.getBroker().getEquity()
print "%s: Portfolio value: $%.2f" % (bars.getDateTime(), portfolioValue)
def main():
# Load the orders file.
ordersFile = OrdersFile("orders.csv")
print "First date", ordersFile.getFirstDate()
print "Last date", ordersFile.getLastDate()
print "Symbols", ordersFile.getInstruments()
# Load the data from QSTK storage. QS environment variable has to be defined.
feed = yahoofeed.Feed()
feed.setBarFilter(csvfeed.DateRangeFilter(ordersFile.getFirstDate(), ordersFile.getLastDate()))
feed.setDailyBarTime(datetime.time(0, 0, 0)) # This is to match the dates loaded with the ones in the orders file.
for symbol in ordersFile.getInstruments():
feed.addBarsFromCSV(symbol, os.path.join(os.getenv("QS"), "QSData", "Yahoo", symbol + ".csv"))
# Run the strategy.
cash = 1000000
useAdjustedClose = True
myStrategy = MyStrategy(feed, cash, ordersFile, useAdjustedClose)
# Attach returns and sharpe ratio analyzers.
retAnalyzer = returns.Returns()
myStrategy.attachAnalyzer(retAnalyzer)
sharpeRatioAnalyzer = sharpe.SharpeRatio()
myStrategy.attachAnalyzer(sharpeRatioAnalyzer)
myStrategy.run()
# Print the results.
print "Final portfolio value: $%.2f" % myStrategy.getResult()
print "Anual return: %.2f %%" % (retAnalyzer.getCumulativeReturns()[-1] * 100)
print "Average daily return: %.2f %%" % (stats.mean(retAnalyzer.getReturns()) * 100)
print "Std. dev. daily return: %.4f" % (stats.stddev(retAnalyzer.getReturns()))
print "Sharpe ratio: %.2f" % (sharpeRatioAnalyzer.getSharpeRatio(0, 252))
main()
The output for homework 3 looks like this:
First date 2011-01-10 00:00:00
Last date 2011-12-20 00:00:00
Symbols ['AAPL', 'IBM', 'GOOG', 'XOM']
2011-01-10 00:00:00: Portfolio value: $1000000.00
2011-01-11 00:00:00: Portfolio value: $998785.00
2011-01-12 00:00:00: Portfolio value: $1002940.00
2011-01-13 00:00:00: Portfolio value: $1004815.00
.
.
.
2011-12-15 00:00:00: Portfolio value: $1113532.00
2011-12-16 00:00:00: Portfolio value: $1116016.00
2011-12-19 00:00:00: Portfolio value: $1117444.00
2011-12-20 00:00:00: Portfolio value: $1133860.00
Final portfolio value: $1133860.00
Anual return: 13.39 %
Average daily return: 0.05 %
Std. dev. daily return: 0.0072
Sharpe ratio: 1.21