Usage

Simple example

Generate 3 Brownian motion paths. All paths start at 1, and have 6 steps with a stepsize of dt=1/4. The drift is -2 and volatility is 0.7.

The result is a 2d numpy array with 3 columns for the 3 random paths.

from quantfinlib.sim import BrownianMotion

bm = BrownianMotion(drift=-2, vol=0.7)
paths = bm.path_sample(x0=1, dt=1/4, num_steps=6, num_paths=3)

print(paths)
[[ 1.          1.          1.        ]
 [ 0.76078112  0.30204577  0.50236666]
 [ 0.10693312  0.52742273 -0.00455142]
 [-0.58735737 -0.07077471 -0.49410279]
 [-1.28767801 -0.45260711 -1.00543806]
 [-1.32530203 -0.38564426 -1.44807087]
 [-1.80358005 -0.44790251 -1.78687451]]

Adding Date-time indices

Add date time labels, and return a Pandas DataFrame with a DateTime index:

In this example we add date-time index labels by specifying label_start and label_freq. The first row is labeled 2000-01-01 and we specify we want daily (D) timesteps frquences. We also set dt = 1/365 so that the simulation timesteps align with the label timesteps.

from quantfinlib.sim import BrownianMotion

bm = BrownianMotion(drift=-2, vol=0.7)

paths = bm.path_sample(
    x0=1, dt=1/365, num_steps=6, num_paths=3,
    label_start='2000-01-01',
    label_freq='D'
)

print(paths)
                 S_0       S_1       S_2
2000-01-01  1.000000  1.000000  1.000000
2000-01-02  1.042587  0.983007  1.009464
2000-01-03  0.995895  1.064768  0.965036
2000-01-04  1.022268  1.064751  0.942556
2000-01-05  1.014225  1.057032  1.014004
2000-01-06  1.014874  1.062645  0.966024
2000-01-07  0.961137  1.103688  0.981758

Other frequency string options are:

Start label

Many input types are supported for the start label, e.g.

  • Strings like “Jul 31, 2009”, “2009-12-31”, “2009/12/31”

  • Python datetime.date or datetime.datetime, like datetime(2023, 6, 30)

  • Epoch timstamp like 1349720105

Label Frequency

Freqency string are compatible with the Pandas date_range function. More frequency strings can be founds in the Pandas documentation Pandas Timeseries Offset Aliases .

The date time index labels are set independently from the path simulation routines. If you specifiy a freq in the path_sim function then you can ommit the simulation step size dt. The dt timstep will then default to the timestep listed in the following table.

Freq

Sim step-size (years)

Description

D

1 / 365

Daily

B

1 / 252

Business days Modays till Friday, skipping Saturday and Sunday.

W

1 / 52

Weekly

M

1 / 12

Monthly

MS

1 / 12

Month starts

ME

1 / 12

Month ends

Q

1 / 4

Quarterly

QS

1 / 4

Quater starts

QE

1 / 4

Quarter ends

YS

1

Yearly starts

YE

1

Yearly ends

In the following example we say we want to start on Jan 12th 2000, and have all labels fall on month ends. The first label wil be the last day of them month Jan 2000, and consecutive labels on te next month ends. We don’t specify dt which will make it default to 1 / 12.

from quantfinlib.sim import BrownianMotion

bm = BrownianMotion(drift=-2, vol=0.7)

paths = bm.path_sample(
    x0=1,  num_steps=6, num_paths=3,
    label_start='2000-01-12',
    label_freq='ME'
)

print(paths)
                 S_0       S_1       S_2
2000-01-31  1.000000  1.000000  1.000000
2000-02-29  0.999258  0.954949  1.011364
2000-03-31  0.978617  1.013084  1.047077
2000-04-30  0.966779  1.053462  0.985346
2000-05-31  0.894828  1.071365  1.022621
2000-06-30  0.870602  1.100539  0.924800
2000-07-31  0.823111  1.157774  0.936199

Simulating correlated assets

Simulation of two correlated assets, the columns are organized in pair of correlated stocks, and the columns hames have _<scenario number> appended.

from quantfinlib.sim import BrownianMotion

bm = BrownianMotion(
    drift=[0.05, 0.05],
    vol=[0.5, 0.5],
    cor=[[1, 0.4],
         [0.4, 1]]
    )

paths = bm.path_sample(
    x0=[1, 2], num_steps=6, num_paths=3,
    label_start='2000-01-01',
    label_freq='D'
    )

print(paths)
                S0_0      S1_0      S0_1      S1_1      S0_2      S1_2
2000-01-01  1.000000  2.000000  1.000000  2.000000  1.000000  2.000000
2000-01-02  1.026423  1.970893  1.095629  2.017679  1.023596  1.970147
2000-01-03  1.048163  2.008878  1.061499  1.999452  1.068060  2.040977
2000-01-04  1.026737  2.048024  1.058046  2.023318  1.034463  1.993922
2000-01-05  1.099012  2.062655  1.122895  2.017559  1.006297  2.010323
2000-01-06  1.026948  2.060643  1.113639  1.992770  1.001308  1.969070
2000-01-07  1.006086  2.021432  1.103503  1.959906  1.037784  1.960683

Column Names

Optionally you can set the columns names with the columns argument.

from quantfinlib.sim import BrownianMotion

bm = BrownianMotion(
    drift=[1.0, -0.1],
    vol=[42, 0.1],
    cor=[[1, 0.9],
         [0.9, 1]]
    )

paths = bm.path_sample(
    x0=[25.0, 0.011], num_steps=6, num_paths=3,
    label_start='2000-01-01',
    label_freq='D',
    columns=['GME', 'DOGE']
    )

print(paths)
                GME_0    DOGE_0      GME_1    DOGE_1      GME_2    DOGE_2
2000-01-01  25.000000  0.011000  25.000000  0.011000  25.000000  0.011000
2000-01-02  20.893130  0.001040  22.269670  0.003637  25.642333  0.013641
2000-01-03  24.836074  0.009915  23.425357  0.006622  29.458321  0.021807
2000-01-04  24.096260  0.004678  25.903173  0.009978  31.614789  0.023195
2000-01-05  25.823232  0.010031  28.066376  0.013523  31.683700  0.024002
2000-01-06  26.080634  0.008546  27.074969  0.011029  31.390732  0.021673
2000-01-07  22.218583  0.000458  28.109728  0.011645  36.041238  0.033805