using EventStudies, TSFrames, DataFrames, Dates, MarketData
using CairoMakie

Stock splits

First, we'll load the stock split data from eventstudies.R.

stock_returns = EventStudies.load_data("StockPriceReturns.rda")
split_dates_df = EventStudies.load_data("SplitDates.rda")
other_returns = EventStudies.load_data("OtherReturns.rda")
720×4 TSFrame with Dates.Date Index
 Index       NiftyIndex       CallMoneyRate     SP500            USDINR
 Date        Float64?         Float64?          Float64?         Float64?
────────────────────────────────────────────────────────────────────────────
 2010-07-01       -1.15678    missing           missing           0.300978
 2010-07-02       -0.27268    missing                -1.34102     0.0
 2010-07-05       -0.0229161  missing           missing           0.407027
 2010-07-06        1.00999    missing           missing          -0.01069
 2010-07-07       -0.910725   missing                 0.0671392   0.533107
 2010-07-08        1.05809    missing                 3.08501    -0.347263
 2010-07-09        1.04421    missing                 0.936867   -0.410599
 2010-07-12        0.569144   missing           missing           0.0428709
     ⋮              ⋮                ⋮                 ⋮             ⋮
 2013-03-20  missing                0.00810168  missing          -0.312433
 2013-03-21  missing                0.00811214  missing           0.220647
 2013-03-22  missing                0.00793053  missing          -0.183842
 2013-03-25  missing                0.00813298  missing          -0.0920387
 2013-03-26  missing                0.00818972  missing           0.330962
 2013-03-27  missing          missing           missing          -0.0918373
 2013-03-28  missing                0.00841387  missing          -0.266753
                                                            705 rows omitted

No model

Let's try a regular event study, with no model:

eventtime_ts, event_return_codes = eventstudy(
    stock_returns, # returns TSFrame
    Symbol.(split_dates_df.name) .=> split_dates_df.when, # [:colname => event_time, ...]
    -6:7 # window - asymmetric to completely mimic R
    ) # note that we haven't provided a model, so it defaults to `nothing` (no-op).
