Inspired in QSTK (http://wiki.quantsoftware.org/index.php?title=QSTK_Tutorial_9), the eventprofiler module is a tool to analyze, statistically, how events affect future equity prices. The event profiler scans over historical data for a specified event and then calculates the impact of that event on the equity prices in the past and the future over a certain lookback period.
The goal of this tool is to help you quickly validate an idea, before moving forward with the backtesting process.
Bases: object
Results from the profiler.
Returns the number of events occurred. Events that are on the boundary are skipped.
Bases: object
Base class for event identification. You should subclass this to implement the event identification logic.
Override (mandatory) to determine if an event took place in the last bar (bards[-1]).
Parameters: |
|
---|---|
Return type: | boolean. |
Bases: object
This class is responsible for scanning over historical data and analyzing returns before and after the events.
Parameters: |
---|
Runs the analysis using the bars supplied by the feed.
Parameters: |
|
---|
Plots the result of the analysis.
Parameters: | profilerResults (Results.) – The result of the analysis |
---|
The following example is inspired on the ‘Buy-on-Gap Model’ from Ernie Chan’s book: ‘Algorithmic Trading: Winning Strategies and Their Rationale’:
- The idea is to select a stock near the market open whose returns from their previous day’s lows to today’s open are lower that one standard deviation. The standard deviation is computed using the daily close-to-close returns of the last 90 days. These are the stocks that “gapped down”.
- This is narrowed down by requiring the open price to be higher than the 20-day moving average of the closing price.
from pyalgotrade import eventprofiler
from pyalgotrade.technical import stats
from pyalgotrade.technical import roc
from pyalgotrade.technical import ma
from pyalgotrade.tools import yahoofinance
# Event inspired on an example from Ernie Chan's book:
# 'Algorithmic Trading: Winning Strategies and Their Rationale'
class BuyOnGap(eventprofiler.Predicate):
def __init__(self, feed):
stdDevPeriod = 90
smaPeriod = 20
self.__returns = {}
self.__stdDev = {}
self.__ma = {}
for instrument in feed.getRegisteredInstruments():
priceDS = feed[instrument].getAdjCloseDataSeries()
# Returns over the adjusted close values.
self.__returns[instrument] = roc.RateOfChange(priceDS, 1)
# StdDev over those returns.
self.__stdDev[instrument] = stats.StdDev(self.__returns[instrument], stdDevPeriod)
# MA over the adjusted close values.
self.__ma[instrument] = ma.SMA(priceDS, smaPeriod)
def __gappedDown(self, instrument, bards):
ret = False
if self.__stdDev[instrument][-1] is not None:
prevBar = bards[-2]
currBar = bards[-1]
low2OpenRet = (currBar.getOpen(True) - prevBar.getLow(True)) / float(prevBar.getLow(True))
if low2OpenRet < (self.__returns[instrument][-1] - self.__stdDev[instrument][-1]):
ret = True
return ret
def __aboveSMA(self, instrument, bards):
ret = False
if self.__ma[instrument][-1] is not None and bards[-1].getOpen(True) > self.__ma[instrument][-1]:
ret = True
return ret
def eventOccurred(self, instrument, bards):
ret = False
if self.__gappedDown(instrument, bards) and self.__aboveSMA(instrument, bards):
ret = True
return ret
def main(plot):
instruments = ["AA", "AES", "AIG"]
feed = yahoofinance.build_feed(instruments, 2008, 2009, ".")
predicate = BuyOnGap(feed)
eventProfiler = eventprofiler.Profiler(predicate, 5, 5)
eventProfiler.run(feed, True)
results = eventProfiler.getResults()
print "%d events found" % (results.getEventCount())
if plot:
eventprofiler.plot(results)
if __name__ == "__main__":
main(True)
The code is doing 4 things:
- Declaring a Predicate that implements the ‘Buy-on-Gap Model’ event identification.
- Loading bars for some stocks.
- Running the analysis.
- Plotting the results.
This is what the output should look like:
2013-09-20 23:30:45,340 yahoofinance [INFO] Creating data directory
2013-09-20 23:30:45,341 yahoofinance [INFO] Downloading AA 2008 to data/AA-2008-yahoofinance.csv
2013-09-20 23:30:46,092 yahoofinance [INFO] Downloading AES 2008 to data/AES-2008-yahoofinance.csv
2013-09-20 23:30:46,683 yahoofinance [INFO] Downloading AIG 2008 to data/AIG-2008-yahoofinance.csv
2013-09-20 23:30:47,260 yahoofinance [INFO] Downloading AA 2009 to data/AA-2009-yahoofinance.csv
2013-09-20 23:30:48,019 yahoofinance [INFO] Downloading AES 2009 to data/AES-2009-yahoofinance.csv
2013-09-20 23:30:48,761 yahoofinance [INFO] Downloading AIG 2009 to data/AIG-2009-yahoofinance.csv
14 events found
Note that Cummulative returns are normalized to the time of the event.