Skip to content

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")
Text(0, 0.5, '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))
[<matplotlib.lines.Line2D at 0x7f05b2c2f1c0>]

parameter bounds and precisions

bounds = [[0, 20, 20],[150, 40, 40]]
precisions = [1, 0.25, 0.25]
bounds
[[0, 20, 20], [150, 40, 40]]

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,
)

***
Number of free params:       3.
Explorable param space size: 990711.
***

Selecting 8 processes for the parallel evaluation of the model

Calibration

params, losses = cal.calibrate(10)

BATCH NUMBER:   1
PARAMS SAMPLED: 0

METHOD: HaltonSampler
----> sim exec elapsed time: 0.3s
---->   min loss new params: 48.81
---->   avg loss new params: 93.88
----> avg loss exist params: 93.88
---->         curr min loss: 48.81198552405123
====>    total elapsed time: 0.3s

METHOD: RandomForestSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 46.24
---->   avg loss new params: 66.12
----> avg loss exist params: 80.0
---->         curr min loss: 46.23645638238496
====>    total elapsed time: 2.1s

METHOD: BestBatchSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 41.37
---->   avg loss new params: 59.29
----> avg loss exist params: 73.1
---->         curr min loss: 41.374024300280325
====>    total elapsed time: 0.0s

BATCH NUMBER:   2
PARAMS SAMPLED: 48

METHOD: HaltonSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 59.83
---->   avg loss new params: 100.14
----> avg loss exist params: 79.86
---->         curr min loss: 41.374024300280325
====>    total elapsed time: 0.0s

METHOD: RandomForestSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 26.62
---->   avg loss new params: 63.31
----> avg loss exist params: 76.55
---->         curr min loss: 26.615971460763685
====>    total elapsed time: 2.0s

METHOD: BestBatchSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 20.26
---->   avg loss new params: 45.86
----> avg loss exist params: 71.43
---->         curr min loss: 20.25857835091562
====>    total elapsed time: 0.0s

BATCH NUMBER:   3
PARAMS SAMPLED: 96

METHOD: HaltonSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 64.43
---->   avg loss new params: 97.26
----> avg loss exist params: 75.12
---->         curr min loss: 20.25857835091562
====>    total elapsed time: 0.0s

METHOD: RandomForestSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 21.18
---->   avg loss new params: 43.8
----> avg loss exist params: 71.21
---->         curr min loss: 20.25857835091562
====>    total elapsed time: 2.0s

METHOD: BestBatchSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 19.47
---->   avg loss new params: 30.07
----> avg loss exist params: 66.64
---->         curr min loss: 19.468179801927736
====>    total elapsed time: 0.0s

BATCH NUMBER:   4
PARAMS SAMPLED: 144

METHOD: HaltonSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 25.85
---->   avg loss new params: 89.51
----> avg loss exist params: 68.92
---->         curr min loss: 19.468179801927736
====>    total elapsed time: 0.0s

METHOD: RandomForestSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 21.5
---->   avg loss new params: 30.01
----> avg loss exist params: 65.39
---->         curr min loss: 19.468179801927736
====>    total elapsed time: 2.0s

METHOD: BestBatchSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 23.76
---->   avg loss new params: 29.4
----> avg loss exist params: 62.39
---->         curr min loss: 19.468179801927736
====>    total elapsed time: 0.0s

BATCH NUMBER:   5
PARAMS SAMPLED: 192

METHOD: HaltonSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 48.76
---->   avg loss new params: 95.72
----> avg loss exist params: 64.95
---->         curr min loss: 19.468179801927736
====>    total elapsed time: 0.0s

METHOD: RandomForestSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 19.4
---->   avg loss new params: 30.32
----> avg loss exist params: 62.48
---->         curr min loss: 19.40128801910293
====>    total elapsed time: 2.0s

METHOD: BestBatchSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 20.73
---->   avg loss new params: 30.09
----> avg loss exist params: 60.32
---->         curr min loss: 19.40128801910293
====>    total elapsed time: 0.0s

