Simulate stocks, interest rates, and other stochastic processes.
pyesg is a lightning fast economic scenario generator for Python.
An economic scenario generator simulates the behavior of unpredictable financial markets like stocks, interest rates, or energy prices. It uses mathematical models called stochastic processes to generate thousands of unique scenarios.
What can you do with an economic scenario generator? Here are a few examples:
pyesg is available on PyPI, and can be installed with pip.
pip install pyesg
All models in pyesg are created and used nearly identically.
First, create a model with its required parameters.
import pyesg
# create a new model with the required parameters
model = pyesg.GeometricBrownianMotion(mu=0.05, sigma=0.2)
Generate scenarios by calling the <model>.scenarios
method. The example below, with 10,000 daily scenarios (2,520,000 values) took just 160 milliseconds to run!
model.scenarios()
import pyesg
# instantiate a new model with the required parameters
model = pyesg.GeometricBrownianMotion(mu=0.05, sigma=0.2)
# prepare the arguments to generate scenarios. Here we'll
# generate 10,000 scenarios with 252 daily (trading day)
# time steps, for a one-year projection in total.
x0 = 100.0 # the start value of our process
dt = 1/252 # the length of each timestep in years
n_scenarios = 10000 # the number of scenarios to generate
n_steps = 252 # the number of time steps per scenario
random_state = 123 # optional random_state for reproducibility
# now we generate the scenarios; this outputs a numpy array. It will
# have shape (10000, 253), which represents (scenarios, timesteps).
# There are 253 timesteps because the initial value is included to start
results = model.scenarios(x0, dt, n_scenarios, n_steps, random_state)
# array([[100. , 98.65207527, 97.12924873, ..., 111.3500094 ,
# 112.00479028, 113.12444153],
# [100. , 101.27637842, 100.8971646 , ..., 61.8709475 ,
# 63.00222064, 62.22126261],
# [100. , 100.37636067, 99.32267874, ..., 141.66969149,
# 140.38291993, 138.91659076],
# ...,
# [100. , 99.42484152, 97.68732205, ..., 139.9306172 ,
# 139.52301459, 139.05345463],
# [100. , 100.75304745, 102.09894601, ..., 115.66615197,
# 116.16385992, 118.06267759],
# [100. , 101.24269853, 101.73381851, ..., 84.65843473,
# 84.73018762, 85.09768131]])
All models provide methods to evaluate their drift, diffusion, expectation, standard deviation, and more.
import pyesg
# instantiate a new model with the required parameters
model = pyesg.GeometricBrownianMotion(mu=0.05, sigma=0.2)
# drift is the instantaneous drift of the process. For example,
# if we start with x0=100, what is the instantaneous drift?
model.drift(x0=100)
# array([5.])
# similarly we can measure the instantaneous diffusion
model.diffusion(x0=100)
# array([20.])
# the expectation is the expected value of the process after
# a given amount of time, dt. Here we calculate the expected
# value of the process after one year.
model.expectation(x0=100, dt=1.0)
# array([105.])
# the standard deviation is measured at a period of time too
model.standard_deviation(x0=100, dt=1.0)
# array([20.])
We can almost always observe interest rates at key maturities, for example, bonds trading with maturies of 1, 2, 3, 5, 7, or 10 years. If we want to estimate the interest rate for an 8-year bond, we need to interpolate between the observed values. Simple techniques like linear interpolation are possible, but have certain obvious disadvantages - namely that the interest rate curve is non-linear. Instead, better techniques like the Nelson-Siegel and Nelson-Siegel-Svensson interpolators might give better results. Both interpolators are availabe in pyesg.
import numpy as np
from pyesg import NelsonSiegelInterpolator, SvenssonInterpolator
from pyesg.datasets import load_ust_historical
# load a dataset of historical US Treasury rates, contained in pyesg.datasets
# ust is a pandas dataframe of rates for various maturities, indexed by year and month
ust = load_ust_historical()
# we will be interpolating rates from the file:
# y - the observed US Treasury rate for the given maturity for a select observation date
# X - the maturity of the bond measured in years
y = ust.iloc[-10].values
X = np.array([0.25, 0.5, 1, 2, 3, 5, 7, 10, 20, 30])
# create Nelson-Siegel and Nelson-Siegel-Svensson interpolator objects
# then fit both models using the historical data
nelson_siegel = pyesg.NelsonSiegelInterpolator()
svensson = pyesg.SvenssonInterpolator()
nelson_siegel.fit(X, y)
svensson.fit(X, y)
# predict values for each maturity from 1 to 30 years
nelson_siegel.predict(np.arange(1, 31, 1))
# array([0.02033871, 0.02252733, 0.02403659, 0.02510373, 0.02587762,
# 0.02645304, 0.02689131, 0.02723275, 0.02750438, 0.02772458,
# 0.02790617, 0.02805818, 0.02818715, 0.02829786, 0.0283939 ,
# 0.02847798, 0.02855218, 0.02861815, 0.02867718, 0.02873031,
# 0.02877839, 0.02882209, 0.02886199, 0.02889857, 0.02893222,
# 0.02896329, 0.02899205, 0.02901876, 0.02904362, 0.02906683])
Open Source and licensed under MIT, Copyright © 2019-2021 Jason Ash