Modeling stock returns and option prices with Mathematica.

Andrzej Kozłowski

Mathematica Day Warsaw University 2017

SetOptions[EvaluationNotebook[],CellContext->Notebook]

Mathematica provides excellent tools for probability and statistics and their various applications, especially to Mathematical finance. It is the only program that combines the ability to performs stochastic simulations, perform data analysis, algebra and calculus (including a vast collection of built-in of special functions) and even obtain live financial data from the Internet. We demonstrate some of this.

Mathematica's simulation abilities are based on its powerful and flexible collection of pseudo-random number generators.The default generator is a based on a non-linear cellular automaton. It's very effective but one has the option to change to other well known pseudo-random number generators, using the function SeedRandom.

For example

RandomInteger[{1,6}]

SeedRandom[Method->"MersenneTwister"];RandomInteger[{1,6}]

SeedRandom[Method->"ExtendedCA"];RandomInteger[{1,6}]

If we fix the seed we get the same sequence of random numbers

SeedRandom[2];RandomInteger[{1,6},5]

SeedRandom[2];RandomInteger[{1,6},5]

data=RandomVariate[NormalDistribution[0,1],{10^6}];

g1=Histogram[data,30,"PDF"]

g2=Plot[PDF[NormalDistribution[0,1],x],{x,-4,4}]

Show[g1,g2]

data=RandomFunction[GeometricBrownianMotionProcess[0.1,0.3,10],{0,1,0.01},100]

ListLinePlot[data,PlotRange->All]

RandomFunction[GeometricBrownianMotionProcess[0.1,0.3,10],{0,1,0.01},10^6];//Timing

Manipulate[
BlockRandom[
SeedRandom[r];
ListLinePlot[RandomFunction[GeometricBrownianMotionProcess[μ,σ,k],{0,1,0.001},n],PlotRange->{{0,1},{0,v}}]],
{{μ,1,"m (drift)"},-5,5,0.001,Appearance->"Labeled"},
{{σ,0.5,"volatility"},0.01,3,Appearance->"Labeled"},
{{k,100,"initial price"},10,200,Appearance->"Labeled"},
{{n,10,"number of paths"},1,100,1,Appearance->"Labeled"},
{{v,500,"range of values"},0.1,1000,Appearance->"Labeled"},
{{r,0,""},Button["reset",r=RandomInteger[2^64-1]]&},
SaveDefinitions->True]

Classical Models

E.g.   Merton’s model of portfolio allocation  or the Black-Scholes option pricing model.

Assumption:  ( continuously compounded) returns are normally distributed or asset prices are driven by a geometric Brownian motion. This is described by the formula

(Subscript[S, t])=exp(σ (Subscript[W, i])+μ t))

where (Subscript[W, t]) denotes the Wiener process or the Brownian motion.

Brownian motion was discovered as a natural phenomenon by the botanist Robert Brown in 1827.  Louis Bachelier, a student of Poincare,  gave the modern mathematical definition in 1900, of the stochastic process called Brownian motion and used it to model the movement of stocks on the stock exchange. This was later adapted to geometric Brownian motion (one reason being that ordinary Brownian motion can become negative).   Bachelier's theory was not well known and was rediscovered by Albert Einstein and the Polish physicist Smoluchowski. Norbert Wiener did a great deal of mathematical work on it so the 1-dimensional version is named after him.

The basic properties are: (Subscript[W, 0])=0, (Subscript[W, t ]) almost surely continuous, (Subscript[W, t]) has independent increments, (Subscript[W, t])-(Subscript[W, s]) has the distribution NormalDistribution[0,t-s]. (In fact, the 2nd and the 4th conditions are equivalent).

DateListPlot[FinancialData["^DJI",{{2008,1,1},{2017,11,5}}], Joined -> True]

Superficially, looks very similar to a path of geometric Brownian motion.

Bachelier reason for modeling stock movements was the desire to calculate the price of options. Options are just one (very important) kind of derivatives.

Derivatives and Options