(14×5 TSFrame with Int64 Index
 Index  HDFC.Bank  HDFC       ONGC       Tata.Motors  Tata.Power
 Int64  Float64?   Float64?   Float64?   Float64?     Float64?
─────────────────────────────────────────────────────────────────
    -6   0.182875  -1.39424    3.62834      1.79053     2.65584
    -5   0.778869  -2.42392   -0.118961    -0.165678    0.142118
    -4  -0.26351   -0.300476   0.562961     1.57929     1.14979
    -3  -1.37165    0.237117   0.942451     0.416966    0.220375
    -2  -1.73087   -0.800433  -0.312044     2.5547     -2.32828
    -1   1.42525    1.25307    0.298643    -3.26589     1.36306
     0   0.549044   3.0914    -5.74383     -4.22636    -1.81471
     1   0.6109     3.62009   -2.5154      -4.72033     3.83498
     2   1.05532   -0.685468  -0.364565     2.02027    -0.396826
     3  -0.702305  -1.74247    1.36032      5.85999     1.67574
     4  -1.56862   -0.558304   0.735891     6.78009    -2.5744
     5  -1.31113   -0.907892   1.12031     -0.216685   -2.69394
     6   1.02236    1.29106   -1.19187      2.90141    -0.206292
     7   0.735224  -0.832071  -0.610305    -0.846438    1.38428, EventStudies.EventStatus[EventStudies.DataMissing(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.Success(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.Success(), EventStudies.WrongSpan()  …  EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.Success(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.DataMissing(), EventStudies.Success(), EventStudies.Success()])

Now, let's perform bootstrap inference:

t0, lower, upper = EventStudies.inference(BootstrapInference(), eventtime_ts |> EventStudies.remap_cumsum)
([0.0, -0.3575148629418301, 0.1880957720707066, 0.27714742452122465, -0.24623724107390998, -0.03141143177055383, -1.660301978084302, -1.4942548850162929, -1.1685092865325686, 0.12174605270397265, 0.6846773161436914, -0.11718994326018972, 0.6461452838188286, 0.6122837568587869], [0.0, -1.506726002073397, -1.4427668290151807, -1.3863363773538318, -2.513148050657854, -1.3437587464359702, -3.612493387761333, -6.586713817372562, -5.07775529240563, -3.5130756688838893, -3.081870439362042, -3.0708410583829426, -3.738197403769643, -3.4077241990091345], [0.0, 0.4673977740634405, 1.2096207008857363, 1.678093652093331, 2.6828472511659918, 1.2078518093625057, 0.2579500612082697, 3.3663073907141263, 2.9709845951455223, 2.8878453741074317, 4.6923199716414565, 4.067936147179984, 5.81225247120455, 5.554618864263193])

and plot the results!

scatterlines(index(eventtime_ts), t0; label = "Mean")
lines!(index(eventtime_ts), upper; color = Makie.wong_colors(0.5)[1], linestyle = :dash, label = "95% CI")
lines!(index(eventtime_ts), lower; color = Makie.wong_colors(0.5)[1], linestyle = :dash)
# spruce up the figure
axislegend(Makie.current_axis(); position = :lt)
Makie.current_axis().xlabel = "Event time (days)"
Makie.current_axis().ylabel = "Return (%)"
Makie.current_axis().title = "Event study of stock splits"
Makie.current_axis().titlealign = :left
Makie.current_axis().subtitle = "In the Indian market, with no market model applied"
translate!(Makie.current_axis().scene.plots[1], 0, 0, 1)
Makie.current_figure()

Market model (NIFTY)

eventtime_ts, event_return_codes = eventstudy(
    stock_returns, # same as before
    Symbol.(split_dates_df.name) .=> split_dates_df.when, # same as before
    -6:7, # same as before
    MarketModel(other_returns[:, [:NiftyIndex]]) # ooh, what's this?
    )
(14×5 TSFrame with Int64 Index
 Index  HDFC.Bank  HDFC        ONGC        Tata.Motors  Tata.Power
 Int64  Float64    Float64     Float64     Float64      Float64
────────────────────────────────────────────────────────────────────
    -6   0.225854  -0.80165     3.81861      0.690046    2.62294
    -5  -1.16383   -1.45301     1.05671      0.420064    0.863938
    -4   0.885413  -0.24794     0.501271     0.262824   -0.113561
    -3  -0.641317  -0.729052   -0.0692522   -1.2425      0.378054
    -2  -0.157188   0.0103284   1.36897      1.75614     0.361421
    -1   0.255605   1.30565     0.411895    -0.783726    2.15257
     0   0.20872    1.37799    -4.6109      -1.17577    -1.32339
     1   0.875184   2.02536    -1.67066     -4.59387     2.16844
     2   1.23528   -0.499531    0.0971726    0.0125441  -0.00315845
     3  -1.631     -2.11913     0.433975     4.10823     0.871909
     4  -0.795657   0.354297   -0.917114     6.51367    -1.59143
     5  -0.920316   0.122166    0.938381     1.16485    -1.41924
     6  -0.746065   0.84182    -1.08392     -0.0517011   0.875767
     7  -0.180709   0.88173    -1.26        -0.696715    1.73189, EventStudies.EventStatus[EventStudies.ModelDataMissing(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.Success(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.Success(), EventStudies.WrongSpan()  …  EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.Success(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.WrongSpan(), EventStudies.ModelDataMissing(), EventStudies.Success(), EventStudies.Success()])

Now for the inference:

t0, lower, upper = EventStudies.inference(BootstrapInference(), eventtime_ts |> EventStudies.remap_cumsum)
([0.0, -0.05522637387771654, 0.20237504247193847, -0.2584376133455678, 0.40949695842266987, 1.0778949505152826, -0.0267745490975587, -0.26588460454727886, -0.09742413797151475, 0.23537286450527545, 0.9481255949593376, 0.9252929048053623, 0.8924728201203213, 0.9877120842924988], [0.0, -0.9627249142940759, -0.9396767129442709, -1.7183160990485633, -1.4278826779182983, -0.750118744459108, -1.049822782053468, -3.8276028982670427, -3.886589043346444, -1.7623287311970084, -2.2195231643581796, -1.9382108356031056, -2.4473268749472705, -3.063124807094376], [0.0, 0.9293814669388158, 1.2214418180167814, 1.007002165595523, 2.19323258084696, 2.847367322890443, 1.321690490307419, 3.202860512841476, 3.3481142600205573, 3.1604723372510106, 3.924512763642318, 3.9747765928190466, 4.636071272056952, 4.78119919485043])

and the plots!

scatterlines(index(eventtime_ts), t0; label = "Mean")
lines!(index(eventtime_ts), upper; color = Makie.wong_colors(0.5)[1], linestyle = :dash, label = "95% CI")
lines!(index(eventtime_ts), lower; color = Makie.wong_colors(0.5)[1], linestyle = :dash)
# spruce up the figure
axislegend(Makie.current_axis(); position = :lt)
Makie.current_axis().xlabel = "Event time (days)"
Makie.current_axis().ylabel = "Return (%)"
Makie.current_axis().title = "Event study of stock splits"
Makie.current_axis().titlealign = :left
Makie.current_axis().subtitle = "In the Indian market, with the NIFTY index applied as a market model"
translate!(Makie.current_axis().scene.plots[1], 0, 0, 1)
Makie.current_figure()

Note how this looks subtly different than the first plot, just because of the market model!

Intraday data

aggregate_returns = EventStudies.load_data("AggregateReturns.rda")
rate_cuts_df = EventStudies.load_data("RateCuts.rda")
index_returns = EventStudies.load_data("IndexReturns.rda")

intraday_eventtime_ts, event_return_codes = eventstudy(
    aggregate_returns,
    Symbol.(rate_cuts_df.name) .=> rate_cuts_df.when,
    -34:35,
    MarketModel(index_returns[:, [:x_1]])
    )

intraday_eventtime_ts.coredata[1, :] .= 0

t0, lower, upper = EventStudies.inference(BootstrapInference(), intraday_eventtime_ts |> EventStudies.remap_cumsum)

lines(t0)
lines!(lower)
line!(upper)
Makie.current_figure()

Something else


This page was generated using Literate.jl.