Building an Alphalens Event Study for Price Threshold Crossings
Summary
This example adapts Alphalens return analysis to study a discrete stock event rather than rank a cross-section of securities. It defines an event when a stock’s opening price crosses below a specified dollar threshold after being at or above it the prior day. The event table contains values only for qualifying date and asset pairs, while all other observations are omitted or missing. Positive event values represent a long-side study; negative values can be used for a short-side study.
The tutorial emphasizes aligning the pricing data so that entry uses the next available price after the event is observed, and subsequent prices determine forward returns. It warns that event detection must not use those entry prices, to avoid lookahead bias. It recommends disabling outlier filtering and using a single bin, with long-short demeaning disabled for ordinary event signals. It demonstrates several forward horizons and includes plotted outputs, but the provided text does not describe their results. The example is limited to its historical large-cap universe, threshold, and chosen dates; it does not establish that the event is profitable or robust.
Key ideas
- An event study can use Alphalens by providing signal values only for securities and dates when an event occurs.
- The example marks a downward crossing of a price threshold using current and prior opening prices.
- Forward-return prices should begin after event detection so the event is not evaluated with lookahead information.
- Positive and negative event values distinguish long and short analyses, while dollar-neutral demeaning is generally inappropriate for this setup.
- The example reports results through plots but does not establish profitability or out-of-sample robustness.
Tags
Full text
# Alphalens: event study
# Alphalens: event study
While Alphalens is a tool designed to evaluate a cross-sectional signal which can be used to rank many securities each day, we can still make use of Alphalens returns analysis functions, a subset of Alphalens, to create a meaningful event study.
An event study is a statistical method to assess the impact of a particular event on the value of a stock. In this example we will evalute what happens to stocks whose price fall below 30$
```python
%pylab inline --no-import-all
import alphalens
import pandas as pd
import numpy as np
import datetime
```
```python
import warnings
warnings.filterwarnings('ignore')
```
Below is a simple mapping of tickers to sectors for a universe of 500 large cap stocks.
```python
tickers = [ 'ACN', 'ATVI', 'ADBE', 'AMD', 'AKAM', 'ADS', 'GOOGL', 'GOOG', 'APH', 'ADI', 'ANSS', 'AAPL',
'AVGO', 'CA', 'CDNS', 'CSCO', 'CTXS', 'CTSH', 'GLW', 'CSRA', 'DXC', 'EBAY', 'EA', 'FFIV', 'FB',
'FLIR', 'IT', 'GPN', 'HRS', 'HPE', 'HPQ', 'INTC', 'IBM', 'INTU', 'JNPR', 'KLAC', 'LRCX', 'MA', 'MCHP',
'MSFT', 'MSI', 'NTAP', 'NFLX', 'NVDA', 'ORCL', 'PAYX', 'PYPL', 'QRVO', 'QCOM', 'RHT', 'CRM', 'STX',
'AMG', 'AFL', 'ALL', 'AXP', 'AIG', 'AMP', 'AON', 'AJG', 'AIZ', 'BAC', 'BK', 'BBT', 'BRK.B', 'BLK', 'HRB',
'BHF', 'COF', 'CBOE', 'SCHW', 'CB', 'CINF', 'C', 'CFG', 'CME', 'CMA', 'DFS', 'ETFC', 'RE', 'FITB', 'BEN',
'GS', 'HIG', 'HBAN', 'ICE', 'IVZ', 'JPM', 'KEY', 'LUK', 'LNC', 'L', 'MTB', 'MMC', 'MET', 'MCO', 'MS',
'NDAQ', 'NAVI', 'NTRS', 'PBCT', 'PNC', 'PFG', 'PGR', 'PRU', 'RJF', 'RF', 'SPGI', 'STT', 'STI', 'SYF', 'TROW',
'ABT', 'ABBV', 'AET', 'A', 'ALXN', 'ALGN', 'AGN', 'ABC', 'AMGN', 'ANTM', 'BCR', 'BAX', 'BDX', 'BIIB', 'BSX',
'BMY', 'CAH', 'CELG', 'CNC', 'CERN', 'CI', 'COO', 'DHR', 'DVA', 'XRAY', 'EW', 'EVHC', 'ESRX', 'GILD', 'HCA',
'HSIC', 'HOLX', 'HUM', 'IDXX', 'ILMN', 'INCY', 'ISRG', 'IQV', 'JNJ', 'LH', 'LLY', 'MCK', 'MDT', 'MRK', 'MTD',
'MYL', 'PDCO', 'PKI', 'PRGO', 'PFE', 'DGX', 'REGN', 'RMD', 'SYK', 'TMO', 'UNH', 'UHS', 'VAR', 'VRTX', 'WAT',
'MMM', 'AYI', 'ALK', 'ALLE', 'AAL', 'AME', 'AOS', 'ARNC', 'BA', 'CHRW', 'CAT', 'CTAS', 'CSX', 'CMI', 'DE',
'DAL', 'DOV', 'ETN', 'EMR', 'EFX', 'EXPD', 'FAST', 'FDX', 'FLS', 'FLR', 'FTV', 'FBHS', 'GD', 'GE', 'GWW',
'HON', 'INFO', 'ITW', 'IR', 'JEC', 'JBHT', 'JCI', 'KSU', 'LLL', 'LMT', 'MAS', 'NLSN', 'NSC', 'NOC', 'PCAR',
'PH', 'PNR', 'PWR', 'RTN', 'RSG', 'RHI', 'ROK', 'COL', 'ROP', 'LUV', 'SRCL', 'TXT', 'TDG', 'UNP', 'UAL',
'AES', 'LNT', 'AEE', 'AEP', 'AWK', 'CNP', 'CMS', 'ED', 'D', 'DTE', 'DUK', 'EIX', 'ETR', 'ES', 'EXC']
```
Load the prices.
```python
import pandas_datareader.data as web
pan = web.DataReader(tickers, "google", datetime.datetime(2015, 6, 1), datetime.datetime(2017, 1, 1))
```
```python
pan = pan.transpose(2,1,0)
```
Now it's time to build the events DataFrame, the input will give to Alphalens.
Alphalens calculates statistics for those dates where the input DataFrame has values (not NaN). So to compute the performace analysis on specific dates and securities (like an event study) then we have to make sure the input DataFrame contains valid values only on those date/security combinations where the event happens. All the other values in the DataFrame must be NaN or not present.
Also, make sure the event values are positive (it doesn't matter the value but they must be positive) if you intend to go long on the events and use negative values if you intent to go short. This impacts the cumulative returns plots.
Let's create the event DataFrame where we "mark" (any value) each day a security price fall below 30$.
```python
today_price = pan.loc[:,:,'Open']
yesterday_price = today_price.shift(1)
events = today_price[ (today_price < 30.0) & (yesterday_price >= 30) ]
events = events.stack()
events.index = events.index.set_names(['date', 'asset'])
events = events.astype(float)
events
```
The pricing data passed to alphalens should contain the entry price for the assets so it must reflect the next available price after an event was observed at a given timestamp. Those prices must not be used in the calculation of the events for that time. Always double check to ensure you are not introducing lookahead bias to your study.
The pricing data must also contain the exit price for the assets, for period 1 the price at the next timestamp will be used, for period 2 the price after 2 timestats will be used and so on.
While Alphalens is time frequency agnostic, in our example we build 'pricing' DataFrame so that for each event timestamp it contains the assets open price for the next day afer the event is detected, this price will be used as the assets entry price. Also, we are not adding additional prices so the assets exit price will be the following days open prices (how many days depends on 'periods' argument).
```python
pricing = pan.loc[:,:,'Open'].iloc[1:]
```
# Run Event Style Returns Analysis
Before running Alphalens beware of some important options:
```python
# we don't want any filtering to be done
filter_zscore = None
```
```python
# We want to have only one bin/quantile. So we can either use quantiles=1 or bins=1
quantiles = None
bins = 1
# Beware that in pandas versions below 0.20.0 there were few bugs in panda.qcut and pandas.cut
# that resulted in ValueError exception to be thrown when identical values were present in the
# dataframe and 1 quantile/bin was selected.
# As a workaroung use the bins custom range option that include all your values. E.g.
quantiles = None
bins = [-1000000,1000000]
```
```python
# You don't have to directly set 'long_short' option when running alphalens.tears.create_event_study_tear_sheet
# But in case you are making use of other Alphalens functions make sure to set 'long_short=False'
# if you set 'long_short=True' Alphalens will perform forward return demeaning and that makes sense only
# in a dollar neutral portfolio. With an event style signal you cannot usually create a dollar neutral
# long/short portfolio
long_short = False
```
```python
factor_data = alphalens.utils.get_clean_factor_and_forward_returns(events,
pricing,
quantiles=None,
bins=1,
periods=(1, 2, 3, 4, 5, 6, 10),
filter_zscore=None)
```
```python
alphalens.tears.create_event_study_tear_sheet(factor_data, pricing, avgretplot=(5, 10))
```
### If we wanted to analyze the performance of short signal, we only had to switch from positive to negative event values
```python
events = -events
```
```python
factor_data = alphalens.utils.get_clean_factor_and_forward_returns(events,
pricing,
quantiles=None,
bins=1,
periods=(1, 2, 3, 4, 5, 6, 10),
filter_zscore=None)
```
```python
alphalens.tears.create_event_study_tear_sheet(factor_data, pricing, avgretplot=(5, 10))
```





Shown in full with attribution under the source's licence. Licence: Apache-2.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.