Event Study — The Announcement Impact of Seasoned Equity Offerings on Stock Returns

Use python and TEJ database to execute event study

Photo Creds: Unsplash


Seasoned equity offerings is a common financing option for listed firms, and the purpose of it includes expansion of capital expenditures, retirement of debts and improvement of financial structure. However, previous literature has implied that this borrowing behavior tends to send negative signals to the market, leading to stock prices plummeting at the date of announcement.

Event study is a statistical method that analyzes the impact of important corporate events(M&A, SEO, stock buyback…) or economic shocks(regulation change, policy, macroeconomic conditions…) on firms’ value. Basically, event study consists of the following steps: event date confirmation, definition of estimation window and event window, calculation of abnormal return and statistical test. Therefore, this week, we will verify whether this negative announcement effect also happens in the Taiwan stock market by adopting the TEJ API database and event study approach !

The Editing Environment and Modules Required

We use Windows OS and Jupyter Notebook in this article

import tejapi
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from scipy import stats
tejapi.ApiConfig.api_key = 'Your Key'
tejapi.ApiConfig.ignoretz = True

Note: sklearn.linear_model is used for regression;scipy is for statistical test

The Highlights of the Article

  • Obtain common stocks issuance events
  • Execute event study

Database Used

Issuance of Common Stocks for TSE-Listed Firms

Step 1. Get the codes of TSE-listed firms, then save in list tse_stocks

security = tejapi.get('TWN/ANPRCSTD',
mkt = 'TSE',
stypenm = '普通股',
opts = {'columns':['coid','mdate','stypenm','mkt']},
paginate = True,
chinese_column_name = True)
tse_stocks = security['證券碼'].tolist()

Step 2. Obtain the events of listed firms

events = tejapi.get('TWN/ASTK1',
x_mt_date = {'gte':'2019-01-01', 'lte':'2021-08-01'},
opts = {'columns':['coid','cash','x_mt_date']},
paginate = True,
chinese_column_name = True)

This article will treat the date of resolution of shareholders’ meeting as event day. The event day falls between January 2019 ~ August 2020

cash = events[events['現金增資(仟股)']>0].reset_index(drop=True)

We only need issuance of common stock for cash, instead of earnings or capital surplus transferred to common stock

Step 3. Select TSE-listed firms’ events

tse_cash = cash[cash['公司'].isin(tse_stocks)].reset_index(drop=True)

Combined with TSE-listed firms’ code tse_stocks and isin(),we finally obtain issuance of common stock for cash event only for TSE-listed firms tse_cash

Event Study — Data Sorting

Photo Creds: University of Victoria

Estimation window(T0~T1): -260~-10 periods is set. The actual returns in this period will be regressed on Fama & French factor-based portfolio return, which yields the coefficient estimates that will be used to calculate expected return within event window

Event day (0): the date of resolution of shareholders’ meeting, since it’s the earliest signal for SEO sent to market

Event window(T2~T3): -5 ~ +5 periods. The difference between actual return and expected return predicted by Fama & French model is so-called abnormal return

Because we include 140 events of common stocks issuance, each loop is used to cope with each event, and the output will be stored in variable final . We also exclude some events that lack data or belong to initial public offerings. In the following section, we select some important parts of codes within the loop to interpret and take the first event ( stock = ‘1314’, date = ‘2019–05–24’ ) as an example to show what’s going on in each loop. Other parts of codes can be viewed in source code

  • Obtain adequate returns
return_set = tejapi.get('TWN/APRCD',
coid = stock,
mdate = {'gte': date + pd.Timedelta(days =
-450), 'lte': date + pd.Timedelta(days = 25)},
opts = {'columns' : ['coid', 'mdate','roi']},
paginate = True,
chinese_column_name = True)

Each event has a unique combination of firm code stock and event date date , which are used to obtain return around event day. Here we choose the returns of 450 days before the event date and 25 days after the event date to make sure we’ll have complete return in estimation window(251 trading days) and event window(11 trading days)

  • Split off the return of estimation window and event window respectively
event_index = return_set[return_set['年月日'] == date].index.values.astype(int)[0]

First of all, the event date’s index should be used as a basis to split two windows

estimate_window = return_set[event_index - 260 - 1: event_index - 10].reset_index(drop=True)
event_window = return_set[event_index - 5: event_index + 5 + 1].reset_index(drop=True)
  • Find the corresponding Fama & French factor-based return