BATCH NUMBER:   6
PARAMS SAMPLED: 240

METHOD: HaltonSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 44.43
---->   avg loss new params: 93.83
----> avg loss exist params: 62.41
---->         curr min loss: 19.40128801910293
====>    total elapsed time: 0.0s

METHOD: RandomForestSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 20.85
---->   avg loss new params: 26.51
----> avg loss exist params: 60.3
---->         curr min loss: 19.40128801910293
====>    total elapsed time: 2.0s

METHOD: BestBatchSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 22.49
---->   avg loss new params: 27.91
----> avg loss exist params: 58.5
---->         curr min loss: 19.40128801910293
====>    total elapsed time: 0.0s

BATCH NUMBER:   7
PARAMS SAMPLED: 288

METHOD: HaltonSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 57.21
---->   avg loss new params: 96.94
----> avg loss exist params: 60.52
---->         curr min loss: 19.40128801910293
====>    total elapsed time: 0.0s

METHOD: RandomForestSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 21.6
---->   avg loss new params: 29.33
----> avg loss exist params: 58.96
---->         curr min loss: 19.40128801910293
====>    total elapsed time: 2.0s

METHOD: BestBatchSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 21.7
---->   avg loss new params: 29.8
----> avg loss exist params: 57.58
---->         curr min loss: 19.40128801910293
====>    total elapsed time: 0.0s

BATCH NUMBER:   8
PARAMS SAMPLED: 336

METHOD: HaltonSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 62.8
---->   avg loss new params: 97.94
----> avg loss exist params: 59.41
---->         curr min loss: 19.40128801910293
====>    total elapsed time: 0.0s

METHOD: RandomForestSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 24.04
---->   avg loss new params: 31.56
----> avg loss exist params: 58.2
---->         curr min loss: 19.40128801910293
====>    total elapsed time: 2.1s

METHOD: BestBatchSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 18.78
---->   avg loss new params: 27.02
----> avg loss exist params: 56.9
---->         curr min loss: 18.777912631604902
====>    total elapsed time: 0.1s

BATCH NUMBER:   9
PARAMS SAMPLED: 384

METHOD: HaltonSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 49.95
---->   avg loss new params: 90.04
----> avg loss exist params: 58.23
---->         curr min loss: 18.777912631604902
====>    total elapsed time: 0.0s

METHOD: RandomForestSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 20.55
---->   avg loss new params: 30.55
----> avg loss exist params: 57.16
---->         curr min loss: 18.777912631604902
====>    total elapsed time: 2.1s

METHOD: BestBatchSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 20.85
---->   avg loss new params: 29.97
----> avg loss exist params: 56.15
---->         curr min loss: 18.777912631604902
====>    total elapsed time: 0.1s

BATCH NUMBER:   10
PARAMS SAMPLED: 432

METHOD: HaltonSampler
----> sim exec elapsed time: 0.0s
---->   min loss new params: 33.91
---->   avg loss new params: 89.94
----> avg loss exist params: 57.36
---->         curr min loss: 18.777912631604902
====>    total elapsed time: 0.0s

METHOD: RandomForestSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 23.68
---->   avg loss new params: 35.37
----> avg loss exist params: 56.6
---->         curr min loss: 18.777912631604902
====>    total elapsed time: 2.1s

METHOD: BestBatchSampler
Warning: Repeated samples still found after 5 duplication passes. This is probably due to a small search space.
----> sim exec elapsed time: 0.0s
---->   min loss new params: 18.78
---->   avg loss new params: 27.49
----> avg loss exist params: 55.63
---->         curr min loss: 18.777912631604902
====>    total elapsed time: 0.1s

# best parameters obtained so far
params[0]
array([64., 24., 35.])

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()
<matplotlib.legend.Legend at 0x7f05d0a0eaf0>
# 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()
<matplotlib.legend.Legend at 0x7f05b2c8dd30>