Monday, June 3, 2013

Platform for Back Testing

We have changed our back testing program to be more efficient and easier to follow.  In the process we caught some semantic errors that have been corrected; these corrections changed our data and we are working on an update to reflect the changes.   Our data collector 'poorBoysData' has also been changed to collect data in reverse chronological order, they were previously sorted chronologically.

We suspect there will be one or two more updates in the future; the functionality of this program is essentially completed and all that needs to be done are cosmetic changes. 

Code:


Language: Python 2.7
Third party packages: NumPy and matplotlib
theBackTest: http://snk.to/f-ct9e788p
The zipped file contains:

  • theBackTest.py
  • poorBoysData.py
  • An empty data folder called 'Tickers' 
  • A text file called 'SP500.txt'
  • A text file 'tBT Descriptions.txt' which contains descriptions of all our variables.

  The previous downloads have also been changed.

New features:


1.  An easier method for calculating buy and sell signals.
2.  A portfolio function where we can specify an initial investment, trading fees, and
     correction for slippage.
3.  A plotting option where we can display the returns of our simulated universe, the
     middle x% of the universe, and the returns of the S&P 500.


Buy and Sell Changes:


Buy signals are calculated through the function ‘buySignal’ whose input is a list of dictionaries that contain open, high, low, close, and volume data for each day up to and including the current day.  For example the first few entries for GE’s buySignal on 2013-04-26 are:

[[  {'Date': '2013-04-26', 'Open':  21.98, 'High': 22.40,
     'Low':  21.97,  'Close'  22.21, 'Volume':  47012500}  ], 
[  {'Date': '2013-04-25', 'Open':  22.21, 'High': 22.23,
     'Low':  21.91,  'Close'  21.95, 'Volume':  41462900}  ], 
[  {'Date': '2013-04-24', 'Open':  21.69, 'High': 22.03,
      'Low':  21.65,  'Close'  21.96, 'Volume':  51496600}  ]]
From here we can calculate our buy signals through the use of built in functions ‘sMA,’ ‘histLow’, and ‘histHigh.’ If our buy signal is triggered the function must return the buy price otherwise return False.

Let's use ‘theBullsSupplier.py’ for an example:

def buySignal(histData):
    # Target price > 200 day MA
    lowoverLongMA = histData[0][‘Low’] > sMA(histData[1:], longMA)

    # Target price > 50 day MA

    lowoverShortMA = histData[0][‘Low’] > sMA(histData[1:], shortMA)
    # Target price sets new low

    newLow = histData[0][‘Low’] <  histLow(histData[1:], highlowPeriods)
    # Our target price is the historical 10 day low
    targetPrice = histLow(histData[1:], highlowPeriods)
    # If the target price is higher than the current day’s open then our signal would 
    # trigger below our 
target price and become the current day’s open
    if targetPrice > histData[0][‘Open’]:
        targetPrice = histData[0][‘Open’]
    # if lowoverLongMA, lowoverShortMA, and newLow evaluate to True our sell 
    # signal is triggered and 
our function returns targetPrice.  Otherwise our 
    # function returns False.

    if lowoverLongMA and lowoverShortMA and newLow:
        return
 targetPrice

    else:
        return False

Our signals are the Boolean lowoverLongMA, lowoverShortMA, and newLow with a target buyPrice of the historical 10 day low.  If the current day’s open is below our target buy price then buyPrice will be changed to the current day's open.  If all the signals evaluate to True our buySignal function will return buyPrice and start calculating sell signals, otherwise it will return false.

The process for creating a sell signal is the exact same - return sell price if signals evaluate to True otherwise return False. 

Portfolio Function:


When we cycle through our sequence of trades we send each one to our ‘portfolio’ function.  This function will take in our bank – the portfolio value prior to the trade, subtract commission, subtract the cost basis, add the market value at time of sell, and subtract commission.   We calculate the return of our portfolio by dividing our bank by our initial investment.

Our buy and sell price is adjusted for slippage by multiplying our target price by a random number between (1 + [-slippage, slippage]).  If slippage was .005 our purchase price would fall between [99.5%, 100.5%] of our target price.

Plotting:


We can now plot!  In order to do so we must set 'plot' equal to True.  Setting plotPopulation to True will draw a scatter plot of all portfolio values at the end of each trade for every trial conducted; plotMiddle will draw a scatter plot of the middle x% of portfolio values; and  plotSP500 draws a line of returns for the S&P 500 over the duration of our analysis.

It should be noted that our program's run time increases with the amount of data.  Plotting 20,000 trials between 2007-01-01 and 2012-12-31 will take more than a fair amount of time.  We can bypass the run time issue by setting 'plot' to False.  This function will undergo major changes in the future.

3 comments:

  1. Hello there, and great job on this project, really interested on how it may turn out. Also, would you be able to post a detailed guide on how to run this? Thanks,
    DarkKunai

    ReplyDelete
    Replies
    1. Hi,

      Thanks for the interest in the site, I'll begin working on a detailed guide and get it posed as soon as I can. I'll shoot for Sunday.

      Delete
    2. A guide has been published.

      Delete