25 Years of Programming
An open source source for C, C++, OWL, BASIC, MDB, XLS, DOT, and more...
Home   Projects   Sitemap   Search   Blog   Forum+Chat   About Us   Privacy   Terms of Use   Feedback   FAQ   Images   Services   Payments   Humor   Music

Monte Carlo simulated stock price time series and random number generator

Given a starting price and desired volatility, this calculator generates a series of simulated daily stock prices using a choice of calculation methods. 

The purpose of doing this would be to generate a series of stock prices that is realistic1 but unpredictable and isn't drawn from a price history that you or a trading system you are testing might already be familiar with, such as prices from the past year.

Ways to use these numbers:

  1. For a real stock, enter its current price and volatility to create hypothetical continuations of its daily prices into the future.
  2. As the basis for calculating the value of options on the stock. Calculate a new option value for each new stock price. View how the theoretical value of the option changes in response to stock price changes. This can give you a sense of what option trading feels like, without risking any real money. Doing this many times for the same stock and option, and recording and averaging the outcomes, is the basis of the Monte Carlo option pricing method, which is one way to study the behavior of American-style options.
  3. Test yourself or a trading system on a series of stock prices that you and the system could not have encountered previously and learned to recognize.
  4. In a stock market trading game.
  5. Create fake stock charts. Mix them up with real stock charts, give the set to your friends, and see if they can tell which are real and which are fake.
  6. Create a stock chart that contains sections of data from a real stock mixed in with sections of data that you calculated here. See if your friends can determine which sections are real and which are fake.
  7. Try to write a computer program that can tell the difference between the fake charts and the real ones. The most realistic model would be the one that the program has the most difficulty identifying as fake.
Inputs Instructions

To calculate by the most common method, simply enter Starting Price and Volatility, and click Calculate.

Output Prices


 

Starting Price:
This will be the starting point from which successive values are calculated, but the start value will not be in the output list. Thus, if you want to extend an existing time series, you can enter its last value as the start value here.
Volatility (%):
%
The same volatility figure required for Black-Scholes option valuation. Enter as a percent, not a decimal. Ex: 62, not 0.62. If you have a set of daily prices for a real stock but don't know its volatility, you can use the volatility calculator. Historical price data is available at Yahoo! Finance.

Price calculation method:



Arithmetic: Up/down percentage point moves are equally likely even though up and down are not symmetrical. For example, a stock that loses 50% must gain 100% to regain the lost ground.

Logarithmic: Up and down moves are symmetrical; the probabilities of the stock doubling or halving are equal. Although it is nonintuitive, the most common model used in economics and finance is Logarithmic + Normal (below) = "lognormal".

None: Uses the calculator as a random number generator. The raw random numbers are not turned into simulated daily prices. 

Probability distribution:



Normal (aka gaussian): Mean=0, StdDev=Volatility / 100. 

Levy: Mean=0, Beta (skewness)=0, Alpha (kurtosis) is used as entered below. c (variability, "StdDev") = (Volatility / 100) / Vol.adj.factor.

Uniform: Mean=0. For raw random numbers, > -Volatility / 100 and < Volatility / 100. For simulated prices, equally distributed between ±1.733421 * Volatility / 100, which forces calculated volatility into desired range9.

For Levy only:

Alpha:

Vol. adj. factor:

Alpha must be > 0 and <= 2. Default value of 1.7 is probably too low. Alpha = 1 is a Cauchy distribution. Alpha = 2 is a Gaussian normal distribution. 

Volatility adjustment (aka fudge) factor is any number that brings the calculated volatility (in Verify:, below) closer to the requested value. With Alpha = 1.7, an adjustment factor of 2 seems to work ok. 

# of days:
The number of values to calculate. Default = 252 = 1 trading year.
Click Calculate.
(Reverse) The output default sort order is from oldest date at the top to most recent at the bottom. To reverse, click the Reverse button before copying the data.
Copy
and
Paste
Click anywhere in the output box. Type Ctrl+A (Select All), then Ctrl+C (Copy to clipboard). Paste the numbers in the application where you want to use them (Ctrl+V). 
  Verify: at left is the actual calculated annualized volatility of the generated numbers. It won't exactly match the requested value because the output prices are random numbers. 

Notes

1) How well any of these models simulate real price behavior is debatable.  

2) General method of calculation:

  • Convert the input Volatility (a percent) to decimal: true annual Volatility = Volatility / 100
  • Convert annual Volatility to daily: Volatilitydaily = Volatilityannual * SQRT(1/252)
    252 is the number of trading days in a year. The calculator generates 252 random daily prices for each year. If the 252-based daily volatility is used 252 times, the volatility for the entire year will approximate the requested annual volatility. Note that if we used a 365-based daily volatility (a smaller number) and only use it in 252 predictions (because no stock or option trades 365 days in a year), the annualized volatility won't approximate the requested value. It will be less.
  • For each daily data point: generate a random number from the specified probability distribution (Normal, Levy, or Uniform); use the random number and yesterday's price in the appropriate equation (arithmetic or logarithmic) to calculate a new price for today; lastly, today's price becomes yesterday, and repeat.

3) Equations for some of the combinations (the others are in the JavaScript source code):

Arithmetic Normal: Today = Yesterday * (1 + NormalRandom(Mean = 0, StdDev = Volatilitydaily))

The Mean (average) of 0 makes it equally likely that today's price will be above/below yesterday's. Volatilitydaily is used as the standard deviation. As an example, if it is .01 and Yesterday was $100, then there is a 68% probability that Today will be somewhere between
($100 * (1 + (-.01))) = $99 and ($100 * (1 + (.01))) = $101.