A (financial) derivative is some kind of financial object whose value depends on the value of some other financial object, which is called "the underlying".  
Options are special kinds of derivatives that involve choice.  The two basic types of options are call options and put options. A call option gives the buyer the right (but not an obligation) to buy a fixed amount of underlying (which could be stock or a commodity) at or before a fixed time (called expiry time) for a fixed price (called strike price). A put option gives the buyer the right (but not the obligation) to sell a fixed amount of underlying at or before a fixed expiry, for a fixed price (called strike price). 
Options that can only be exercised at the final expiry time are called European options. Options that can be exercised any time before the expiry time are called American options. Naturally American options are more valuable than European ones as they give the owner more choice.

Arbitrage

While there is no such thing as a "fair price" of a share(other than the market price), in the case of a derivative the notion of  a "fair price " exists and "mispricingmispricing" is possible. The key concepts in finance: are "arbitrage" and "replicating portfolio".  "Arbitrage", sometimes called "free lunch" is essentially making money without taking any risk. The basic principle of option pricing assumes that the market prices are such that arbitrage is impossible. There is a lot of evidence that this assumption is justified. More precisely;  in reality arbitrage is possible and, in fact,  there are companies that specialize in arbitrage. But the amount of gain possible from arbitrage is small. Because in reality all market operations are subject to transaction costs, the small amount of arbitrage that exists can only be profitably exploited by large scale specialists. And by finding and exploiting arbitrage such companies help to eliminate it.
The other important concept is that of a replicating portfolio. A replicating portfolio for a derivative is a collection of other financial instruments that always gives the same final payoff as the derivative. If the market does not admit arbitrage that a replicating portfolio for a derivative must have the same value as the derivative.

Hedging and Black-Scholes

In the Black-Scholes model every derivative can be perfectly hedged using only the underlying and a risk-less bond, just as in the above demonstration (the Black-Scholes model is complete). This does not mean, as is often said, that in the Black-Scholes model one can eliminate risk - it means however that one can "hedge" risk (for a fee).  Unfortunately, as we know well, this does not reflect the reality.

Built-in Black-Scholes

FinancialDerivative[]

Example: American Option

americanOption[type_String, k_?NumericQ, 
s_?NumericQ, t_?NumericQ, r_?NumericQ, 
σ_?NumericQ, d_?NumericQ, v_: "Value"] := 
FinancialDerivative[{"American", type}, 
{"StrikePrice" -> k, "Expiration" -> t}, 
 {"InterestRate" -> r, "Volatility" -> 
σ, "CurrentPrice" -> s, "Dividend" -> d}, 
{v}, Method -> "Binomial"]

Manipulate[Module[{a = Quiet[Check[a = americanOption[type, 100, 100, t, r, σ, d, "CriticalValue"], -1]], pt, $strike, val, slope}, slope = If[type === "Call", 1, -1]; val = If[a > 0, americanOption[type, 100, a, t, r, σ, d], 10^3]; $strike = {Dashing[0.02], Line[{{100, 0}, {100, 10^3}}]}; pt = {Red, PointSize[0.015], Point[{a, val}]};
    If[a > 0, Plot[{val + slope (s - a), americanOption[type, 100, s, t, r, σ, d]}, {s, 0, maxstock}, Prolog -> {pt, $strike}, PlotStyle -> {Directive[Opacity[Boole[tangent]], Green], Directive[Black]}, PlotRange -> {{0, maxstock}, {0, maxoption}}, AxesLabel -> {"stock price", "option value"}, AspectRatio -> Automatic, ImageSize -> {500, 250}], Plot[americanOption[type, 100, s, t, r, σ, d], {s, 0, maxstock}, Prolog -> {$strike}, PlotStyle -> Directive[Black],
        PlotRange -> {{0, maxstock}, {0, maxoption}}, AspectRatio -> Automatic, AxesLabel -> {"stock price", "option value"}, ImageSize -> {500, 250}]]],
  Style["option specs", Bold],
  {{type, "Call", "option type"}, 
{"Call" -> "call", "Put" -> "put"}}, {{t, 0.5, "time to expiry (years)"}, 0.05, 1, 0.05, Appearance -> "Labeled", ImageSize -> Tiny},
  Delimiter,
  Style["general parameters", Bold], {{r, 0.05, "risk free interest rate"}, 0.01, 0.4, 0.01, Appearance -> "Labeled"}, {{d, 0.05, "dividend"}, 0, 0.4, 0.01, Appearance -> "Labeled"}, {{σ, 0.16, "volatility"}, 0.1, 0.8, 0.1, Appearance -> "Labeled"}, Delimiter,
  {{tangent, False, "show tangent"}, {True, False}, ControlType -> Checkbox},
  {{maxstock, 200, "stock price range"}, 150, 300}, {{maxoption, 150, "options price range"}, 50, 300}, ControlPlacement -> Top,
  SaveDefinitions -> True]

