/*	pl simulator.js	062008 hac	v1.0	071308 hac	v1.1	x, y std dev bias fix	Processes a form containg the mean and std dev of historical trades,	forecasts the next 100 trades based on the Axiom of the Small Edge (even prob of win/loss), 	and returns the URL for a google chart representing the trades*///polar version of =SQRT(-2*LN(A6))*COS(2*PI()*B6)function getrandomnumber3(count, r, winpct){	var flipper;	var i = 0;    var x1, x2, y1, y2;    var w = 999;  	while (i < count) { 	 		finished 	= false; 		flipper		= Math.random(); 			while (w >= 1.0) {					x1 		= 2.0 * Math.random() - 1.0;			x2 		= 2.0 * Math.random() - 1.0;			w  		= (x1 * x1) + (x2 * x2);		}				w  = Math.sqrt((-2.0 * Math.log(w))/w);		y1 = x1 * w;		y2 = x2 * w;				if (flipper >= 1 - winpct){			if (y1 >= 0) {				r[i] 	= y1; i++; finished = true;							} else if (y2 >= 0) {				r[i] 	= y2; i++; finished = true;							}		} else {			if (y1 < 0) {				r[i] = y1; i++; finished = true;							} else if (y2 < 0) {				r[i] = y2; i++; finished = true;							}				} 	 	}}//returns an array of count random numbers, normally distributed through winloss percentage//use a to simulate winpct and x or y to be the result if it has the same sign//for example, if winpct = 60, and a >=.6 and x is pos, then r[i] = xfunction getrandomnumber2(count, r, winpct){	var a, b, x, y 	= 0;	var i 			= 0;	var finished 	= false;	var flipper		= 0;	var wins 		= 0;	var losses 		= 0;		while (i < count) {			finished = false;			while (finished == false) {					flipper = Math.random();			a 		= Math.random();			b 		= Math.random();						//=SQRT(-2*LN(A6))*COS(2*PI()*B6)			x = Math.sqrt(-2*Math.log(a))*Math.cos(2*Math.PI*b);			y = Math.sqrt(-2*Math.log(a))*Math.sin(2*Math.PI*b);						if (flipper >= 1 - winpct){				//x/y bias?				if (x >= 0) {					r[i] 	= x; i++; finished = true;									} else if (y >= 0) {					r[i] 	= y; i++; finished = true;									}			} else {				if (x < 0) {					r[i] = x; i++; finished = true;									} else if (y < 0) {					r[i] = y; i++; finished = true;									}						}					}	}	}//returns an array of count normally distr random numbersfunction getrandomnumber(count, r) {	var a = 0;	var b = 0;	var x = 0;	var y = 0;		for (var i = 0; i < count;) {			a = Math.random();		b = Math.random();				//=SQRT(-2*LN(A6))*COS(2*PI()*B6)		x = Math.sqrt(-2*Math.log(a))*Math.cos(2*Math.PI*b);		y = Math.sqrt(-2*Math.log(a))*Math.sin(2*Math.PI*b);				r[i] 	= x; i++;		r[i] 	= y; i++;				/*if (window.console)			window.console.log(i.toString());*/	}}//Init simulation arraysfunction initsimulationarrays(sim, notrades, pctwins) {	var winpct = 0;		if (pctwins != "") {		winpct = parseFloat(pctwins);		if (winpct > 1) {			winpct = winpct/100;		}	}	for (var i = 0; i < sim.length; i++) {				sim[i] = new Array(notrades);				// fill the array w/ simulated, normally distributed random numbers		if (winpct == 0) {			getrandomnumber(sim[i].length, sim[i]);		} else 			getrandomnumber3(sim[i].length, sim[i], winpct);				}}//creates the trades in place from the // normally distributed random varsfunction buildtradeseries(mean, stddev, sim) {	var dx, z = 0;		for (var i = 0; i < sim.length; i++){		z = 0;		dx = 0; //running sum of trades			for (var j=0; j<sim[i].length; j++){					// start each series at 0			// otherwise add each trade			if (j > 0) {				z = sim[i][j];  //get the z for this trade							dx = dx + mean + (stddev * z); //calc the trade and add to sum of trades			}			sim[i][j] = dx;		}						/*if (window.console) {			window.console.log(sim[i][0].toString());			window.console.log(sim[i][sim[i].length-1].toString());		}*/			}	}//creates the trades in place from the // normally distributed random varsfunction buildtradeseriespct(avgwin, wlratio, sim) {	var dx, trade, z = 0;		for (var i = 0; i < sim.length; i++){		z = 0;		dx = 0; //running sum of trades			for (var j=0; j<sim[i].length; j++){					// start each series at 0			// otherwise add each trade			// the series is normally distributed so the bumps are a bit more realistic			if (j > 0) {				z		= sim[i][j];			//get the z for this trade				if (z > 0) {					z = 1				} else if (z <= 0) {					z = -1				}								//calc trades adjusting for w/l ratio				if (z > 0) 					trade	= avgwin * z				else if (z < 0)					trade	= avgwin/wlratio * z			 	else			 		trade= 0;							dx = dx + trade;				//running sum of trades			}			sim[i][j] = dx;		}						/*if (window.console) {			window.console.log(sim[i][0].toString());			window.console.log(sim[i][sim[i].length-1].toString());		}*/			}	}// returns best, worst and average series indicesfunction gettradeindices(sim, indices){	var avgindex	= 0;	var avgtrade	= new Array(sim.length);	// for sorting and finding avg series	var dx			= 0;	var lastentry 	= sim[0].length - 1;	var lookup		= false;	var max, maxindex	= 0;	var min, minindex	= 0;	// get max and min series	for (var i=0; i < sim.length; i++) {				if (sim[i][lastentry] > max) {						max 		= sim[i][lastentry];			maxindex 	= i;		} else if (sim[i][lastentry] < min) {						min			= sim[i][lastentry];			minindex	= i;		}				avgtrade[i]		= sim[i][lastentry];	// populate by net result	}		// find the median series	avgtrade.sort( function (a,b) { return a-b }); 	//sort min to max		dx = avgtrade[Math.floor(sim.length/2)+2];		//median series - NOTE: adjusted up to there's a funny downside bias...		lookup = false;	avgindex = 0;	while(!lookup) {		if (sim[avgindex][lastentry] == dx || avgindex >= sim.length) {			lookup = true;			} else {			avgindex++;		}	}		indices[0] = maxindex;	indices[1] = minindex;	indices[2] = avgindex;		/*if (window.console) {		window.console.log("max index: "+maxindex.toString());		window.console.log("min index: "+minindex.toString());		window.console.log("avg index: "+avgindex.toString());	}*/}//get trade stats// outputs 3 arrays - best, worst and averagefunction gettradestats(sim, stats){	var avgtrade	= new Array(sim.length);	var dx, i		= 0;	var indices		= new Array(3);	// for best, worst and average series	var lookup		= false;	var maxindex, minindex = 0;		// get indices for best, worst and average series	gettradeindices(sim, indices);		// set pointers to series	stats[0] = sim[indices[0]]; //best	stats[1] = sim[indices[1]]; //worst	stats[2] = sim[indices[2]]; //avg	}//get the max and min for each seriesfunction getseriesmaxmin(stats, max, min){	for (var i=0; i < stats.length; i++){			min[i] = 9999;		max[i] = -9999;				for (var j=0; j<stats[i].length; j++){						if (stats[i][j] > max[i]) {				max[i] = stats[i][j];			}			else if (stats[i][j] < min[i]) {				min[i] = stats[i][j];			}					}				/*if (window.console) {			window.console.log("max: " + max[i].toString());			window.console.log("min: " + min[i].toString());		}*/			}	}//scale series for charting//all we do here is truncate the median series to 1 decimal placefunction scale(stats, seriesindex) {	for (var j=0; j<stats[0].length; j++) {					stats[seriesindex][j] = stats[seriesindex][j].toFixed(1);	//one decimal place	}}//add white space, rounds max, min for plottingfunction addwhitespace(min, max, index){	min[index] = min[index] - Math.abs(.1 * min[index]);	min[index] = Math.floor(min[index]);	min[index] = min[index].toFixed(0);		max[index] = max[index] * 1.1;	max[index] = Math.ceil(max[index]);	max[index] = max[index].toFixed(0);}//encode chart urlfunction encodecharturl(stats, min, max, index){	var chartstr	= "";	var chs, chd, chds, cht, chtt, chco, chdl, chls	="";	var chxt, chxl, chg, chm	= "";	var dx, dy;		chs			= "chs=600x400";	    chd 		= "chd=t:" + stats[index].toString();        chds 		= "chds=" + min[index].toString() + "," + max[index].toString();        dx 			= Math.floor(stats[index].length/10);    dx			= dx.toFixed(0);    dy			= Math.floor((max[index] - min[index])/10);    dy			= dy.toFixed(0);    chg			= "chg=" + dx.toString() + "," + dy.toString() + ",1,5";				//grid - y not working        dx			= stats[index][stats[index].length-1].toString();    chm			= "chm=t" + dx + ",0000ff,0," + dx + ",13,1";							// marker - not working    cht			= "cht=lc";        chtt		= "chtt=Forecast";       	chco		= "chco=0000ff"; 				// colors    chdl		= "chdl=Median";				//legend    chls		= "chls=1,1,0";					// lines    chxt		= "chxt=x,y";					// axes        chxl		= "chxl=0:|0|" + stats[2].length.toString() + "|" 			    					+"1:|" + min[2].toString() + "|" + max[2].toString();	//axes scales        chartstr 	= "http://chart.apis.google.com/chart?" + chs + "&amp;" + chd + "&amp;" + chds + "&amp;"     					+ chco + "&amp;" /*+ chdl + "&amp;"*/ + chls + "&amp;" + chxt + "&amp;" + chxl + "&amp;"     					+ cht + "&amp;" + chtt + "&amp;" + chg /*+ "&amp;" + chm*/;		return chartstr;}//returns the url to fetch the chart from googlefunction getcharturl(stats){	var chs, chd, cht, chl, chartstr = "";	var min		= new Array(stats.length);	var max		= new Array(stats.length);		// get the max and min for each series	getseriesmaxmin(stats, max, min);		// scale the average series for charting	scale(stats, 2);	scale(min, 2);	scale(max, 2);		//add some white space to the median series max and min	addwhitespace(min, max, 2);	        //encode url from the median series for plotting    chartstr = encodecharturl(stats, min, max, 2);        if (window.console) {			window.console.log("url length: " + chartstr);	}        return chartstr;}function plsimulator (form) {	var dx;    var mean 	= form.mean.value;    var sim		= new Array(100);		//holds 100 simulations    var stats	= new Array(3);			//arrays of best, worst and median series    var stddev 	= form.stddev.value;    var t		= "";    	// init simulation array w/ size of test	initsimulationarrays(sim, 100, "");        //using the mean and std dev from the form, simulate trades    buildtradeseries(parseFloat(mean), parseFloat(stddev), sim);        // build out each trade series, accumulating each trade    gettradestats(sim, stats);        // build out the url to get a chart from google	charturl = getcharturl(stats);		// display the chart	t = "<img src=" + charturl + " />"			+ "<br /><br />"			+ "Forecast = $" + stats[2][stats[2].length-1].toString();	document.getElementById("chart").innerHTML = t;    }//for calling the simulator from a mac widget//widget uses 100 arrays of length 50 instead of length 100 in simulatorfunction plsimulatorpctwins (form) {	var avgwin		= form.avgwin.value;	var charturl	= ""	var dx;	var pctwins		= form.pctwins.value;    var sim			= new Array(100);		//holds 100 simulations    var stats		= new Array(3);			//arrays of best, worst and median series    var t			= "";    var wlratio		= form.wlratio.value;    	// init simulation array w/ size of test	initsimulationarrays(sim, 100, pctwins);        //using the mean and std dev from the form, simulate trades    buildtradeseriespct(parseFloat(avgwin), parseFloat(wlratio), sim);        // build out each trade series, accumulating each trade    gettradestats(sim, stats);        // build out the url to get a chart from google	charturl = getcharturl(stats);		// display the chart	t = "<img src=" + charturl + " />"			+ "<br /><br />"			+ "Forecast = $" + stats[2][stats[2].length-1].toString();	document.getElementById("chart").innerHTML = t;    }