Skip to content

Latest commit

 

History

History
915 lines (696 loc) · 21.3 KB

Insurely.org

File metadata and controls

915 lines (696 loc) · 21.3 KB

Bayesian Change Point Detection

Introduction

Two Presentations for the Price of One

A Framework for Exotic Financial Derivatives

  • At the end of 2006 Barclays managed more than 35 templates, representing a total population of several thousand (exotic) trades.
  • The various downstream systems need to be able to process the new trade type.
  • Templates took months to release.

Change Point Detection

  • [2016-12-16 Fri], UK Chancellor tweets

Arrived in South Korea, a growing trade opportunity for the UK where exports have doubled over the last year. Now worth nearly £11bn.

  • But these days, UK Office of National Statistics makes this easy to verify.

Change Point Detection

Office for National Statistics (ONS)

Quarterly Trade Data

./diagrams/quarterly.png

Annual Trade Data

./diagrams/annual.png

Monthly Trade Data

./diagrams/monthly.png

Naive Model

Naive Stan I

data {
  int<lower=1> N;
  vector[N] x;
  vector[N] y;
}

parameters {
  real tau;
  real mu1;
  real mu2;
  real gamma1;
  real gamma2;

  real<lower=0> sigma1;
  real<lower=0> sigma2;
}

Naive Stan II

model {
  real mu;
  real gamma;
  real sigma;

  mu1 ~ normal(0, 10);
  mu2 ~ normal(0, 10);
  gamma1 ~ normal(0, 10);
  gamma2 ~ normal(0, 10);
  sigma1 ~ normal(0, 10);
  sigma2 ~ normal(0, 10);
  tau ~ uniform(0,N+1);

  for (i in 1:N) {
    mu = i < tau ? mu1 : mu2;
    gamma = i < tau ? gamma1 : gamma2;
    sigma = i < tau ? sigma1 : sigma2;
    y[i] ~ normal(mu * x[i] + gamma, sigma);
  }
}

Some Test Data

./diagrams/test-data.png

Inferred Change Point

./diagrams/naive-tau-hist.png

PyMC3

The Same in Python

chg_model = Model()

with chg_model:
  
  alpha1 = Normal('alpha1', mu=0, sd=10)
  alpha2 = Normal('alpha2', mu=0, sd=10)
  beta1  = Normal( 'beta1', mu=0, sd=10)
  beta2  = Normal( 'beta2', mu=0, sd=10)
  sigma1 = HalfNormal('sigma1', sd=10)
  sigma2 = HalfNormal('sigma2', sd=10)
  tau = Uniform('tau', lower=0, upper=len(w) + 1)
  
  alpha = switch(tau >= v, alpha1, alpha2)
  beta  = switch(tau >= v,  beta1,  beta2)
  sigma = switch(tau >= v, sigma1, sigma2)
  
  mu = alpha + beta * v
  
  Y_obs = Normal('Y_obs', mu=mu, sd=sigma, observed=w)

The Results

./diagrams/naive-py3.png

What Went Wrong?

  • Stan uses “burn-in” to initialise.
  • PyMC3 uses ADVI.
Variational inference (VI) is a scalable technique for approximate Bayesian inference. Automatic differentiation variational inference (ADVI) is a way of automating VI so that all that is needed is the model and the data.

Diagnostics for Stan

./diagrams/naive-R-diagnostics.png

Python Diagnostics ADVI

pd.DataFrame(list(start_advi.items()))
        0          1
0   beta1   1.307549
1  alpha2   2.251540
2  alpha1   3.327910
3  sigma2   8.354255
4   beta2   1.512960
5     tau  73.073964
6  sigma1   6.992683

Python Diagnostics MAP

pd.DataFrame(list(start_map.items()))
                0                   1
0           beta1  0.9680002398415648
1          alpha2  -37.86057522849939
2          alpha1  10.729059293077137
3  tau_interval__                 0.0
4           beta2  1.9750114311467755
5    sigma2_log__  0.7086888732834176
6    sigma1_log__  0.8616867832117518

Not Continuous

  • ADVI probably breaks because the posterior is not continuous
  • Idea: use sigmoid (soft step) rather than (hard) step function.

./diagrams/sigmoid.png

PyMC3 Second Attempt

with chg_cont_model:
    
    alpha1 = Normal('alpha1', mu=0, sd=10)
    alpha2 = Normal('alpha2', mu=0, sd=10)
    beta1  = Normal( 'beta1', mu=0, sd=10)
    beta2  = Normal( 'beta2', mu=0, sd=10)
    sigma1 = HalfNormal('sigma1', sd=10)
    sigma2 = HalfNormal('sigma2', sd=10)
    
    tau = Uniform('tau', lower=0, upper=len(w) + 1)
    
    weight = tt.nnet.sigmoid(2 * (v - tau))
    
    alpha = weight * alpha2 + (1 - weight) * alpha1
    beta = weight * beta2 + (1 - weight) * beta1
    sigma = weight * sigma2 + (1 - weight) * sigma1
    
    mu = alpha + beta * v
    
    Y_obs = Normal('Y_obs', mu=mu, sd=sigma, observed=w)

The Results

./diagrams/cont-py3.png

Stan Again

Stan Second Attempt I

functions {
  vector interp(vector w, vector wc, vector a) {
    return w * a[1] + wc * a[2];
  }
}

