In [2]:
%pylab inline
import datetime
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from pandas.io.data import DataReader
from backtest import Strategy, Portfolio

class MovingAverageCrossStrategy(Strategy):
    def __init__(self, symbol, bars, short_window=100, long_window=400):
        self.symbol = symbol
        self.bars = bars
        self.short_window = short_window
        self.long_window = long_window

    def generate_signals(self):
        """Returns the DataFrame of symbols containing the signals
        to go long, short or hold (1, -1 or 0)."""
        signals = pd.DataFrame(index=self.bars.index)
        signals['signal'] = 0.0
        # Create the set of short and long simple moving averages over the
        # respective periods
        signals['short_mavg'] = pd.rolling_mean(bars['Close'], self.short_window, min_periods=1)
        signals['long_mavg'] = pd.rolling_mean(bars['Close'], self.long_window, min_periods=1)
        # Create a 'signal' (invested or not invested) when the short moving average crosses the long
        # moving average, but only for the period greater than the shortest moving average window
        signals['signal'][self.short_window:] = np.where(signals['short_mavg'][self.short_window:]
            > signals['long_mavg'][self.short_window:], 1.0, 0.0)
        # Take the difference of the signals in order to generate actual trading orders
        signals['positions'] = signals['signal'].diff()
       
        return signals
class MarketOnClosePortfolio(Portfolio):
    def __init__(self, symbol, bars, signals, initial_capital=100000.0):
        self.symbol = symbol
        self.bars = bars
        self.signals = signals
        self.initial_capital = float(initial_capital)
        self.positions = self.generate_positions()

    def generate_positions(self):
        positions = pd.DataFrame(index=signals.index).fillna(0.0)
        positions[self.symbol] = 100*signals['signal']   # This strategy buys 100 shares
        return positions

    def backtest_portfolio(self):
        portfolio = self.positions*self.bars['Close']
        pos_diff = self.positions.diff()

        portfolio['holdings'] = (self.positions*self.bars['Close']).sum(axis=1)
        portfolio['cash'] = self.initial_capital - (pos_diff*self.bars['Close']).sum(axis=1).cumsum()

        portfolio['total'] = portfolio['cash'] + portfolio['holdings']
        portfolio['returns'] = portfolio['total'].pct_change()
        return portfolio
if __name__ == "__main__":
    # Obtain daily bars of AAPL from Yahoo Finance for the period
    # 1st Jan 1990 to 1st Jan 2002 - This is an example from ZipLine
    symbol = 'AAPL'
    bars = DataReader(symbol, "yahoo", datetime.datetime(2013,1,1), datetime.datetime(2015,1,1))

    # Create a Moving Average Cross Strategy instance with a short moving
    # average window of 100 days and a long window of 400 days
    mac = MovingAverageCrossStrategy(symbol, bars, short_window=100, long_window=400)
    signals = mac.generate_signals()

    # Create a portfolio of AAPL, with $100,000 initial capital
    portfolio = MarketOnClosePortfolio(symbol, bars, signals, initial_capital=100000.0)
    returns = portfolio.backtest_portfolio()

    # Plot two charts to assess trades and equity curve
    fig = plt.figure()
    fig.patch.set_facecolor('white')     # Set the outer colour to white
    ax1 = fig.add_subplot(211,  ylabel='Price in $')

    # Plot the AAPL closing price overlaid with the moving averages
    bars['Close'].plot(ax=ax1, color='r', lw=2.)
    signals[['short_mavg', 'long_mavg']].plot(ax=ax1, lw=2.)

    # Plot the "buy" trades against AAPL
    ax1.plot(signals.ix[signals.positions == 1.0].index,
             signals.short_mavg[signals.positions == 1.0],
             '^', markersize=10, color='m')

    # Plot the "sell" trades against AAPL
    ax1.plot(signals.ix[signals.positions == -1.0].index,
             signals.short_mavg[signals.positions == -1.0],
             'v', markersize=10, color='k')

    # Plot the equity curve in dollars
    ax2 = fig.add_subplot(212, ylabel='Portfolio value in $')
    returns['total'].plot(ax=ax2, lw=2.)

    # Plot the "buy" and "sell" trades against the equity curve
    ax2.plot(returns.ix[signals.positions == 1.0].index,
             returns.total[signals.positions == 1.0],
             '^', markersize=10, color='m')
    ax2.plot(returns.ix[signals.positions == -1.0].index,
             returns.total[signals.positions == -1.0],
             'v', markersize=10, color='k')

    # Plot the figure
    fig.show()
    print(returns)


Populating the interactive namespace from numpy and matplotlib
            signal  short_mavg   long_mavg  positions
