@@ -119,7 +119,8 @@ def simOU(s0=5, mu=4, theta=2, sigma=1, T=1, dt=1 / 252, sims=1000, eps=None, se
119119 Starting value for mean reverting random walk at time = 0
120120 mu : float, int or pandas Series
121121 Mean that the function will revert to. Can be either a scalar value (i.e. 5) or a pandas series for a
122- time dependent mean. If array-like, it must be the same length as T/dt (i.e. the number of periods)
122+ time dependent mean. If array-like, it must be the same length as T/dt (i.e. the number of periods,
123+ excluding start value)
123124 theta : float
124125 Mean reversion rate, higher number means it will revert slower
125126 sigma : float
@@ -157,10 +158,26 @@ def simOU(s0=5, mu=4, theta=2, sigma=1, T=1, dt=1 / 252, sims=1000, eps=None, se
157158
158159 # number of business days in a year
159160 bdays_in_year = 252
161+
162+ # calc periods
163+ N = int (T / dt )
160164
161165 # print half-life of theta
162166 print ("Half-life of theta in days = " , _np .log (2 ) / theta * bdays_in_year )
163167
168+ # make mu an array of same size as N+1
169+ try :
170+ iter (mu )
171+ if len (mu ) == N :
172+ mu = _np .append (mu [0 ] , mu )
173+ else :
174+ raise ValueError ("if mu is passed as an iterable, it must be of length int(T/dt)" )
175+ except :
176+ mu = _np .ones (N + 1 )* mu
177+
178+ # make same size as 1D array of all periods and sims
179+ mu = _np .tile (_np .array (mu ), sims )
180+
164181 if c == True :
165182 return _simOUc (s0 = s0 , mu = mu , theta = theta , T = T , dt = dt , sigma = sigma , sims = sims , eps = eps , seed = seed , log_price = log_price )
166183 else :
@@ -183,17 +200,6 @@ def _simOUc(s0, theta, mu, dt, sigma, T, sims=10, eps=None, seed=None, log_price
183200 '''
184201 )
185202
186- # make mu an array of same size as N+1
187- try :
188- iter (mu )
189- if len (mu ) != N + 1 :
190- raise ValueError ("if mu is passed as an iterable, it must be of length int(T/dt) + 1 to account for starting value s0" )
191- except :
192- mu = _np .ones ((N + 1 ))* mu
193-
194- # make same size as 1D array of all periods and sims
195- mu = _np .tile (_np .array (mu ), sims )
196-
197203 # generate a 1D array of random numbers that is based on a
198204 # 2D array of size P x S where P is the number of time steps
199205 # including s0 (so N + 1) and S is the number of sims. 1D
@@ -216,25 +222,18 @@ def _simOUc(s0, theta, mu, dt, sigma, T, sims=10, eps=None, seed=None, log_price
216222
217223
218224def _simOUpy (s0 , mu , theta , sigma , T , dt , sims = 1000 , eps = None , seed = None , log_price = False ):
219-
225+ mu = _pd .Series (mu )
226+
220227 # number of periods dt in T
221228 periods = int (T / dt )
222229
223- if isinstance (mu , list ):
224- assert len (mu ) == (
225- periods
226- ), "Time dependent mu used, but the length of mu is not equal to the number of periods calculated."
227-
228230 # init df with zeros, rows are steps forward in time, columns are simulations
229231 out = _np .zeros ((periods + 1 , sims ))
230232 out = _pd .DataFrame (data = out )
231233
232234 # set first row as starting value of sim
233235 out .loc [0 , :] = s0
234236
235- if isinstance (mu , list ):
236- mu = _pd .Series (mu )
237-
238237 # calc gaussian vector
239238 if eps is None :
240239 # rng = default_rng(seed)
@@ -251,18 +250,13 @@ def _simOUpy(s0, mu, theta, sigma, T, dt, sims=1000, eps=None, seed=None, log_pr
251250 continue # skip first row
252251
253252 # calc step
254- if isinstance (mu , list ) | isinstance (mu , _pd .Series ):
255- out .iloc [i , :] = (
256- out .iloc [i - 1 , :]
257- + (theta * (mu .iloc [i - 1 ] - out .iloc [i - 1 , :]) - ss ) * dt
258- + sigma * out .iloc [i , :] * _np .sqrt (dt )
259- )
260- else :
261- out .iloc [i , :] = (
262- out .iloc [i - 1 , :]
263- + (theta * (mu - out .iloc [i - 1 , :]) - ss )* dt
264- + sigma * out .iloc [i , :] * _np .sqrt (dt )
265- )
253+
254+ out .iloc [i , :] = (
255+ out .iloc [i - 1 , :]
256+ + (theta * (mu .iloc [i ] - out .iloc [i - 1 , :]) - ss ) * dt
257+ + sigma * out .iloc [i , :] * _np .sqrt (dt )
258+ )
259+
266260
267261 return out
268262
0 commit comments