Package: pyesg
Simulate stocks, interest rates, and other stochastic processes.pyesgis a lightning fast economic scenario generator for Python.What is an economic scenario generator?An economic scenario generator simulates the behavior of unpredictable financial markets like stocks, interest rates, or energy prices. It uses mathematical models calledstochastic processesto generate thousands of unique scenarios.What can you do with an economic scenario generator? Here are a few examples:Simulate an investment portfolioGenerate 1,000 correlated, daily stock pricesConstruct a portfolio from the stocksPlot the value of the portfolio over time, and calculate metrics like high, low, max drawdown, etc.Choose a mortgageGenerate 1,000 30-year, monthly scenarios of mortgage ratesCalculate the monthly payment for different loans under each scenario:30-year fixed (lock in the rate today for all 30 years)15-year fixed (lock in the rate today and pay over 15 years)10-year adjustable-rate (fixed rate for 10 years, then variable rate for 20 yearsetc.Determine which loan fits the best with your budgetPlan for retirementGenerate 1,000 30-year, monthly scenarios of stock market dataGenerate 1,000 30-year, monthly scenarios of bond fund dataTrack your portfolio balance as a mix of investments in stocks and bondsEach month, simulate a withdrawal from your portfolio and the growth from your investmentsAdjust the withdrawal up or down and identify the types of markets that lead to the best and worst outcomesProtect your businessBanks: test whether loan portfolios are resilient to drops in interest rates and higher-than-expected customer refinancingInsurers: test whether assets are sufficient to cover liabilities under a wide range of bond market scenariosInvestment managers: test the impact of market declines on revenue from account-based feesSmall Businesses: model customer demand correlated with the stock market to plan for potential downturnsKey Features ofpyesgBuilt onnumpyfor lightning fast scenario generation: 10,000+ scenarios in millisecondsDozens of stochastic processes available out of the boxEquity: Geometric Brownian Motion / Black Scholes, HestonInterest rate: Vasicek, Cox-Ingersoll-Ross, Hull-WhiteComplete implementation of the American Academy of Actuariesstochastic interest rate generatorthat is200 times fasterthan the Excel versionCurve interpolation functions like Nelson-Siegel and Svensson modelsHundreds of unit tests and excellentcode coverageOpen source software, free to use, copy, or modify under MIT licenseComing soonMore models!Fit stochastic models using historical dataBuilt-in plotting methodsScenario summary reportsInstallingpyesgpyesgis available onPyPI, and can be installed with pip.pip install pyesgUsageAll models inpyesgare created and used nearly identically.First, create a model with its required parameters.importpyesg# create a new model with the required parametersmodel=pyesg.GeometricBrownianMotion(mu=0.05,sigma=0.2)Generate scenarios by calling the<model>.scenariosmethod. The example below, with 10,000 daily scenarios (2,520,000 values) took just160 millisecondsto run!Under the hood:model.scenarios()This method generates scenarios, given the following arguments:x0: the value or array of values each scenario starts with. For example, you might pass100.0to model a security with a current value of 100, or[100.0, 90.0]to model two scenarios with start values of 100 and 90.dt: the length of each time step in the projection, in years. For example, you might pass1/12to model mothly timesteps,1/52to model weekly timesteps,1/252to model daily (trading day) timesteps, or1to model annual timesteps.n_scenarios: the number of scenarios you want to generate. Often you can generate 10,000 scenarios in fractions of a second.n_steps: the number of timesteps for each scenario. In combination withdt, this argument determines the total length of time a projection covers. For example, withdt=1/52andn_steps=104, the projection will cover two years with weekly timesteps. Withdt=1/12andn_steps=360, the projection will cover 30 years with monthly timesteps.random_state: an optional field that may be provided if you want to be able to reproduce pseudo-random numbers for each batch of scenarios. For example,<model>.scenarios(..., random_state=123)will generate the exact same batch of scenarios every time.importpyesg# instantiate a new model with the required parametersmodel=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 processdt=1/252# the length of each timestep in yearsn_scenarios=10000# the number of scenarios to generaten_steps=252# the number of time steps per scenariorandom_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 startresults=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.importpyesg# instantiate a new model with the required parametersmodel=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 diffusionmodel.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 toomodel.standard_deviation(x0=100,dt=1.0)# array([20.])Available ModelsEquityGeometric Brownian MotionHeston ModelInterest RateAmerican Academy of Actuaries Interest Rate GeneratorBlack-Derman-ToyBlack-KarasinskiCox-Ingersoll-RossHo-LeeOrnstein-Uhlenbeck Process (Vasicek Model)GeneralWiener ProcessCurve InterpolatorsWe 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 inpyesg.importnumpyasnpfrompyesgimportNelsonSiegelInterpolator,SvenssonInterpolatorfrompyesg.datasetsimportload_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 monthust=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 yearsy=ust.iloc[-10].valuesX=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 datanelson_siegel=pyesg.NelsonSiegelInterpolator()svensson=pyesg.SvenssonInterpolator()nelson_siegel.fit(X,y)svensson.fit(X,y)# predict values for each maturity from 1 to 30 yearsnelson_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])LicenseOpen Source and licensed under MIT, Copyright © 2019-2021 Jason Ash