estimate_start = estimate_window.loc[0, '年月日']
event_end = event_window.loc[5*2, '年月日']

For starters, we need to find the beginning date of the estimation window and the last date of the event window. Then based on the two dates, we directly obtain the daily portfolio return of market risk premium, size premium, book-to-market premium, profitability and investment factorsY9999 means the above returns are based on TSE-listed firms and belong to simple return

fama_french = tejapi.get('TWN/AFACTO1D',
coid = 'Y9999',
mdate = {'gte':estimate_start, 'lte': event_end},
opts = {'columns': ['coid',
paginate = True,
chinese_column_name = True)
  • Estimate the coefficient of factors
ols_data = estimate_window.merge(fama_french, on = '年月日')
x = ols_data.loc[:,['市場風險溢酬', '規模溢酬(5因子)','淨值市價比溢酬','盈利能力因子','投資因子']].values
y = ols_data['報酬率%'].values.reshape(-1,1)
model = LinearRegression()

After combining estimation return and Fama-French portfolio return, we convert them into two-dimensional array variables which are required in a linear model. Finally, put dependent variable and independent variable in the model

  • Calculate abnormal return
predict_data = event_window.merge(fama_french, on = '年月日')    
event_x = predict_data.loc[:,['市場風險溢酬','規模溢酬(5因子)','淨值市價比溢酬','盈利能力因子','投資因子']].values

Here we combine the event window return with Fama & French portfolio return, and store the factor-based portfolio returns to be independent variables to get the expected return by putting them in fitted model model.predict() . The next step is to calculate the abnormal returns, cumulative returns and add one more columns to indicate the relative day

event_window['預期報酬率'] = model.predict(event_x)
event_window['異常報酬率'] = event_window['報酬率%'] - event_window['預期報酬率']
event_window['累計異常報酬率'] = event_window['異常報酬率'].cumsum()
event_window['相對天數'] = [i for i in range(-5, 5 + 1)]

Each loop will keep repeating the above steps and the output will be added in final table, as the following shown

Event Study — Visualization and Statistical Tests

  • Calculate the average abnormal returns and cumulative abnormal returns
sorted_data = final.groupby(by = '相對天數').mean().reset_index()
  • Visualization
plt.plot(sorted_data['相對天數'], sorted_data['異常報酬率'], label = 'Average Abnormal Retrun')
plt.plot(sorted_data['相對天數'], sorted_data['累計異常報酬率'], label = 'Cumulative Abnormal Return')
plt.xlabel('Event Day')
plt.title('Event Study')
plt.xticks(np.arange(-5, 5+1 , 1))

As you can see, there’s apparently negative abnormal return one or two days after the event day. However, the abnormal return reverses back around zero afterwards, which imply the market might already digest the information

  • Statistical test
ttest = pd.DataFrame()
for day in range(-5,5+1):
sample = final[final['相對天數'] == day]['異常報酬率'].values
t, p_value = stats.ttest_1samp(sample, 0)
if p_value <= 0.01:
significance = '***'
elif 0.01 < p_value <= 0.05:
significance = '**'
elif 0.05 < p_value <= 0.1:
significance = '*'
significance = ''
ttest = ttest.append(pd.DataFrame(np.array([day,t,p_value, significance]).reshape((1,4)), columns = ['相對天數','T檢定值', 'P-value','顯著水準'],)).reset_index(drop=True)ttest = ttest.set_index('相對天數')

We use stats.ttest_lsamp() to carry out T-tests to examine whether the daily abnormal return is significantly different from zero. We also add one more significance star column based on p-value

Therefore, we can prove that the announcement of SEO does significantly impact firms’ value. The reason for not impacting the return at the event date may result from firms usually declaring important issues after the stock market closes


After today’s introduction, we believe readers have more understanding of event study! Actually still lots of assumptions we proposed in this article can be adjusted based on previous literature or event characteristics, such as estimation and event window or the methods to calculate the abnormal return. To execute event study more efficiently, we highly recommend TEJ API databases as we use in this article given its quality and variety without wasting time on data crawling and cleaning. If readers are interested in observing other events’ impact on firms’ value, welcome to the TEJ E Shop to purchase the data that satisfy your need!

Related Link