So how can a drunkard walking down the street lead to such a scary sounding thing like ‘Stochastic Calculus‘? Under certain conditions and taking the continuous limit, the Drunkard’s Walk becomes Brownian Motion. I’ll try to show you how this all happens using a little bit of JavaScript. In the Drunkard’s Walk, we assumed that with each step the drunkard takes he moves a distance of 1 foot to either the left or right. Its natural to wonder if something interesting would happen if we scaled this distance and took many more steps. As a matter of fact, something interesting does happen!
Scaled Symmetric Random Walk
To show you how this all happens, I need to first introduce the scaled symmetric random walk process, which is a modified version of the Drunkard’s Walk.
In this equation, is the current value of the random process at time t. This process moves
steps during each time interval, such that
, the time difference between steps, equals
. The reason we call this process a ‘symmetric‘ random walk is that for each step, we increase or decrease the process with the same probability. The ‘scaled‘ part in the name comes from the fact that we scale each step by
. This may seem like a strange value to scale the process by, but I’ll show you why we chose this particular value in a moment.
Simulation
Too illustrate the above process, I’ve created the following simulation. Simply select the number of paths you want to generate, the number of steps per period, and the total number of periods, then click ‘Draw’. Since this is JavaScript, it will run on your computer. If you have an older computer, it could take a minute so be patient!
One thing I hope you noticed from this simulation is that the final values look roughly bell shaped (or normally distributed). Additionally, the sample mean and sample variance of the final values are also close to 0 and T, respectively. As a matter of fact, as the the number of steps each period goes to infinity, the final value of each path is exactly distributed normally with a mean of 0 and a variance of T. If we had scaled the random walk by some value other than , the variance would be either 0 or infinity; therefore, the scaling factor we selected is a special case and gives us a normally distributed final value. When the steps per period goes to infinity, we call this process Brownian Motion. If you set the steps per period and the total periods to the largest values allowed, the simulated Brownian Motion paths look oddly like stock prices! Hopefully this gives you a feel for why Brownian Motion is often used as the basic building block for simulating stock prices.
JavaScript Code
For those interested, the following is the JavaScript code was used to generate the chart above. It generates the paths using the scaledSymRandomWalk() function, and generates the chart using the Google Visualization API. The call to scaledSymRandomWalkDemo() is the workhorse that populates the charts and inserts them into the specified HTML div’s.
// load Google Visualization API google.load("visualization", "1", {packages:["linechart"]}); google.load("visualization", "1", {packages:["columnchart"]}); // function to demonstrate a scaled symmetric random walk // m is the number of paths // n is the number of steps per period // t is the number of periods function scaledSymRandomWalkDemo(m, n, t) { // create and populate 2D array of random walk paths var w = new Array(m) for(var i=0; i<m; i++){ w[i] = scaledSymRandomWalk(n, t); } // create DataTables for paths and histogram var path = new google.visualization.DataTable(); var hist = new google.visualization.DataTable(); path.addColumn('string', 'n'); for(var i=0; i<m; i=i+1){ path.addColumn('number', i); } hist.addColumn('string', 'h'); hist.addColumn('number', 'count'); // populate DataTable path path.addRows(n*t+1); var label = ''; for(var i=0; i<(n*t+1); i++){ label = Math.round(i/n*1000)/1000+''; path.setValue(i, 0, label); for(var j=0; j<m; j++){ path.setValue(i, j+1, Math.round(w[j][i]*1000)/1000); } } // populate histogram bucket boundry array var buckets = 20; var bucketSize = 0.25*Math.sqrt(t); var bucketLower = -2.5*Math.sqrt(t); var histBounds = new Array(buckets); for(var k=0; k<(buckets+1); k++){ histBounds[k] = k*bucketSize + bucketLower; } // initialize array to hold bucket frequency counts var v=new Array(buckets); for(var k=0; k<buckets; k++){ v[k]=0; } // populate bucket frequency count array var x=new Array(m); for(var i=0; i<m; i++){ x[i] = w[i][n*t]; for(var k=0; k<buckets; k++){ if(x[i]>histBounds[k] && x[i]<=histBounds[k+1]){ v[k] = v[k] + 1; } } } // populate DataTable hist hist.addRows(buckets); for(var k=0; k<buckets; k++){ hist.setValue(k, 0, Math.round(histBounds[k]*100)/100 +' to '+ Math.round(histBounds[k+1]*100)/100); hist.setValue(k, 1, v[k]); } // Draw charts using Google Visualization API var chartPath = new google.visualization.LineChart(document.getElementById('scaledSymRandomWalk_div')); var chartHist = new google.visualization.ColumnChart(document.getElementById('histogram_div')); chartPath.draw(path, {width:700, height:400, enableTooltip:false, pointSize:0, legend:'none', lineSize:1, title:'Scaled Symmetric Random Walk', titleX:'t', titleY:'W(t)', axisFontSize:10, titleFontSize:15}); chartHist.draw(hist, {width:400, height:250, is3D:false, enableTooltip:false, pointSize:0, legend:'none', title:'Histogram of Final Values W(T)', titleY:'Counts', axisFontSize:10, titleFontSize:15}); // Calculate sample mean and sample variance var sampleMean = Math.round(mean(x)*100)/100; var sampleVar = Math.round(variance(x)*100)/100; // Show sample stats document.getElementById('sampleStats_div').innerHTML="W(T) Sample Mean: "+ sampleMean +"<br />W(T) Sample Variance: "+ sampleVar; } // function to perform a scaled symmetric random walk // n is the number of steps per period // t is the number of periods function scaledSymRandomWalk(n, t) { var w=new Array(n*t+1); w[0] = 0; var u = 0; for(var i=1; i<(n*t+1); i++){ u = Math.random(); if(u>0.5){ w[i] = w[i-1] - 1/Math.sqrt(n); } else { w[i] = w[i-1] + 1/Math.sqrt(n); } } return w; } // function to calculate the sample mean // x is an array of values function mean(x) { var n=x.length; var s=0; for(var i=0; i<n; i++){ s = s + x[i]; } return s/n; } // function to calculate sample variance // x is an array of values function variance(x) { var n=x.length; var xbar=mean(x); var s=0; for(var i=0; i<n; i++){ s = s + (x[i]-xbar)*(x[i]-xbar); } return s/(n-1); }
Rather interesting ideas…might you expand somewhat more? I’d love to include a portion of this post in my Ph. D thesis… existence exchange