If the Black-Scholes model were true, the world would be a much better place, or at least a safer for financial companies. In the Black-Scholes model all the risk involved in derivatives can be hedged and each derivative has a unique fair price (which may be difficult to compute for complicated derivatives). We can actually see that the Black-Scholes model is not really a good fit to stock prices in the short or medium term. We will use Mathematica's FinancialData function to demonstrate this on an example of the S&P 500 index.

dataSP= FinancialData["^GSPC","Return", {"Jan. 1, 2010","Dec.1,2017"}];

retsSP=dataSP[[All,2]];

Kurtosis[retsSP]

ff=SmoothKernelDistribution[retsSP];

hh=EstimatedDistribution[retsSP,NormalDistribution[μ,σ]]

Plot[{Tooltip[PDF[hh][x],"estimated normal"],Tooltip[PDF[ff][x],"S&P500"]},{x,-0.1,0.1},PlotRange->All,PlotStyle->{Red,Blue}]

Plot[{PDF[hh][x],PDF[ff][x]},{x,-0.03,-0.04},PlotRange->All,PlotStyle->{Red,Blue}]

(This would be more pronounced if we chose a period with big crashes).

One solution is to try other processes than Brownian motion. The most natural thing to is to replace the Brownian motion by called Lévy processes. These are processes that have independent and identically distributed increments but are not necessarily continuous paths (and the distribution of returns are not normal). In fact, Brownian motion is the only Lévy  process with continuous paths.

We can ask Mathematica to find some distributions that fit well the given data. Here is a list.

FindDistribution[retsSP,4]

Not all of these are suitable since the distribution of returns of a Lévy process has to be "infinitely divisible" and only the second and fourth one are. But we ill construct a Lévy process that fits much better the returns distribution (and which Mathematica did not include in the list).

?MeixnerDistribution

gg=EstimatedDistribution[retsSP,MeixnerDistribution[a,b,m,d]]

Plot[{Tooltip[PDF[gg][x],"estimated Meixner"],Tooltip[PDF[ff][x],"S&P500"]},{x,-0.1,0.1},PlotRange->All,PlotStyle->{Red,Blue}]

It' s not perfect but much better. (This time the kurtosis is to large).

What does the process look like?

mx[a_,b_,m_,d_,t_]:=ProbabilityDistribution[Abs[PDF[MeixnerDistribution[a,b,m t,d t],x]],{x,-Infinity,Infinity}]

