Computational Investing Part I

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.

Homework 1

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

Download the data with the following commands:

python -c "from pyalgotrade.tools import yahoofinance; yahoofinance.download_daily_bars('aeti', 2011, 'aeti-2011-yahoofinance.csv')"
python -c "from pyalgotrade.tools import yahoofinance; yahoofinance.download_daily_bars('egan', 2011, 'egan-2011-yahoofinance.csv')"
python -c "from pyalgotrade.tools import yahoofinance; yahoofinance.download_daily_bars('glng', 2011, 'glng-2011-yahoofinance.csv')"
python -c "from pyalgotrade.tools import yahoofinance; yahoofinance.download_daily_bars('simo', 2011, 'simo-2011-yahoofinance.csv')"

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.utils import stats


class MyStrategy(strategy.BacktestingStrategy):
    def __init__(self, feed):
        strategy.BacktestingStrategy.__init__(self, feed, 1000000)

        # We wan't to use adjusted close prices instead of close.
        self.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():
            self.marketOrder(instrument, quantity, onClose=True, allOrNone=True)

    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))

The results were:

Final portfolio value: $1604979.11
Anual return: 60.50 %
Average daily return: 0.20 %
Std. dev. daily return: 0.0136
Sharpe ratio: 2.30

Homework 3 and 4

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.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 is None:
                self.__firstDate = dateTime
            else:
                self.__firstDate = min(self.__firstDate, dateTime)

            if self.__lastDate is 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.BacktestingStrategy):
    def __init__(self, feed, cash, ordersFile, useAdjustedClose):
        # Suscribe to the feed bars event before the broker just to place the orders properly.
        feed.getNewValuesEvent().subscribe(self.__onBarsBeforeBroker)
        strategy.BacktestingStrategy.__init__(self, feed, cash)
        self.__ordersFile = ordersFile
        self.setUseAdjustedValues(useAdjustedClose)
        # We will allow buying more shares than cash allows.
        self.getBroker().setAllowNegativeCash(True)

    def __onBarsBeforeBroker(self, dateTime, bars):
        for instrument, action, quantity in self.__ordersFile.getOrders(dateTime):
            if action.lower() == "buy":
                self.marketOrder(instrument, quantity, onClose=True)
            else:
                self.marketOrder(instrument, quantity*-1, onClose=True)

    def onOrderUpdated(self, order):
        if order.isCanceled():
            raise Exception("Order canceled. Ran out of cash ?")

    def onBars(self, bars):
        portfolioValue = self.getBroker().getEquity()
        self.info("Portfolio value: $%.2f" % (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.
    if os.getenv("QS") is None:
        raise Exception("QS environment variable not 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))

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

Table Of Contents

Previous topic

TA-Lib integration

Next topic

Sample strategies

This Page