EnglishSvenska

Algorithmic trading with Python

I have been experimenting with algorithmic trading for a couple of weeks. Zipline is a Python library for backtesting trading algorithms and I would like to share one of the algorithms I made.

import talib
from zipline.api import record, order_target, history, add_history
import dateutil
import logging
from zipline.utils.factory import load_from_yahoo
from zipline.finance.slippage import FixedSlippage
from zipline.algorithm import TradingAlgorithm
from zipline.finance import commission

logging.basicConfig(level=logging.DEBUG)


# initialize algorithm
def initialize(context):
    logging.debug('enter initialize')
    context.set_slippage(FixedSlippage())
    context.set_commission(commission.PerTrade(cost=5))

    context.LOW_RSI = initialize.low_RSI
    context.HIGH_RSI = initialize.high_RSI
    context.rsi_window = initialize.rsi_window
    add_history(context.rsi_window, '1d', 'price')
    context.i = 0
    context.invested = False

# default parameters for algorithm
initialize.rsi_window = 15
initialize.low_RSI = 30
initialize.high_RSI = 70


# Will be called on every trade event for the securities you specify.
def handle_data(context, data):
    logging.debug('enter handle_data')
    context.i += 1
    if context.i < context.rsi_window:
        return

    # get the last RSI value
    prices = history(context.rsi_window, '1d', 'price')
    sec_rsi = talib.RSI(
        prices[context.security].values,
        timeperiod=context.rsi_window - 1)

    # buy and sell flags
    buy = False
    sell = False

    if sec_rsi[-1] < context.LOW_RSI and not context.invested:
        # RSI under 30 indicates oversold, time to buy
        order_target(context.security, 1000)
        logging.debug('Buying {}'.format(context.security))
        context.invested = True
        buy = True

    elif sec_rsi[-1] > context.HIGH_RSI and context.invested:
        # RSI over 70 indicates overbought, sell everything
        order_target(context.security, 0)
        logging.debug('Selling {}'.format(context.security))
        context.invested = False
        sell = True

    # record data for each time increment
    record(secRSI=sec_rsi[-1],
           price=data[context.security].price,
           buy=buy,
           sell=sell)
    logging.info(context.portfolio.cash)


def run_algorithm(
        security='AAPL',
        start_date='20100101',
        end_date='20150101',
        initial_cash=100000,
        rsi_window=15,
        low_RSI=30,
        high_RSI=70):
    logging.debug('run_algorithm begin')
    # dates
    start = dateutil.parser.parse(start_date)
    end = dateutil.parser.parse(end_date)

    # get data from yahoo
    data = load_from_yahoo(stocks=[security], indexes={}, start=start, end=end)
    logging.debug('done loading from yahoo. {} {} {}'.format(
        security, start_date, end_date))

    # create and run algorithm
    algo = TradingAlgorithm(
        initialize=initialize,
        handle_data=handle_data,
        capital_base=initial_cash)
    algo.security = security
    initialize.low_RSI = low_RSI
    initialize.high_RSI = high_RSI
    initialize.rsi_window = rsi_window
    logging.debug('starting to run algo...')
    results = algo.run(data).dropna()
    logging.debug('done running algo')
    return results


if __name__ == '__main__':
    import matplotlib.pyplot as plt

    # run algorithm and get results
    results = run_algorithm(
        security='AAPL',
        start_date='20100101',
        end_date='20150101',
        initial_cash=100000,
        rsi_window=15,
        low_RSI=30,
        high_RSI=70)

    # get s&p500 and nasdaq indexes
    index_data = load_from_yahoo(
        stocks=['^gspc', '^ixic'],
        indexes={},
        start=results.index[0],
        end=results.index[-1])

    # portfolio value, stock holdings and S&P 500 index
    fig = plt.figure(figsize=(12, 6))
    ax11 = fig.add_subplot(311)
    ax12, ax13 = ax11.twinx(), ax11.twinx()
    ax13.spines['right'].set_position(('axes', 1.07))
    ax11.set_ylabel('portfolio value', color='blue')
    ax12.set_ylabel('holdings', color='green')
    ax13.set_ylabel('S&P 500', color='red')

    # portfolio value
    ax11.plot(results.index, results.portfolio_value, color='blue')

    # holdings (number of stocks owned)
    holdings = [0 if t == [] else t[0]['amount'] for t in results.positions]
    ax12.plot(results.index, holdings, color='green')
    ax12.set_ylim([min(holdings) - 30, max(holdings) + 30])

    # index
    ax13.plot(index_data.index, index_data['^gspc'], color='red')

    # algo visualization
    ax21 = fig.add_subplot(312)
    ax21.set_ylabel('stock price', color='blue')
    ax22 = ax21.twinx()
    ax22.set_ylabel('rsi', color='red')

    # stock
    ax21.plot(results.index, results.price, color='blue')

    # add sell and buy flags on top of stock price
    ax21.plot(
        results.ix[results.buy].index,
        results.price[results.buy],
        '^',
        markersize=10,
        color='green')
    ax21.plot(
        results.ix[results.sell].index,
        results.price[results.sell],
        'v',
        markersize=10,
        color='red')

    # rsi value
    ax22.plot(results.index, results.secRSI, color='red')
    # add lines to show under- and over value indicator
    ax22.plot([results.index[0], results.index[-1]], [30, 30], 'k-')
    ax22.plot([results.index[0], results.index[-1]], [70, 70], 'k-')

    # portfolio value, stock value and index in percentage
    ax31 = fig.add_subplot(313)
    ax32, ax33 = ax31.twinx(), ax31.twinx()  # share x for other plots
    ax31.set_ylabel('algo %', color='blue')
    ax32.set_ylabel('snp index %', color='green')
    ax33.set_ylabel('stock %', color='red')
    ax33.spines['right'].set_position(('axes', 1.07))

    # portfolio value
    ax31.plot(
        results.index,
        results.portfolio_value / results.portfolio_value[0] * 100 - 100,
        color='blue')

    # index
    ax32.plot(
        index_data.index,
        index_data['^gspc'] / index_data['^gspc'][0] * 100 - 100,
        color='green')

    # stock value
    ax33.plot(
        results.index,
        results.price /
        results.price[0] * 100 - 100,
        color='red')

    plt.show()

If you get it working you should see a plot similar to this one:
Skärmavbild 2015-04-04 kl. 22.20.20

If you are observant, it is easy to see that the performance of this algorithm is not good enough to be used on a real portfolio, and it is more of a test.

Links:

Tagged with: ,