I'm trying to generate some sample geometric brownian motion paths for an asset which is traded 24/7 without interruption and is highly volatile (upwards to 150% implied volatility on options markets).
I'm currently using this script: https://stackoverflow.com/a/13203189/5433929
I would like to generate sample paths with arbitrary resolution like a minute, an hour, a day, or anything between these. My understanding is that if I assume an annualized volatility of 150% for example, and I want to generate an hourly GBM using the script I linked, I will need to convert this 150% in to an hourly volatility, which is done by taking 1.5/sqrt(number of hours in a year)
. However when I do this, the sample paths generated over for example a 30 days time horizon are not realistic at all. Depending on the drift parameter, it eithers goes almost in a straight line up, varies with the typical GBM features within an extremely tight range of +/- 0.1% not at all representative of an asset with such high volatility.
What am I doing wrong here?
Thanks in advance.
EDIT:
Due to demand from @Kermittfrog, I'm pasting in my specific script.
def generateGBM(T, mu, sigma, S0, dt):
'''
Generate a geometric brownian motion time series. Shamelessly copy pasted from here: https://stackoverflow.com/a/13203189
Params:
T: time horizon
mu: drift
sigma: percentage volatility
S0: initial price
dt: size of time steps
Returns:
t: time array
S: time series
'''
N = round(T/dt)
t = np.linspace(0, T, N)
W = np.random.standard_normal(size = N)
W = np.cumsum(W)*np.sqrt(dt) ### standard brownian motion ###
X = (mu-0.5*sigma**2)*t + sigma*W
S = S0*np.exp(X) ### geometric brownian motion ###
return t, S
I'm doing this with the following parameters:
#Initial reference market price
INITIAL_PRICE = 1100
#The desired annualized volatility
ANNUALIZED_VOL = 1.5
#The annual drift of the geometric brownian motion
DRIFT = 0.04
#The time horizon in days
TIME_HORIZON = 30
#The size of the time steps in days (20 minutes here)
TIME_STEPS_SIZE = 0.0138889
and scaling down annualized volatility and drift by dividing by the square root of the number of timesteps there would be in a year
N_timesteps = 365/dt
sigma_timestep = sigma/np.sqrt(N_timesteps)
mu = DRIFT/np.sqrt(N_timesteps)
The result is plots that don't really look anything like what one would expect from a 150% volatility asset over a period of a month, unless my expectations are really wrong
sigma=1.50
, but you set the time increment parameter to something likedt = 1 / 365 / 24
or whatever idea of #trading days / year and #trading hours / day you have. Then, your hourly drift ism = (mu - 0.5 * sigma**2)*dt
, and your hourly random increment ise = sigma * sqrt(dt) * np.random.randn()
. Thus, the next hour's simulated price given the price right now isS * exp(m + e)
. You can of course neatly vectorise all that. HTH? $\endgroup$