1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
# Copyright (C) 2016, 2018 EDF
# All Rights Reserved
# This code is published under the GNU Lesser General Public License (GNU LGPL)
import numpy as np
import math
import random
class AR1Simulator :
# Constructor
# p_D0 Initial value
# p_m average value
# p_sigma Volatility
# p_mr Mean reverting per factor
# p_T Maturity
# p_nbStep Number of time step for simulation
# p_nbSimul Number of simulations for the Monte Carlo
# p_bForward true if the simulator is forward, false if the simulation is backward
def __init__(self, p_D0, p_m, p_sigma, p_mr, p_T, p_nbStep, p_nbSimul, p_bForward) :
self.m_D0 = p_D0
self.m_m = p_m
self.m_sigma = p_sigma
self.m_mr = p_mr
self.m_T = p_T
self.m_step = p_T / p_nbStep
self.m_nbStep = p_nbStep
self.m_nbSimul = p_nbSimul
self.m_bForward = p_bForward
self.m_currentStep = 0. if p_bForward else p_T
self.m_OUProcess = np.zeros(p_nbSimul)
np.random.seed(0)
if self.m_bForward :
self.m_OUProcess = np.zeros(p_nbSimul)
else :
stDev = self.m_sigma * math.sqrt(1 - math.exp(-2 * self.m_mr * self.m_T) / (2 * self.m_mr))
self.m_OUProcess = stDev * np.random.randn(p_nbSimul)
# a step forward for OU process
def forwardStepForOU(self) :
racine = math.sqrt((1 - np.exp(-2 * self.m_mr * self.m_currentStep)) / (2 * self.m_mr))
stDev = self.m_sigma * racine
expActu = np.exp(-self.m_mr * self.m_step)
normalSample = np.random.randn(self.m_nbSimul)
increment = np.multiply(stDev, normalSample)
# update OU process
self.m_OUProcess = np.multiply(self.m_OUProcess, expActu) + increment
# a step backward for OU process
def backwardStepForOU(self) :
if self.m_currentStep <= 0. :
self.m_OUProcess = np.zeros(self.m_nbSimul)
else :
# use brownian bridge
util = np.sinh(self.m_mr * self.m_currentStep) / np.sinh(self.m_mr * (self.m_currentStep + self.m_step))
variance = np.multiply(pow(self.m_sigma, 2.) / (np.multiply(2, self.m_mr)), (1 - np.exp(-2 * self.m_mr * self.m_currentStep)) * pow(1 - np.multiply(np.exp(-self.m_mr * self.m_step), util), 2.) + np.multiply(1 - np.exp(-2 * self.m_mr * self.m_step), pow(util, 2.)))
stdDev = np.sqrt(variance)
temp = self.m_OUProcess
self.m_OUProcess = np.multiply(temp, util) + np.multiply(stdDev, np.random.randn(self.m_nbSimul))
# get current markov state
def getParticles(self) :
ret = self.m_OUProcess + (np.zeros(len(self.m_OUProcess)) + ((self.m_D0 - self.m_m) * math.exp(- self.m_m * self.m_currentStep) + self.m_m))
retMap = np.zeros((1, len(ret)))
for i in range(len(ret)):
retMap[0,i] = max(ret[i], 0.)
return retMap
# a step forward for simulations
def stepForward(self) :
if self.m_bForward == False :
pass
else :
self.m_currentStep += self.m_step
self.forwardStepForOU()
# return the asset values (asset, simulations)
def stepBackward(self) :
if self.m_bForward == True :
pass
else :
self.m_currentStep -= self.m_step
self.backwardStepForOU()
# a step forward for simulations
# return the asset values (asset, simulations)
def stepForwardAndGetParticles(self) :
if self.m_bForward == False :
pass
else :
self.m_currentStep += self.m_step
self.forwardStepForOU()
return self.getParticles()
# a step backward for simulations
# return the asset values (asset, simulations)
def stepBackwardAndGetParticles(self) :
if self.m_bForward == True :
pass
else :
self.m_currentStep -= self.m_step
self.backwardStepForOU()
return self.getParticles()
# Get back attribute
def getCurrentStep(self) :
return self.m_currentStep
def getT(self) :
return self.m_T
def getStep(self) :
return self.m_step
def getSigma(self) :
return self.m_sigma
def getMr(self) :
return self.m_mr
def getNbSimul(self) :
return self.m_nbSimul
def getNbStep(self) :
return self.m_nbStep
def getDimension(self) :
return 1
|