Date                                                 
2013-01-02       0  549.030000  549.030000        NaN
2013-01-03       0  545.565000  545.565000          0
2013-01-04       0  539.376667  539.376667          0
2013-01-07       0  535.507500  535.507500          0
2013-01-08       0  533.468000  533.468000          0
2013-01-09       0  530.740000  530.740000          0
2013-01-10       0  529.707143  529.707143          0
2013-01-11       0  528.531250  528.531250          0
2013-01-14       0  525.555556  525.555556          0
2013-01-15       0  521.592000  521.592000          0
2013-01-16       0  520.182727  520.182727          0
2013-01-17       0  518.724167  518.724167          0
2013-01-18       0  517.283846  517.283846          0
2013-01-22       0  516.390000  516.390000          0
2013-01-23       0  516.231333  516.231333          0
2013-01-24       0  512.123125  512.123125          0
2013-01-25       0  507.873529  507.873529          0
2013-01-28       0  504.648889  504.648889          0
2013-01-29       0  502.207895  502.207895          0
2013-01-30       0  499.939000  499.939000          0
2013-01-31       0  497.822381  497.822381          0
2013-02-01       0  495.813182  495.813182          0
2013-02-04       0  493.487391  493.487391          0
2013-02-05       0  492.002083  492.002083          0
2013-02-06       0  490.616000  490.616000          0
2013-02-07       0  489.754615  489.754615          0
2013-02-08       0  489.207407  489.207407          0
2013-02-11       0  488.876071  488.876071          0
2013-02-12       0  488.152759  488.152759          0
2013-02-13       0  487.448000  487.448000          0
...            ...         ...         ...        ...
2014-11-18       0  100.452900  389.885425          0
2014-11-19       0  100.670300  389.175425          0
2014-11-20       0  100.898200  388.450875          0
2014-11-21       0  101.128100  387.728400          0
2014-11-24       0  101.374100  387.004025          0
2014-11-25       0  101.590400  386.255025          0
2014-11-26       0  101.826900  385.477225          0
2014-11-28       0  102.062300  384.667600          0
2014-12-01       0  102.262600  383.857050          0
2014-12-02       0  102.456700  383.029825          0
2014-12-03       0  102.651500  382.194700          0
2014-12-04       0  102.853200  381.331650          0
2014-12-05       0  103.055400  380.472500          0
2014-12-08       0  103.248500  379.593900          0
2014-12-09       0  103.445400  378.737275          0
2014-12-10       0  103.625500  377.884725          0
2014-12-11       0  103.794500  377.026925          0
2014-12-12       0  103.919900  376.191600          0
2014-12-15       0  104.031900  375.390050          0
2014-12-16       0  104.122700  374.570475          0
2014-12-17       0  104.226600  373.760850          0
2014-12-18       0  104.369300  372.935150          0
2014-12-19       0  104.505600  372.115450          0
2014-12-22       0  104.679000  371.294425          0
2014-12-23       0  104.843100  370.470425          0
2014-12-24       0  105.007300  369.637575          0
2014-12-26       0  105.196000  368.818950          0
2014-12-29       0  105.385500  367.991350          0
2014-12-30       0  105.565900  367.143700          0
2014-12-31       0  105.722300  366.295325          0

[504 rows x 4 columns]
            AAPL  holdings    cash   total  returns
Date                                               
2013-01-02     0         0     NaN     NaN      NaN
2013-01-03     0         0  100000  100000      NaN
2013-01-04     0         0  100000  100000        0
2013-01-07     0         0  100000  100000        0
2013-01-08     0         0  100000  100000        0
2013-01-09     0         0  100000  100000        0
2013-01-10     0         0  100000  100000        0
2013-01-11     0         0  100000  100000        0
2013-01-14     0         0  100000  100000        0
2013-01-15     0         0  100000  100000        0
2013-01-16     0         0  100000  100000        0
2013-01-17     0         0  100000  100000        0
2013-01-18     0         0  100000  100000        0
2013-01-22     0         0  100000  100000        0
2013-01-23     0         0  100000  100000        0
2013-01-24     0         0  100000  100000        0
2013-01-25     0         0  100000  100000        0
2013-01-28     0         0  100000  100000        0
2013-01-29     0         0  100000  100000        0
2013-01-30     0         0  100000  100000        0
2013-01-31     0         0  100000  100000        0
2013-02-01     0         0  100000  100000        0
2013-02-04     0         0  100000  100000        0
2013-02-05     0         0  100000  100000        0
2013-02-06     0         0  100000  100000        0
2013-02-07     0         0  100000  100000        0
2013-02-08     0         0  100000  100000        0
2013-02-11     0         0  100000  100000        0
2013-02-12     0         0  100000  100000        0
2013-02-13     0         0  100000  100000        0
...          ...       ...     ...     ...      ...
2014-11-18     0         0   60392   60392        0
2014-11-19     0         0   60392   60392        0
2014-11-20     0         0   60392   60392        0
2014-11-21     0         0   60392   60392        0
2014-11-24     0         0   60392   60392        0
2014-11-25     0         0   60392   60392        0
2014-11-26     0         0   60392   60392        0
2014-11-28     0         0   60392   60392        0
2014-12-01     0         0   60392   60392        0
2014-12-02     0         0   60392   60392        0
2014-12-03     0         0   60392   60392        0
2014-12-04     0         0   60392   60392        0
2014-12-05     0         0   60392   60392        0
2014-12-08     0         0   60392   60392        0
2014-12-09     0         0   60392   60392        0
2014-12-10     0         0   60392   60392        0
2014-12-11     0         0   60392   60392        0
2014-12-12     0         0   60392   60392        0
2014-12-15     0         0   60392   60392        0
2014-12-16     0         0   60392   60392        0
2014-12-17     0         0   60392   60392        0
2014-12-18     0         0   60392   60392        0
2014-12-19     0         0   60392   60392        0
2014-12-22     0         0   60392   60392        0
2014-12-23     0         0   60392   60392        0
2014-12-24     0         0   60392   60392        0
2014-12-26     0         0   60392   60392        0
2014-12-29     0         0   60392   60392        0
2014-12-30     0         0   60392   60392        0
2014-12-31     0         0   60392   60392        0

[504 rows x 5 columns]
C:\Anaconda\lib\site-packages\matplotlib\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure
  "matplotlib is currently using a non-GUI backend, "

In [ ]: