Fitting a simple shock model to the stock price of "Slack Technologies"
Here we will fit a very simple "shock model" to the stock price of Slack Technologies from the 27th of august 2020 to the 31st of march 2021.
We will try to capture the shock induces by the spearing of rumors on the 25th of november 2020 that Salesforce was interested in buying Slack. More info can be found here https://www.cnbc.com/2020/11/25/slack-shares-jump-following-report-of-possible-salesforce-acquisition.html.
# import standard libraries
import numpy as np
import matplotlib.pyplot as plt
slack_shock_data = np.atleast_2d(np.loadtxt("data/slack_shock.txt")).T
plt.plot(slack_shock_data)
plt.xlabel("days from 27-8-2020")
plt.ylabel("Slack stock price")
Model
# a simple model of a simple step function with three parameters
def step_func(theta, N, seed=None):
# [tau, d1, d2]
e = np.zeros(N)
tau = int(theta[0]) # day of the sudden change in evaluation
d1, d2 = theta[1], theta[2] # initial and final stock prices
e[0:tau] = d1
e[tau:] = d2
return np.atleast_2d(e).T
plt.plot(step_func([20, 0, 1], 100))
parameter bounds and precisions
bounds = [[0, 20, 20],[150, 40, 40]]
precisions = [1, 0.25, 0.25]
bounds
samplers
from black_it.samplers.halton import HaltonSampler
from black_it.samplers.random_forest import RandomForestSampler
from black_it.samplers.best_batch import BestBatchSampler
hs = HaltonSampler(batch_size=16)
rf = RandomForestSampler(batch_size=16)
bb = BestBatchSampler(batch_size=16)
samplers = [hs, rf, bb]
loss
# use a quadratic loss
from black_it.loss_functions.minkowski import MinkowskiLoss
loss = MinkowskiLoss()
calibrator
from black_it.calibrator import Calibrator
cal = Calibrator(
samplers=samplers,
loss_function=loss,
model=step_func,
parameters_bounds=bounds,
parameters_precision=precisions,
ensemble_size=1,
convergence_precision=None,
verbose=True,
saving_folder=None,
real_data=slack_shock_data,
random_state=1,
)
Calibration
params, losses = cal.calibrate(10)
# best parameters obtained so far
params[0]
plots
# index of mimumum loss
idxmin = np.argmin(cal.losses_samp)
param_min = cal.params_samp[idxmin]
# convergence
losses_per_batch = [
cal.losses_samp[cal.batch_num_samp == i]
for i in range(int(max(cal.batch_num_samp)) + 1)
]
mins_per_batch = np.array([np.min(l) for l in losses_per_batch])
cummin_per_batch = [
np.min(mins_per_batch[: i + 1]) for i in range(mins_per_batch.shape[0])
]
plt.figure()
plt.plot(mins_per_batch, "-o", label="batch minimum")
plt.plot(cummin_per_batch, "-o", label="cumulative minimum")
plt.ylabel("loss")
plt.xlabel("batch number")
plt.legend()
# agreement between real and simulated time series
plt.plot(slack_shock_data[:, 0], "-", label="real series")
plt.ylabel(
"Slack stock price",
)
plt.xlabel("days from 27-8-2020")
plt.plot(cal.series_samp[idxmin, 0, :, 0].T, ls="--", label="fitted model")
plt.legend()