data {
  int<lower=1> N;
  vector[N] x;
  vector[N] y;
}

transformed data {
  vector[N] steps;
  for (n in 1:N) steps[n] = 2 * n;
}

parameters {
  real<lower=0, upper=N+1> tau;
  vector[2] mu;
  vector[2] gamma;
  vector<lower=0>[2] sigma;
}

Stan Second Attempt II

model {
  vector[N] w = inv_logit(steps - 2 * tau);
  vector[N] wc = 1 - w;

  y ~ normal(x .* interp(w, wc, mu) + interp(w, wc, gamma),
             interp(w, wc, sigma));

  mu ~ normal(0, 10);
  gamma ~ normal(0, 10);
  sigma ~ normal(0, 10);
}

Inferred Change Point

./diagrams/naive-tau-hist.png

The Promise

Four Variants

  • I promised four variants
  • But here are two more for free
  • Stan manual implies making time discrete and the marginalising it out
  • PyMC3 documentation also implies making time discrete but using Metropolis-Hastings for this variable rather than NUTS

Back to the Real World

Finally, Did UK / South Korea Change?

./diagrams/kr-cont-tau-hist.png

Where Precisely?

125447
1671051
226490
23088
233190

Fitting the Model

./diagrams/kr-fit.png

Framework for Exotic Derivatives

Background

What is an Option

An option or derivative is a contract giving the owner the right, but not the obligation, to buy (call) or sell (put) an underlying asset at a specified price (aka the strike), on or before a specified date.

Mathematically

$$ c = (x - k)^+ $$

$$ p = (k - x)^+ $$

In Haskell

call k x = max (x - k) 0
put k x = max (k - x) 0

Call Chart

./diagrams/call.png

Put Chart

./diagrams/put.png

Exotic

  • Baskets
    • An option on a portfolio of underlyings
  • Compound options
    • Options on other options, e.g. a call on a call
  • Path dependent options
    • Barrier options — payout locked-in when underlying hits trigger
    • Lookback options — payout based on highest or lowest price during the lookback period
    • Asian options–payout derived from average value of underlying over a specified window
    • Autocallables — will redeem early if a particular barrier condition is met
    • Knock-in put

Trade Lifecycle

  • Sales interact with the customers
  • Structurers create new products, often on customer request
  • Quants provide mathematical models and formal description of trades (payout functions)
  • Risk management validate and sign-off the payout functions
  • Traders derive the final price, manage the trade over its lifetime and analyse upcoming events
  • Payments systems handle payment events throughout the lifetime of the trade

The Framework

Functional Payout Framework

  • \cite{Jones_2000} \citeauthor{Jones_2000} \citetitle{Jones_2000}
  • Barclays 2006
  • A standardized representation for describing payoffs
  • A common suite of tools for trades which use this representation
    • Pricing via C / Monte Carlo
    • Mathematical / \LaTeX representation / Mathematica for risk management
    • Barrier analysis
    • Payments and other lifecycle events
    • Pricing via C / PDE

Functional Payout Framework

Specifying a Trade

  • Trade type is Haskell script
  • Trade parameters e.g. start date, strike, expiration date, barrier levels, etc
  • Fixings e.g. prices on Asian in

Backends

  • Pricing via MC or PDE
  • \LaTeX
  • Payments
  • Barriers
  • Mathematica

Some Examples

perf :: Date -> Date -> Asset -> Double
perf t1 t2 asset =
  observe asset t2 / observe asset t1 - 1

bestOf :: (List Asset, Date, Date) -> Double
bestOf (assets', startDate', endDate') =
  foldl1 max perfs where
    assets = name "Assets" assets'
    startDate = name "Starting date" startDate'
    endDate = name "End date" endDate'
    perfs = map (perf startDate endDate) assets

Some Examples

cliquet
  ( name "Asset" -> asset
  , name "Global floor" -> gf
  , name "Global cap" -> gc
  , name "Local floor" -> lf
  , name "Local cap" -> lc
  , name "Initial date" -> inDate
  , name "Dates" -> dates
  , name "Payment date" -> payDate
  )
  = max gf $ min gc $ sum perfs
  where
    cliquet d d' = (d', max lf $ min lc $ perf d d' asset)
    (_, perfs) = mapAccumL cliquet inDate dates

The \LaTeX

\begin{center} \small $$ \mathrm{pay}\Bigg(t{PD},min\Bigg({GC},max\Bigg({GF}, ∑i=1\mathrm{len(t^D)}min\Bigg({LC},\frac{STOP(t_i^D)}{STOP(ti-1^D)} - 1\Bigg) \Bigg) \Bigg)\Bigg) $$ \end{center}

\begin{center} \small \begin{tabular}{ l l l } \bf{Variable} & \bf{Description} & \bf{Type}
$TOP$ & Top-level input & Tuple of $(STOP, GF, GC, LF, LC, tID, t^D, tPD)$ \ \quad $STOP$ & Asset & Asset \ \quad $GC$ & Global floor & Double \ \quad $GF$ & Global cap & Double \ \quad $LC$ & Local floor & Double \ \quad $LF$ & Local cap & Double \ \quad $tID$ & Initial date & Date \ \quad $t^D$ & Dates & List of Date \ \quad $tPD$ & Payment date & Date \end{tabular} \end{center}

#

#