mm=mx[a,b,m,d,1]/.{a->158.8`,b->-0.09740493995361921,d->0.0006623278419398293`,m->0.00003195731805137607`};

RandomVariate[mm,{10}]

Clear[a]

Manipulate[
BlockRandom[
SeedRandom[r];
Quiet[Module[{n=100,dt,ls},ls=Accumulate[Prepend[RandomVariate[mx[a,b,m,d,1/n],n],0]];ListPlot[ls,DataRange->{0,1},PlotRange->{{0,1},{-v,v}}]]]],
{{m,1,"m (drift)"},-5,5,0.001,Appearance->"Labeled"},
{{a,0.5,"a"},0.01,1,0.001,Appearance->"Labeled"},
{{b,0.5,"b"},-3,3,0.001,Appearance->"Labeled"},
{{d,1,"d"},0.1,4,0.001,Appearance->"Labeled"},
{{v,1,"range of values"},0.1,10,Appearance->"Labeled"},
{{r,0,""},Button["new path",r=RandomInteger[2^64-1]]&},
SaveDefinitions->True,AutorunSequencing->{1,2,3,4},ControlPlacement->Top,SaveDefinitions->True]

Option Pricing

Unfortunately option pricing based on models other than Black-Scholes is much more complicated and not-surprisingly, presents many difficulties. For a start, potions cannot be completely hedged and there is no unique "fair price" determined by the requirement that there should be no arbitrage. In other words, some other principle is needed, in addition to absence of arbitrage, to determine the "fair price". Here is one example given by the so called "Esscher transform" (based on an idea from actuarial mathematics). We compare the prices of options in the Meixner model with Black-Scholes with the same volatility. We see that the former are generally higher.

Meixner

θ[ a_, b_, m_, d_,r_]:=((-1)/a)(b+2 ArcTan[((-Cos[a/2]+Exp[(m-r)/(2 d)])/(Sin[a/2]))])

MeixnerEsscher["call",a_, b_, m_, d_,r_,s_,k_,T_]:=Module[{c=Log[k/s],th=θ[ a, b, m, d,r]},s NIntegrate[PDF[MeixnerDistribution[a,a (th+1)+b,  m T, d T],x],{x,c,Infinity},AccuracyGoal->8]-Exp[-r T]k  NIntegrate[PDF[MeixnerDistribution[a,a  th+b,  m T, d T],x],{x,c,Infinity},AccuracyGoal->8]]

MeixnerEsscher["put",a_, b_, m_, d_,r_,s_,k_,T_]:=MeixnerEsscher["call",a, b, m, d,r,s,k,T]+k*Exp[-r*T]-s

Manipulate[Quiet@Show[DiscretePlot[{Tooltip[MeixnerEsscher[If[tt,"call","put"],a, b, m, d,r,100,k,t],"Meixner with Esscher transform"],Tooltip[FinancialDerivative[{"European",If[tt,"Call","Put"]}, {"StrikePrice"->k, "Expiration"->t},  {"InterestRate"-> r, "Volatility" -> ((a Sqrt[(d/(2 ))])/(Cos[b/2])), "CurrentPrice"-> 100, "Dividend"->0}],"Black-Scholes"]},{k,100-h,100+h,0.2},Joined->True,Filling->None,PlotStyle->{Red,Green},AxesLabel->{"strike price","option value"}, ImageSize-> {350,400}],Graphics[{Dashing[0.01],Tooltip[Line[{{100,-1000},{100,1000}}],"current option price"]}]],
Style["option type",Bold],
{{tt,True,""},{True->"call",False->"put"}},
Style["model parameters                                               ",Bold],
{{m,0.0015,"m (drift)"},-0.1,0.1,0.0001,Appearance->"Labeled", ImageSize-> Tiny},
{{a,.0242,"a"},0.01,0.03,0.0001,Appearance->"Labeled", ImageSize-> Tiny},
{{b,-0.19,"b"},-3.142,3.142,0.001,Appearance->"Labeled", ImageSize-> Tiny},
{{d,0.434,"d"},0.1,1,0.001,Appearance->"Labeled", ImageSize-> Tiny},
Delimiter,
Style["other parameters",Bold],
{{t,0.3,"expiry"},0.1,1,0.001,Appearance->"Labeled", ImageSize-> Tiny},
{{r,0.02,"rate of interest"},0,0.5,0.001,Appearance->"Labeled", ImageSize-> Tiny},
Delimiter,
{{h,2,"range of values"},0.2,10,0.001,Appearance->"Labeled", ImageSize-> Tiny},
SaveDefinitions->True,
ControlPlacement->Left,
SynchronousUpdating->False,Bookmarks->{"SP500":>{a=0.0242,b=-0.19,d=0.434,m=0.0015},"Nikkei":>{a=0.02982825,b=0.12716244,d=0.57295483,m=-0.00112426}}]