Log Normal: Today = Yesterday * Math.exp(NormalRandom(Mean = 0, StdDev = Volatilitydaily))
which means: Today = Yesterday * eNormalRandom(0, Volatility); (e = 2.71828...)

The lognormal model of price fluctuations is commonly used. It is the model assumed by Black-Scholes. Using the random number in the exponent causes the price changes in the output series to have a lognormal distribution. This means that the price changes themselves do not fall into a normal distribution, but the natural logarithms of the price changes do. 

Arithmetic Levy: Today = Yesterday * (1 + GSLRandomLevy(c = Volatilitydaily / AdjustFactor, Alpha))

The equation is the same as for Arithmetic Normal, but the random number is from a Levy distribution. Levy (Lévy) distributions have wider variance than the Gaussian normal distribution and can produce large price jumps that almost never occur with a normal distribution. The reason some people advocate using a Levy distribution is specifically because price swings that the Gaussian distribution says are nearly impossible do occur in real trading. 

The Alpha parameter of a Levy determines its kurtosis (inversely). A Gaussian normal curve actually is a Levy curve with alpha=2. As alpha drops below 2, the kurtosis increases: the curve becomes more pointy in the middle, and the tails rise farther above the baseline so there is more area in them. What this means in practical terms is that even though most values still tend to be near the center point of 0, deviations that are very far away from it become more and more probable as alpha goes lower.  

Levy distributions have a skewness parameter called beta. In these calculations, beta = 0.

A peculiar characteristic of a Levy distribution is that it has no defined standard deviation. This becomes a problem when we want to generate random numbers with a particular standard deviation.

Instead, a Levy has a scale (or dispersion) parameter, known as "c", that is analogous to StdDev in that it describes in a sense how wide the distribution is but isn't the same as StdDev.

This calculator uses the Volatility as the value for c. However, because the Levy distribution doesn't "respect" the standard deviation the way the Gaussian does, the numbers generated are not so strictly limited by this c value as they would be for a real standard deviation. Thus, due to the greater likelihood of extreme values in the generated numbers, their calculated volatility (in the "Verify:" box of the calculator) can vary wildly from the requested volatility value and can vary wildly from one run to the next.

In testing, I found that although there is great variability in the calculated volatility, it's not totally random, and it's possible to bring the calculated values more or less into the desired range, but it requires applying a fudge factor to c (the Volatility) to do it, and that is where AdjustFactor in the above equation comes in. It's a practical necessity. Since, in the Levy case, the Volatility is not a real standard deviation anyway, fudging it hardly seems a violation from any theoretical perspective. The ultimate goal is to get output numbers whose actual volatility, when calculated the usual way, is in the requested range. 

Nonetheless, I'm open to alternatives, especially ones that make more theoretical sense. One alternative that might make more sense is to use an AdjustmentFactor of 1 and adjust Alpha instead, to values between 1.7 and 2.0.

Log Levy: Today = Yesterday * Math.exp(GSLRandomLevy(c = Volatilitydaily / AdjustFactor, Alpha))

This method is like the lognormal, except it uses the Levy random number in the exponent and therefore produces lognormally distributed stock prices. I suspect that if the Levy distribution ever replaces the Gaussian normal for stock price models, it would be with this log-Levy model.

However, the Levy distribution's ability to produce almost arbitrarily large numbers can be especially weird when the value is used as an exponent. In one test, a stock price went from $9 to $29,000 in one day, which can hardly be said to be realistic.

4) The Levy methods in the calculator are experimental. I don't know if they are correct.

5) Wikipedia has information about the Levy-related probability distributions.

6) The Gaussian and Levy random number generator functions are in my JavaScript library

7) How to graph the simulated price series in Excel:

  • Copy the output prices and paste them into Column A of a blank worksheet.
  • Click Insert > Chart (or the Chart Wizard button).
  • Type=Line. Next...
  • Data Range: Click the top of Column A so the entire column is selected. Equivalent is $A:$A.
  • Click Finish. You can drag the chart handles to resize it.

8) How to make a frequency histogram in Excel:

The type of graph that reveals the bell shape of a bell-shaped distribution (or the shape of any probability distribution) from raw data is called a histogram. It plots each number (on the X axis) against the number of times it occurred (on the Y axis). (As a practical matter, since any one number is unlikely to recur, the numbers are usually grouped into intervals first.)

  • Click Tools > Data Analysis > Histogram
  • Input Range = the column where you pasted the source numbers, such as $A:$A
  • Bin Range = (blank). Let Excel automatically determine how the numbers are grouped.
  • Labels = checked if the top cell is a textual label
  • New Worksheet Ply = checked
  • Pareto and Cumulative = unchecked
  • Chart Output = checked 
  • Click OK. Drag chart handles to resize it.

As an example: next to Column A of raw prices (for which a histogram isn't much use), make Column B for the "daily returns" (today's price / yesterday's price), and next to that, Column C for the logarithm (LN() function) of the daily returns. Make (separate) histograms for Columns B and C. If your prices were created using a lognormal distribution, the graph of Column B looks like a bell-shaped curve except that the right side has a slightly longer and taller tail than the squished-looking left side. (It is skewed.) However, the histogram of Column C (the logarithms) should be a symmetrical normal curve.

9) I found through testing that using (Volatility * 1.733421) for uniformly distributed random numbers used for generating time series brought their calculated volatility into the same range as a normally distributed random number with StdDev=Volatility. It wasn't the factor I expected to use, so where it comes from is a mystery to me. It is approximately SQRT(3), which might or might not be a coincidence.

10) Questions, comments, feedback, suggestions are welcome in the discussion forum. It was a forum question that inspired the addition of Lévy distribution methods.

11) Most options traders lose money. 


 

Valid HTML 4.01 Transitional Valid CSS
Yahoo! Search
Search the web Search this site
View content labeling at ICRA.