rxquant

23
16 7 20 30 9 15 8 15 7 4 15 10 8 S w K RxQuant Functional and Reactive programming Mathematics meets Coding Filippo Perugini Applied Mathematics MSc K G

Upload: filippo-perugini

Post on 31-Jul-2015

44 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: RxQuant

16

7

20

30

9

15

8

15

7

4

15

10

8

S

w

K

RxQuantFunctional and Reactive programming

Mathematics meets Coding

Filippo Perugini Applied Mathematics MScK

G

Page 2: RxQuant

PRESENTATION summary

¬I

INTRODUCTION • Scope and Motivation

(II

MATHEMATICS • Financial Markets • Stochastic Calculus • Numerical Mathematic

GIV

RUNNING CODE • Demonstration

ÜIII

CODE • Structure • Operation

Page 3: RxQuant

Mathematical Models

• Systems of equations describing the evolution of phenomena !

• Good approximation of how things works in reality

¬[

I

• Models needs to be implemented to be actually used

!• Let’s find a nice way to do it

Ü

FUNCTIONAL and

REACTIVE programming

Page 4: RxQuant

Random Nature of Prices!Stock prices evolve apparently without a specific direction (or sense). We need to capture this feature. !Simple Random Walk!Can model a drunk man trying to get home after to much beer ( this is actually used in the industry )

Financial MarketsWhat is a good model?

Page 5: RxQuant

General Equation!!!!Different Processes!By specifying the abstract “methods” a() and b() we obtain different processes:!

Stochastic ProcessesDescribe the evolution in time of systems affected by uncertainty

Geometric Brownian Motion

dXt = µXtdt +σ XtdWtdXt = k(θ − Xt )dt +σ Xt dWt

C.I.R. (Cox, Ingersoll, Ross)

Heston Model Stochastic Volatility

dXt = µXtdt + vt XtdWt

dvt = k(θ − vt )dt +σ vt dWt

StructuredXt = a(Xt ,t)dt +b(Xt ,t)dWt

Page 6: RxQuant

Numerical MathematicsDiscretises the processes

The previous processes are in continuous time. Computers understand discrete (step by step) procedures.

• Numerical Mathematics provides algorithms to implement models. A discretisation scheme tells how to move to the next step:

!

Xt → Xt+1

type Scheme = ( StochasticProcess, Time, Time, Double ) => Try[Double]

Page 7: RxQuant

The ChallengeWe want a code that:

Reactive

Incorporates dynamic nature of the

processes and of the relations between

them

Functional

Reflects the mathematical

structure of the models

( Ñ

Page 8: RxQuant

Visualisation

!

Geometric Brownian!

Motion

Extensions

C.I.R.Y

Code Structure

HESTON

Y

Milstein

Q.E.

Euler

Discretisation5

Evolutiono

StochasticProcesses

w

S

f

Page 9: RxQuant

Stochastic ProcessesOk but… Show me the code!

dXt = a(Xt ,t)dt +b(Xt ,t)dWt 1 abstract class StochasticProcess{ 2 3 // current value of the process 4 var x_t : Try[Double] 5 6 // drift a(t,x(t)) 7 def drift(t: Time, x: Try[Double]): Try[Double] 8 9 // diffusion b(t,x(t)) 10 def sigma(t: Time, x: Try[Double]): Try[Double] 11 12 // discretization used to make the process evolve 13 def discretization: Scheme 14 15 // returns x(t) + dx(t) --> uses scheme discretization 16 def evolve (t: Time, dt: Time, dw: Double): Try[Double] = discretization.apply(this, t, dt, dw) 17 18 }

Page 10: RxQuant

Geometric Brownian MotionOk but… Show me the code!

dXt = µXtdt +σ XtdWt 1 class GeometricBrownian(mu: Double, sigma: Double, initialValue: Try[Double], scheme: Scheme) extends StochasticProcess { 2 3 // current value of the process 4 var x_t : Try[Double] = initialValue 5 6 // drift mu(t,x(t)) 7 def drift(t: Time, x: Try[Double]): Try[Double] = Success(mu * x.get) 8 9 // diffusion sigma(t,x(t)) 10 def sigma(t: Time, x: Try[Double]): Try[Double] = Success(sigma * x.get) 11 12 // discretization used to make the process evolve 13 def discretization = scheme 14 15 // returns x(t) + dx(t) --> uses scheme discretization 16 override def evolve (t: Time, dt: Time, dw: Double): Try[Double] = discretization.apply(this, t, dt, dw) 17 }

Page 11: RxQuant

C.I.R. (Cox, Ingersoll, Ross)dXt = k(θ − Xt )dt +σ Xt dWt

1 class CIR ( k: Double, thet: Double, sig: Double, initialValue: Try[Double], scheme: Scheme ) extends StochasticProcess { 2 3 // current value of the process 4 var x_t: Try[Double]= initialValue 5 6 var kappa: Double = k 7 8 var theta: Double = thet 9 10 var sigma: Double = sig 11 12 // drift mu(t,x(t)) 13 def drift(t: Time, x: Try[Double]): Try[Double] = Success( k * (thet - x.get) ) 14 15 // diffusion sigma(t,x(t)) 16 def sigma(t: Time, x: Try[Double]): Try[Double] = Success( sig * math.sqrt(x.get) ) 17 18 // discretization used to make the process evolve 19 def discretization = scheme 20 21 // returns x(t) + dx(t) --> uses scheme discretization 22 override def evolve(t: Time, dt: Time, dw: Double): Try[Double] = discretization.apply(this, t, dt, dw) 23 }

Page 12: RxQuant

Heston Model Stochastic Volatility

dXt = µXtdt + vt XtdWt

dvt = k(θ − vt )dt +σ vt dWt{

1 class Heston( m: Double, rh: Double, k: Double, thet: Double, sig: Double, varia: (Double, Double), initialValue: Try[Double], scheme: Scheme ) extends StochasticProcess { 3 4 // current value of the process 5 var x_t : Try[Double] = initialValue 6 7 var mu = m ; var kappa: Double = k ; var theta: Double = thet ; var sigm: Double = sig; var rho = rh 8 9 var variance = varia // ( V(t-1), V(t) ) : previous and current value of the variance 10 11 // drift mu(t,x(t)) 12 def drift(t: Time, x: Try[Double]): Try[Double] = Success(mu * x.get) 13 14 // diffusion sigma(t,x(t)) 15 def sigma(t: Time, x: Try[Double]): Try[Double] = 16 for { 17 x <- x 18 variaCurrent = variance._2 19 } yield math.sqrt(variaCurrent) * x 20 21 // discretization used to make the process evolve 22 def discretization = scheme 23 24 // returns x(t) + dx(t) --> uses scheme discretization 25 override def evolve (t: Time, dt: Time, dw: Double): Try[Double] = discretization.apply(this, t, dt, dw) 26 }

Page 13: RxQuant

Euler Discretisation

1 def euler(process: StochasticProcess, t: Time, dt: Time, dw: Double): Try[Double] = 2 for { 3 drift <- process.drift(t,process.x_t) 4 sigma <- process.sigma(t,process.x_t) 5 } yield process.x_t.get + drift * dt + sigma * dw

“and it's all wrapped in the monad, you're happy and life is good”

Yi → Xi+1

m a → (a → m b) → m b

Page 14: RxQuant

Rx: go Reactive• Evolution class: set of method that

takes a static Stochastic Process and makes it evolve from the initial to the final state

b

a

PROBLEM !!• The discretisation method provides just the next step

• We need the full evolution up to final time T

• We want to capture the dynamic nature of the process

Xi+1

StochasticProcess

Observable[Double]

Page 15: RxQuant

ReactiveEvolution.reactiveRun

1 def reactiveRun(process: StochasticProcess, t0: Time , T: Time, dt: Time ): Observable[Double] = { ! 2 val N = T/dt 3 4 Observable[Double](subscriber => { // LAMBDA expression 5 for (i <- 1 to N.toInt) { 6 process.x_t = process.evolve(t0 + dt, dt, math.sqrt(dt) * Random.nextGaussian()) 7 process.x_t match { 8 case Success(v) => subscriber.onNext(v) 9 case Failure(e) => subscriber.onError(e) 10 } 11 } 12 subscriber.onCompleted() 13 }) 14 }

For any Stochastic Process

Page 16: RxQuant

EvolutionEston.runHeston 1 def runHeston(processT: StochasticProcess, t0: Time , T: Time, dt: Time ): Observable[ (Double, Double) ] ={ 2 val process = processT.asInstanceOf[Heston] 3 val N = (T/dt).toInt 4 5 val volatility = Volatility.volatility(process.kappa, process.theta, process.sigm, Success(process.variance._1), Discretization.varianceQuadraticExponential, t0, T, N) 6 7 Observable[ (Double,Double) ]( subscriber => { 8 9 volatility.subscribe( v => { 10 process.variance = v 11 process.x_t = process.evolve(t0 + dt, dt, math.sqrt(dt) * Random.nextGaussian()) 12 process.x_t match { 13 case Success(h) => subscriber.onNext( (v._2, h) ) 14 case Failure(e) => subscriber.onError(e) 15 } }) })

1 def volatility(kappa: Double, theta: Double, sigma: Double, v0: Try[Double], discretization: Scheme, t0: Time, T: Time, N: Int): Observable[(Double, Double)] = { 2 3 val dt = (T - t0) / N 4 val ceikit = new CIR(kappa, theta, sigma, v0, discretization) 5 val last = v0.get +: reactiveRun(ceikit, t0, T, dt) 6 7 last.zip(last.tail) 8 }

Page 17: RxQuant

Moving Average• Basic tool: widely used in the industry

f

a

Observable[Double]

Observable[Double]

Technical Indicators!• Metrics derived from the values of a stochastic process (stock price)

• “Predict” future values or determine trend

• Dynamic transformation of a process (a function applied to )Xi+1

Page 18: RxQuant

Arithmetic Moving AverageSimple stuff, isn’t it ?

Functional vs ImperativeIn the next slide, try to guess which code is Functional

and which Imperative !

→MAt =Xt + Xt−1 + ...+ Xt−n+1

nMAt = MAt−1 + (Xt − Xt−n ) / n

Page 19: RxQuant

1 def arithmeticMA(n: Int): Observable[Double] = { 2 3 var movAvg: Double = 0 4 var value: Queue[Double] = Queue() 5 var i = 0 6 7 Observable[Double](subscriber => { 8 9 series.subscribe(v => { 10 i = i + 1 11 if (i < n) { 12 movAvg = movAvg + v 13 value.enqueue(v) 14 subscriber.onNext(v) } 15 else { 16 if (i == n ) { 17 movAvg = movAvg + v 18 movAvg = movAvg / n 19 value.enqueue(v) // current value updated 20 value.dequeue() // removing the queue head 21 subscriber.onNext(movAvg) 22 } 23 else { 24 if (i > n) { 25 movAvg = movAvg + (v - value.dequeue) / n 26 value.enqueue(v) // current series value updated 27 subscriber.onNext(movAvg) //sending value to sub. 28 } } } }) }) }

implicit class TechnicalIndicator(series: Observable[Double]) {

1 def arithmeticMA_Functional (bufferSize: Int): Observable[Double] = { 2 series 3 .slidingBuffer(bufferSize, 1) 4 .scan(-1.0)( (prevMovAvg, b) => prevMovAvg match { 5 case -1 => b.foldRight(0.0){ _ + _ }/ bufferSize 6 case _ => prevMovAvg + (b.last - b.head) / bufferSize 7 } ) 8 .drop(1) // because scan return also the seed (-1) 9 }

Use of High Order Functions with Lambda Expression :

dramatic improvement •clarity •code length (-70%)

Page 20: RxQuant

Exponential Moving AverageHere it’s even more!

ExpMAt ,Xt (α ) = (1−α ) ⋅Xt +α ⋅ExpMAt−1 1 def exponentialMA(alpha: Double): Observable[Double] = { 2 var movAvg: Double = 0 3 var i = 0 4 Observable[Double](subscriber => { 5 series.subscribe(v => { 6 i = i + 1 7 if (i == 1) { movAvg = v; subscriber.onNext(v) } 8 else { movAvg = (1 - alpha) * v + alpha * movAvg 9 subscriber.onNext(movAvg)} 10 }) 11 }) 12 }

1 def exponentialMA_Functional (alpha: Double): Observable[Double] = { 2 series . scan ( (movAvg, v) => (1 - alpha) * v + alpha * movAvg ) 3 }

Page 21: RxQuant

How to show things?!• We want to show the processes we have been talking about

• In a nice and dynamic way

Reactive! JavaFX

Q

Page 22: RxQuant

Reactive Java FXReactive Plotting

1 def heston(): Observable[(Double,Double)] = { 2 val t0: Time = 0 // initial time 3 val N = 1000 // number of time-steps 4 val T: Time = 5 // maturity 5 val dt = (T - t0) / N // time-step length 6 val S0: Double = 10 // initial value of the stock 7 val v0: (Double, Double) = (0.044 ,0.044) 8 val ceikit = new Heston(0.03, - 0.6288, 14.829, 0.04, 0.7, v0, Success(S0), Discretization.stockQE) 9 10 (v0._2 , S0) +: EvolutionHeston.runHeston(ceikit, t0, T, dt) 11 } 12 13 val result: Observable[ (Double, Double) ] = heston().publish 14 val index = Observable.interval(50 milliseconds).onBackpressureBuffer 15 val movingAverage3 = result.map(v => v._2).exponentialMA(0.90) 16 val movingAverage4 = result.map(v => v._2).exponentialMA_Functional(0.98) 17 18 chart.observeOn(FXScheduler()).subscribe(v =>{ 19 20 series1.getData.add(new XYChart.Data(v._1 , math.sqrt(v._2._1)) ) 21 series2.getData.add(new XYChart.Data(v._1 , v._2._2 )) 22 series3.getData.add(new XYChart.Data(v._1 , v._3 ) ) 23 series4.getData.add(new XYChart.Data(v._1 , v._4 ) ) 24 } ) 25 result.connect

Page 23: RxQuant

Happy Hacking !

YOUTHANKfor your attention