

// The cumulative normal distribution function
function CND(X, debug)
{

var L, K;
var a1 = 0.31938153;
var a2 = -0.356563782;
var a3 = 1.781477937;
var a4 = -1.821255978;
var a5 = 1.330274429;

L = Math.abs(X);

K = 1 / (1 + 0.2316419 * L);

var ret  = 1 - 1 / Math.sqrt(2 * Math.PI) * Math.exp((-1) * Math.pow(L,2) / 2) * (a1 * K + a2 * Math.pow(K,2) + a3 * Math.pow(K,3) + a4 * Math.pow(K,4) + a5 * Math.pow(K,5));

if (X < 0)
{
	ret = 1 - ret;
};



return ret;

}; // end





// The generalized Black and Scholes formula
function GBlackScholes(CallPutFlag, S, X, T, r, b, v)
{

    var ret = 0;
    var d;


S = parseFloat(S);
X = parseFloat(X);
T = parseFloat(T);
r = parseFloat(r);
v = parseFloat(v);
b = parseFloat(b);




if(S.indexOf(",")==-1)	S=parseFloat(S);

else
{
	var str1=S.substring(0,S.indexOf(","))+'.'+S.substring(S.indexOf(",")+1);
	S=parseFloat(str1);
};

if(X.indexOf(",")==-1)	X=parseFloat(X);

else
{
	var str2=X.substring(0,X.indexOf(","))+'.'+X.substring(X.indexOf(",")+1);
	X=parseFloat(str2);
};


if(r.indexOf(",")==-1) 	r=parseFloat(r);

else
{
	var str3=r.substring(0,r.indexOf(","))+'.'+r.substring(r.indexOf(",")+1);
	r=parseFloat(str3);
};

if(v.indexOf(",")==-1)	v=parseFloat(v);

else
{
	var str4=v.substring(0,v.indexOf(","))+'.'+v.substring(v.indexOf(",")+1);
	v=parseFloat(str4);
};

if(T.indexOf(",")==-1)	T=parseFloat(T);

else
{
	var str5=T.substring(0,T.indexOf(","))+'.'+T.substring(T.indexOf(",")+1);
	T=parseFloat(str5);
};


// range check
if ((isNaN(S)) || (S <= 0))
{
	alert("Lütfen Spot Fiyatini Dogru Giriniz!");
	return Number.NaN;
};
if ((isNaN(X)) || (X <= 0))
{
	alert("Lütfen Kullanim Fiyatini Dogru Giriniz!");
	return Number.NaN;
};
if ((isNaN(r)) || (r < 0))
{
	alert("Lütfen Risksiz Faiz Oranini Dogru Giriniz!");
	return Number.NaN;
};
if (r == 0)
{
	alert("Dikkat: Risksiz Faiz Orani Sifir Olamaz");
	return Number.NaN;
};

if ((isNaN(v)) || (v < 0))
{
	alert("Lütfen Volatiliteyi Dogru Giriniz! ");
	return Number.NaN;
};
if (v == 0)
{
	alert("Dikkat: Volatilite Sifir Girilmis");
};



if ((isNaN(T)) || (T < 0))
{
	alert("Lütfen Vadeyi Dogru Giriniz!");
	return Number.NaN;
};







    var d1 = (Math.log(S / X) + ((r-b) + Math.pow(v,2) / 2) * T) / (v * Math.sqrt(T));
    var d2 = d1 - v * Math.sqrt(T);

    if (CallPutFlag == Call)
    {
	ret = S * Math.exp((-b) * T) * CND(d1) - X * Math.exp(-r * T) * CND(d2);
    }
    else // Put
    {
	ret = X * Math.exp(-r * T) * CND(-d2) - S * Math.exp((-b) * T) * CND(-d1)
    };

    

return ret;
};


// Rho for the generalized Black and Scholes formula
function GRho(CallPutFlag, S, X, T, r, b, v)
{
    

if (b == "uuu")
{
	 b = r;

	
};

	var ret = 0;        
	


S = parseFloat(S);
X = parseFloat(X);
T = parseFloat(T);
r = parseFloat(r);
v = parseFloat(v);
b = parseFloat(b);




var d1 = (Math.log(S / X) + ((r-b) + Math.pow(v,2) / 2) * T) / (v * Math.sqrt(T));
    var d2 = d1 - v * Math.sqrt(T);

    if (CallPutFlag == Call)
	 {
	
	    ret =  T * X * Math.exp(-r * T) * CND(d2);
		
	 }
	else // P
	{
	
		ret = -T * X * Math.exp(-r * T) * CND(-d2);
			
			};
	
	ret=ret*100000;
	ret=parseInt(ret);
	x=ret%10;
	if(x>=5)
	{
	y=10-x;
	ret=ret+y;
	}
	else	ret=ret-x;

	ret=ret/100000;
	return ret;
};

// Carry for the generalized Black and Scholes formula
function GCarry(CallPutFlag, S, X, T, r, b, v)
{    
    var d1 = (Math.log(S / X) + (b + Math.pow(v,2) / 2) * T) / (v * Math.sqrt(T));
	var ret = 0;

    if (CallPutFlag == Call)
	{
	ret = T * S * Math.exp((b - r) * T) * CND(d1);
	}
	else
	{
	ret = -T * S * Math.exp((b - r) * T) * CND(-d1);
	};
	return ret;
};


// Delta for the generalized Black and Scholes formula
function GDelta(CallPutFlag, S, X, T, r, b, v)
{
	
	var ret = 0;        
	

if (b == "uuu")
{
	 b = r;

	
};


S = parseFloat(S);
X = parseFloat(X);
T = parseFloat(T);
r = parseFloat(r);
v = parseFloat(v);
b = parseFloat(b);


var d1 = (Math.log(S / X) + ((r-b) + Math.pow(v,2) / 2) * T) / (v * Math.sqrt(T));




if (CallPutFlag == Call)
	 {
	ret = Math.exp((-b) * T) * CND(d1);



	 }
	 else // "P"
	 {
	ret = Math.exp((-b) * T) * (CND(d1) - 1);
	 };
   
ret=ret*100000;
	ret=parseInt(ret);
	x=ret%10;
	if(x>=5)
	{
	y=10-x;
	ret=ret+y;
	}
	else	ret=ret-x;

	ret=ret/100000;
	return ret;




	
};


// Gamma for the generalized Black and Scholes formula
function GGamma(S, X, T, r, b, v)
{    
    

	var ret = 0;        
	

if (b == "uuu")
{
	 b = r;

	
};

S = parseFloat(S);
X = parseFloat(X);
T = parseFloat(T);
r = parseFloat(r);
v = parseFloat(v);
b = parseFloat(b);





var d1=  (Math.log(S / X) + ((r-b) + Math.pow(v,2) / 2) * T) / (v * Math.sqrt(T));
    ret= (Math.exp((-b) * T) * ND(d1) / (S * v * Math.sqrt(T)));

ret=ret*100000;
	ret=parseInt(ret);
	x=ret%10;
	if(x>=5)
	{
	y=10-x;
	ret=ret+y;
	}
	else	ret=ret-x;

	ret=ret/100000;
	return ret;



};


// Theta for the generalized Black and Scholes formula
function GTheta(CallPutFlag, S, X, T, r, b, v)
{
   

if (b == "uuu")
{
	 b = r;

	
};
 

var ret = 0;        
	
S = parseFloat(S);
X = parseFloat(X);
T = parseFloat(T);
r = parseFloat(r);
v = parseFloat(v);
b = parseFloat(b);

var d1=  (Math.log(S / X) + ((r-b) + Math.pow(v,2) / 2) * T) / (v * Math.sqrt(T));


var d2 = d1 - v * Math.sqrt(T);
	

    if (CallPutFlag == Call)
	 {
	ret = (-S * Math.exp((-b) * T) * ND(d1) * v / (2 * Math.sqrt(T)) + (b) * S * Math.exp((-b) * T) * CND(d1) - r * X * Math.exp(-r * T) * CND(d2))/365;

	 }
	else // P
	{
	ret = (-S * Math.exp((-b) * T) * ND(d1) * v / (2 * Math.sqrt(T)) - (b) * S * Math.exp((-b) * T) * CND(-d1) + r * X * Math.exp(-r * T) * CND(-d2))/365;
	};
	
ret=ret*100000;
	ret=parseInt(ret);
	x=ret%10;
	if(x>=5)
	{
	y=10-x;
	ret=ret+y;
	}
	else	ret=ret-x;

	ret=ret/100000;
	return ret;




};






// Vega for the generalized Black and Scholes formula
function GVega(S, X, T, r, b, v)
{
	

var ret = 0;        
	
if (b == "uuu")
{
	 b = r;

	
};

S = parseFloat(S);
X = parseFloat(X);
T = parseFloat(T);
r = parseFloat(r);
v = parseFloat(v);
b = parseFloat(b);





var d1 = (Math.log(S / X) + ((r-b) + Math.pow(v,2) / 2) * T) / (v * Math.sqrt(T));
   ret= (S * Math.exp((-b) * T) * ND(d1) * Math.sqrt(T));


ret=ret*100000;
	ret=parseInt(ret);
	x=ret%10;
	if(x>=5)
	{
	y=10-x;
	ret=ret+y;
	}
	else	ret=ret-x;

	ret=ret/100000;
	return ret;



};











// The normal distribution function
function ND(X)
{
    return ( 1 / Math.sqrt(2 * Math.PI) * Math.exp(-Math.pow(X,2) / 2));
};

function Sgn(X)
{
	if (X > 0) return 1
	else if (X < 0) return -1
	else return 0;
};

// The cumulative bivariate normal distribution function
function CBND(a, b, rho)
{

	var ret = 0;
	var X = new Array(0.24840615, 0.39233107, 0.21141819, 0.03324666, 0.00082485334);
	var y = new Array(0.10024215, 0.48281397, 1.0609498, 1.7797294, 2.6697604);

	var a1 = a / Math.sqrt(2 * (1 - Math.pow(rho,2)));
	var b1 = b / Math.sqrt(2 * (1 - Math.pow(rho,2)));

	if ((a <=0) && (b <= 0) && (rho <= 0))
	{
		var Sum = 0;
		for(var i = 0; i < 5; i++)
			for(var j = 0; j <5; j++)
				{
					Sum     += X[i] * X[j] * Math.exp(a1 * (2 * y[i] - a1)
							+ b1 * (2 * y[j] - b1) + 2 * rho * (y[i] - a1) * (y[j] - b1));
				};
		ret = Math.sqrt(1 - Math.pow(rho,2)) / Math.PI * Sum;
	}
	else if ((a <= 0) && (b >= 0)  && (rho >=0))
	{
	ret = CND(a) - CBND(a, -b, -rho);
	}
	else if((a>=0) && (b <=0) && (rho >=0))
	{
	ret = CND(b) - CBND(-a, b, -rho);
	}
	else if ((a >=0) && (b >=0) && (rho <=0))
	{
	ret = CND(a) + CND(b) - 1 + CBND(-a, -b, rho);
	}
	else if (a * b * rho > 0)
	{
      var rho1 = (rho * a - b) * Sgn(a) / Math.sqrt(Math.pow(a,2) - 2 * rho * a * b + Math.pow(b,2));
      var rho2 = (rho * b - a) * Sgn(b) / Math.sqrt(Math.pow(a,2) - 2 * rho * a * b + Math.pow(b,2));
      var delta = (1 - Sgn(a) * Sgn(b)) / 4;
      ret = CBND(a, 0, rho1) + CBND(b, 0, rho2) - delta;
	}
	return ret;
};


// Black Scholes Formula
function BlackScholes(CallPutFlag, S, X, T, r, v, b,rw)
{
var d1, d2, ret;

if (b == "uuu")
{
	 b = r;

	
};




if(S.indexOf(",")==-1)	S=parseFloat(S);

else
{
	var str1=S.substring(0,S.indexOf(","))+'.'+S.substring(S.indexOf(",")+1);
	S=parseFloat(str1);
};

if(X.indexOf(",")==-1)	X=parseFloat(X);

else
{
	var str2=X.substring(0,X.indexOf(","))+'.'+X.substring(X.indexOf(",")+1);
	X=parseFloat(str2);
};


if(r.indexOf(",")==-1) 	r=parseFloat(r);

else
{
	var str3=r.substring(0,r.indexOf(","))+'.'+r.substring(r.indexOf(",")+1);
	r=parseFloat(str3);
};

if(v.indexOf(",")==-1)	v=parseFloat(v);

else
{
	var str4=v.substring(0,v.indexOf(","))+'.'+v.substring(v.indexOf(",")+1);
	v=parseFloat(str4);
};

if(T.indexOf(",")==-1)	T=parseFloat(T);

else
{
	var str5=T.substring(0,T.indexOf(","))+'.'+T.substring(T.indexOf(",")+1);
	T=parseFloat(str5);
};



if(b.indexOf(",")==-1) 	b=parseFloat(b);

else
{
	var str3=b.substring(0,b.indexOf(","))+'.'+b.substring(b.indexOf(",")+1);
	b=parseFloat(str3);
};





// range check
if ((isNaN(S)) || (S <= 0))
{
	alert("Lütfen Spot Fiyatini Dogru Giriniz!");
	return Number.NaN;
};
if ((isNaN(X)) || (X <= 0))
{
	alert("Lütfen Kullanim Fiyatini Dogru Giriniz!");
	return Number.NaN;
};
if ((isNaN(r)) || (r < 0))
{
	alert("Lütfen Risksiz Faiz Oranini Dogru Giriniz!");
	return Number.NaN;
};
if (r == 0)
{
	alert("Dikkat: Risksiz Faiz Orani Sifir Olamaz");
	return Number.NaN;
};

if ((isNaN(v)) || (v < 0))
{
	alert("Lütfen Volatiliteyi Dogru Giriniz! ");
	return Number.NaN;
};
if (v == 0)
{
	alert("Dikkat: Volatilite Sifir Girilmis");
};



if ((isNaN(T)) || (T < 0))
{
	alert("Lütfen Vadeyi Dogru Giriniz!");
	return Number.NaN;
};



if ((isNaN(b)) || (b < 0))
{
	alert("Lütfen Temettü Oranini Dogru Giriniz!");
	return Number.NaN;
};





if (rw != null)
{
	d.write('<BR>calculate log(S / X): ' + Math.log(S / X) + '</BR>');
	d.write('<BR>calculate v^2: ' + Math.pow(v,2)  + '</BR>');
	d.write('<BR>calculate (r + v^2) / 2) * T: ' + ( r + Math.pow(v,2) / 2) * T  + '</BR>');
	d.write('<BR>calculate (v * sqrt(T)): ' + (v * Math.sqrt(T)) + '</BR>');
};








d1 = (Math.log(S / X) + ((r-b) + Math.pow(v,2) / 2) * T) / (v * Math.sqrt(T));
d2 = d1 - v * Math.sqrt(T);

if (rw != null)
{
	d.write('<BR>result d1: ' + d1 + '</BR>');
	d.write('<BR>result d2: ' + d2 + '</BR>');
};

if (CallPutFlag == Call)
{
	ret = S * Math.exp((-b) * T)*CND(d1, rw) - X * Math.exp(-r * T) * CND(d2, rw);
}
else if (CallPutFlag == Put)
{
	ret  = X * Math.exp(-r * T) * CND(-d2, rw) - S * Math.exp((-b) * T)*CND(-d1, rw);
}
else
{
	alert("Flag must be Call or Put: " + CallPutFlag );
};	
	ret=ret*100000;
	ret=parseInt(ret);
	x=ret%10;
	if(x>=5)
	{
	y=10-x;
	ret=ret+y;
	}
	else	ret=ret-x;

	ret=ret/100000;
	return ret;

}; // end








// Futures Hesaplama
function Futures(CallPutFlag, S, X, T, r, b,v,rw)
{



if (b == "uuu")
{
	 b = r;

	
};


var ret;




if(S.indexOf(",")==-1)	S=parseFloat(S);

else
{
	var str1=S.substring(0,S.indexOf(","))+'.'+S.substring(S.indexOf(",")+1);
	S=parseFloat(str1);
};



if(r.indexOf(",")==-1) 	r=parseFloat(r);

else
{
	var str3=r.substring(0,r.indexOf(","))+'.'+r.substring(r.indexOf(",")+1);
	r=parseFloat(str3);
};



if(T.indexOf(",")==-1)	T=parseFloat(T);

else
{
	var str5=T.substring(0,T.indexOf(","))+'.'+T.substring(T.indexOf(",")+1);
	T=parseFloat(str5);
};


// range check
if ((isNaN(S)) || (S <= 0))
{
	alert("Lütfen Spot Fiyatini Dogru Giriniz!");
	return Number.NaN;
};

if ((isNaN(r)) || (r < 0))
{
	alert("Lütfen Risksiz Faiz Oranini Dogru Giriniz!");
	return Number.NaN;
};
if (r == 0)
{
	alert("Dikkat: Risksiz Faiz Orani Sifir Olamaz");
	return Number.NaN;
};



if ((isNaN(T)) || (T < 0))
{
	alert("Lütfen Vadeyi Dogru Giriniz!");
	return Number.NaN;
};









ret=b;

	
	return ret;

}; // end
















//----------------------------------------------------------------------------------------------
// option on option from 2.5.00
//----------------------------------------------------------------------------------------------
function optionOnOption(callPutFlag, assetprice, strikeprice, strikepriceUnderlying, timeToMaturity, timeToMaturityUnderlying, zinssatz, vola, carry, rw)
{

	var callPutFlagUnderlying;
	var rho, I, y1, y2, z1, z2, value;

	if (rw != null)
	{
        var d = rw.document;

        d.write('<BR><INPUT TYPE="button" VALUE="Close Window" onClick="self.close()"></BR>');

        d.write('<BR>Input  : ' + callPutFlag + '</BR>');
        d.write('<BR>Input S: ' + assetprice + '(Asset)</BR>');
        d.write('<BR>Input X: ' + strikeprice + '(Strike)</BR>');
        d.write('<BR>Input X2: ' + strikepriceUnderlying+ '(Strike of Underlying)</BR>');
        d.write('<BR>Input T: ' + timeToMaturity + '(Time)</BR>');
        d.write('<BR>Input T2: ' + timeToMaturityUnderlying + '(Time of Underlying)</BR>');
        d.write('<BR>Input r: ' + zinssatz + '(Interest)</BR>');
        d.write('<BR>Input b: ' + carry+ '(Cost of Carry)</BR>');
        d.write('<BR>Input v: ' + vola + '(Vola)</BR>');
	};

	assetprice = parseFloat(assetprice);
	strikeprice = parseFloat(strikeprice );
	strikepriceUnderlying= parseFloat(strikepriceUnderlying);
	timeToMaturity = parseFloat(timeToMaturity );
	timeToMaturityUnderlying = parseFloat(timeToMaturityUnderlying );
	zinssatz = parseFloat(zinssatz );
	carry= parseFloat(carry);
	vola = parseFloat(vola);


	if (timeToMaturityUnderlying == timeToMaturity)
	{
		alert("time to maturity incorrect.");
		return NaN;
	};

	if ((callPutFlag == "Call on Call") || (callPutFlag == "Put on Call"))
		callPutFlagUnderlying = Call
	else
		callPutFlagUnderlying = Put;

        if (rw != null) d.write('<BR>underlying type: ' + callPutFlagUnderlying + '</BR>');

	var I = CriticalValueOptionsOnOptions(callPutFlagUnderlying, strikepriceUnderlying, strikeprice, timeToMaturityUnderlying - timeToMaturity, zinssatz, carry, vola, rw);

        if (rw != null) d.write('<BR> critical value: ' + I + '</BR>');

	var rho = Math.sqrt(timeToMaturity/timeToMaturityUnderlying);

        if (rw != null) d.write('<BR> rho: ' + rho + '</BR>');

	y1 =  (Math.log(assetprice / I) + (carry + Math.pow(vola,2) / 2) * timeToMaturity) / (vola * Math.sqrt(timeToMaturity));

        if (rw != null) d.write('<BR> y1: ' + y1 + '</BR>');

        y2 = y1 - vola * Math.sqrt(timeToMaturity);

        if (rw != null) d.write('<BR> y2: ' + y2 + '</BR>');

        z1 = (Math.log(assetprice / strikepriceUnderlying) + (carry + Math.pow(vola,2) / 2) * timeToMaturityUnderlying) / (vola * Math.sqrt(timeToMaturityUnderlying));

        if (rw != null) d.write('<BR> z1: ' + z1 + '</BR>');

        z2 = z1 - vola * Math.sqrt(timeToMaturityUnderlying);

        if (rw != null) d.write('<BR> z2: ' + z2 + '</BR>');        

    if (callPutFlag == "Call on Call")
    {

        if (rw != null) rw.document.write('<BR>CBND(' + z1 + ',' + y1 + ',' + rho + ')= ' + CBND(z1, y1, rho) + '</BR>');
        if (rw != null) rw.document.write('<BR>CBND(' + z2 + ',' + y2 + ',' + rho + ')= ' + CBND(z2, y2, rho) + '</BR>');
        if (rw != null) rw.document.write('<BR>CND (' + y2 + ')= ' + CND(y2) + '</BR>');

        var A = (assetprice * Math.exp((carry - zinssatz) * timeToMaturityUnderlying) * CBND(z1, y1, rho));
        var B = ((strikepriceUnderlying * Math.exp((-1) * zinssatz * timeToMaturityUnderlying) * CBND(z2, y2, rho)));
        var C = (strikeprice * Math.exp(-zinssatz  * timeToMaturity) * CND(y2));

        value = A - B - C;

        //OptionsOnOptions =                    S * Exp((b - r) * T2) * CBND(z1, y1, rho) - X1 * Exp(-r * T2) * CBND(z2, y2, rho) - X2 * Exp(-r * t1) * CND(y2)
    }
    else if (callPutFlag == "Put on Call")
        value = strikepriceUnderlying * Math.exp(-zinssatz * timeToMaturityUnderlying) * CBND(z2, -y2, -rho) - assetprice * Math.exp((carry - zinssatz) * timeToMaturityUnderlying) * CBND(z1, -y1, -rho) + strikeprice * Math.exp(-zinssatz * timeToMaturity) * CND(-y2)
    else if(callPutFlag == "Call on Put")
        value = strikepriceUnderlying * Math.exp(-zinssatz  * timeToMaturityUnderlying) * CBND(-z2, -y2, rho) - assetprice * Math.exp((carry - zinssatz) * timeToMaturityUnderlying) * CBND(-z1, -y1, rho) - strikeprice * Math.exp(-zinssatz  * timeToMaturity) * CND(-y2)
    else if (callPutFlag == "Put on Put")
        value = assetprice * Math.exp((carry - zinssatz) * timeToMaturityUnderlying) * CBND(-z1, y1, -rho) - strikepriceUnderlying * Math.exp(-zinssatz  * timeToMaturityUnderlying) * CBND(-z2, y2, -rho) + Math.exp(-zinssatz * timeToMaturity) * strikeprice * CND(y2);

    if(rw != null)
    {
        d.write('<BR>option on option value: ' + value + '</BR>');
        d.write('<BR><INPUT TYPE="button" VALUE="Close Window" onClick="self.close()"></BR>');
    };
    return value;

};

//----------------------------------------------------------------------------------------------
// option on option from 2.5.00
// Calculation of critical price options on options
//----------------------------------------------------------------------------------------------
function CriticalValueOptionsOnOptions(CallPutFlag, X1, X2, T, r, b, v, debug)
{
	var Si = X1;
	if (debug!= null)
	{
         debug.document.write('<BR> CriticalValueOptionsOnOptions<BR>');
		 debug.document.write('Input X1: ' + X1 + '</BR>');
		 debug.document.write('Input X2: ' + X2 + '</BR>');
		 debug.document.write('Input T : ' + T  + '</BR>');
		 debug.document.write('Input r : ' + r  + '</BR>');
		 debug.document.write('Input b : ' + b  + '</BR>');
		 debug.document.write('Input v : ' + v  + '</BR>');
	};


	var ci = GBlackScholes(CallPutFlag, Si, X1, T, r, b, v, null);
	var di = GDelta(CallPutFlag, Si, X1, T, r, b, v);

	if (debug!= null)
	{
	 debug.document.write(' start - GDelta: ' + di + ' GBlackScholes: ' + ci + '</BR>');
        };

	var epsilon = 0.000000001;
	var step = 0;
        var criterium = Math.abs(ci - X2);

    // Newton-Raphson algorithm
    while (criterium > epsilon)
	{
        Si -= (ci - X2) / di;
        step++;

        ci = GBlackScholes(CallPutFlag, Si, X1, T, r, b, v, null);
        di = GDelta(CallPutFlag, Si, X1, T, r, b, v);

	     if (debug!= null)
			{
			 debug.document.write('Newton-Raphson after step ' + step + ': Si ' + Si + ' criterium ' + criterium);
			 debug.document.write(' neu - GDelta: ' + di + ' GBlackScholes: ' + ci + '</BR>');
			};
        criterium = Math.abs(ci - X2);
	};
	return Si;
};

//----------------------------------------------------------------------------------------------
// binominal tree from 5.5.00
// Calculation of a binominal tree
//----------------------------------------------------------------------------------------------
function CRR_binominal_tree(CallPutFlag, EuAmFlag, S, X, T, r, b, v, n, debug)
{

    var ret = 0;
    var d = null;

if (debug != null)
{
	d = debug.document;

	d.write('<BR>----Binominal Tree-------</BR>');
	d.write('<BR>Input  : ' + CallPutFlag + '</BR>');
	d.write('<BR>Input  : ' + EuAmFlag + '</BR>');	
	d.write('<BR>Input S: ' + S + '(Asset)</BR>');
	d.write('<BR>Input X: ' + X + '(Strike)</BR>');
	d.write('<BR>Input T: ' + T + '(Time)</BR>');
	d.write('<BR>Input r: ' + r + '(Interest)</BR>');
	d.write('<BR>Input v: ' + v + '(Vola)</BR>');
	d.write('<BR>Input b: ' + b + '(Cost of Carry)</BR>');
	d.write('<BR>Input n: ' + n + '(Time Steps)</BR>');	
};
S = parseFloat(S);
X = parseFloat(X);
T = parseFloat(T);
r = parseFloat(r);
v = parseFloat(v);
b = parseFloat(b);
n = parseFloat(n);


// range check
if ((isNaN(S)) || (S <= 0))
{
	alert("Asset invalid: " + S);
	return Number.NaN;
};
if ((isNaN(X)) || (X <= 0))
{
	alert("Strike price invalid!");
	return Number.NaN;
};
if ((isNaN(r)) || (r < 0))
{
	alert("Interest rate invalid!");
	return Number.NaN;
};
if (r == 0)
{
	alert("Warning: interest rate sero.");
};
if ((isNaN(v)) || (v < 0))
{
	alert("volatility invalid: " + v);
	return Number.NaN;
};
if (v == 0)
{
	alert("Warning: volatility sero.");
};

if ((isNaN(b)) || (b <= 0))
{
	alert("Cost of Carry invalid!");
	return Number.NaN;
};
	
if ((isNaN(n)) || (n <= 0))
{
	alert(n + "number of steps invalid!");
	return Number.NaN;
};
	
var OptionValue = new Array(n + 1);	

	var z;
	if (CallPutFlag == "Call")
	{
		z = 1;
	}
	else
	{
		z = -1;
	};

	var dt = T / n;    
    var u = Math.exp(v * Math.sqrt(dt));
    var q = 1 / u;
    var p = (Math.exp(b * dt) - q) / (u - q);
    var Df = Math.exp(-r * dt);


if (debug)
{
	d.write('<BR>dt = T / n  = ' + dt + '</BR>');
	d.write('<BR>u = e^(v * sqr(dt))  = ' + u + '</BR>');	
	d.write('<BR>q = 1 / u  = ' + q + '</BR>');		
	d.write('<BR>p = (e^(b*dt) - q) / (u - q)  = ' + p + '</BR>');		
	d.write('<BR>Df = e^(-r * dt)  = ' + Df + '</BR>');	
};
    
    for(var i = 0; i <= n; i++)
	{
         OptionValue[i] = Math.max(0, z * (S * Math.pow(u,i) * Math.pow(q,n - i) - X));
		 if (debug)
		 {
			d.write('<BR>OptionValue[' + i + '] = ' +  OptionValue[i] + '</BR>');			 
		 };
	};
    

	for(var j = n-1; j >= 0; j--)    
	{
		 if (debug)
		 {
			d.write('<BR>------Step' + j + '------------------</BR>');				 
		 };
		for (var i = 0; i <= j; i++)
		{
            if (EuAmFlag == "European")
			{
				 
                OptionValue[i] = (p * OptionValue[i + 1] + (1 - p) * OptionValue[i]) * Df;
				 if (debug)
		 		 {
						d.write('<BR>OptionValue[' + i + '] = ' +  OptionValue[i] + '</BR>');				 
				 };				
			}
			else
			{
			
				var x1 = (z * (S * Math.pow(u,i) * Math.pow(q,Math.abs(i - j)) - X));
				var x2 = (p * OptionValue[i + 1] + (1 - p) * OptionValue[i])* Df;
			
                OptionValue[i] = Math.max(x1,x2);
				 if (debug)
		 		 {
						d.write('<BR>x1 = ' +  x1 + '</BR>');
						d.write('<BR>x2 = ' +  x2 + '</BR>');						
						d.write('<BR>OptionValue[' + i + '] = ' +  OptionValue[i] + '</BR>');
				 };				
							
			};
		};
	};
    return OptionValue[0];
};

//----------------------------------------------------------------------------------------------
// trinomial tree from 5.5.00
// Calculation of a binominal tree
//----------------------------------------------------------------------------------------------
function trinomial_tree(CallPutFlag, EuAmFlag, S, X, T, r, b, v, n, debug)
{

    var ret = 0;
    var d = null;

if (debug != null)
{
	d = debug.document;

	d.write('<BR>----Binominal Tree-------</BR>');
	d.write('<BR>Input  : ' + CallPutFlag + '</BR>');
	d.write('<BR>Input  : ' + EuAmFlag + '</BR>');	
	d.write('<BR>Input S: ' + S + '(Asset)</BR>');
	d.write('<BR>Input X: ' + X + '(Strike)</BR>');
	d.write('<BR>Input T: ' + T + '(Time)</BR>');
	d.write('<BR>Input r: ' + r + '(Interest)</BR>');
	d.write('<BR>Input v: ' + v + '(Vola)</BR>');
	d.write('<BR>Input b: ' + b + '(Cost of Carry)</BR>');
	d.write('<BR>Input n: ' + n + '(Time Steps)</BR>');	
};
S = parseFloat(S);
X = parseFloat(X);
T = parseFloat(T);
r = parseFloat(r);
v = parseFloat(v);
b = parseFloat(b);
n = parseFloat(n);


// range check
if ((isNaN(S)) || (S <= 0))
{
	alert("Asset invalid: " + S);
	return Number.NaN;
};
if ((isNaN(X)) || (X <= 0))
{
	alert("Strike price invalid!");
	return Number.NaN;
};
if ((isNaN(r)) || (r < 0))
{
	alert("Interest rate invalid!");
	return Number.NaN;
};
if (r == 0)
{
	alert("Warning: interest rate sero.");
};
if ((isNaN(v)) || (v < 0))
{
	alert("volatility invalid: " + v);
	return Number.NaN;
};
if (v == 0)
{
	alert("Warning: volatility sero.");
};

if ((isNaN(b)) || (b <= 0))
{
	alert("Cost of Carry invalid!");
	return Number.NaN;
};
	
if ((isNaN(n)) || (n <= 0))
{
	alert(n + "number of steps invalid!");
	return Number.NaN;
};
	
var OptionValue = new Array(2 * n + 1);	

    
	var z;
	if (CallPutFlag == "Call")
	{
		z = 1;
	}
	else
	{
		z = -1;
	};

	var dt = T / n;    
    var u = Math.exp(v * Math.sqrt(2 * dt));
    var q = Math.exp((-1) * v * Math.sqrt(2 * dt));
    var pu = Math.pow((Math.exp(b * dt / 2) - Math.exp(-v * Math.sqrt(dt / 2))) / (Math.exp(v * Math.sqrt(dt / 2)) - Math.exp(-v * Math.sqrt(dt / 2))), 2);
    var pd = Math.pow((Math.exp(v * Math.sqrt(dt / 2)) - Math.exp(b * dt / 2)) / (Math.exp(v * Math.sqrt(dt / 2)) - Math.exp(-v * Math.sqrt(dt / 2))), 2);
    var pm = 1 - pu - pd;
    var Df = Math.exp(-r * dt);


if (debug)
{
	d.write('<BR>dt = T / n  = ' + dt + '</BR>');
	d.write('<BR>u = e^(v * sqr(2 * dt))  = ' + u + '</BR>');	
	d.write('<BR>q = e^(-v * sqr(2 * dt))  = ' + q + '</BR>');		
	d.write('<BR>pu = <BR>((e^(b * dt / 2) - e^(-v * Sqr(dt / 2))) / (e^(v * Sqr(dt / 2)) - e^(-v * Sqr(dt / 2)))) ^ 2<BR>      = ' + pu + '</BR>');		
	d.write('<BR>pd = <BR>((e^(v * Sqr(dt / 2)) - e^(b * dt / 2)) / (e^(v * Sqr(dt / 2)) - e^(-v * Sqr(dt / 2)))) ^ 2<BR>      = ' + pd + '</BR>');		
	d.write('<BR>pm = 1 - pu - pd  = ' + pm + '</BR>');		
	d.write('<BR>Df = e^(-r * dt)  = ' + Df + '</BR>');	
};
    
    
    for(var i = 0;i <= (2 * n); i++)
	{
         OptionValue[i] = Math.max(0, z * (S * Math.pow(u, Math.max(i - n, 0)) * Math.pow(q, Math.max(n * 2 - n - i, 0)) - X));
		 if (debug)
		 {
			d.write('<BR>OptionValue[' + i + '] = ' +  OptionValue[i] + '</BR>');			 
		 };
    };

	for (var j = n-1; j >=0; j--)
	{
		 if (debug)
		 {
			d.write('<BR>------Step' + j + '------------------</BR>');				 
		 };
         for (var i = 0;i <= (j * 2); i++)
		 {
            if (EuAmFlag == "European")
			{				 
                OptionValue[i] = (pu * OptionValue[i + 2] + pm * OptionValue[i + 1] + pd * OptionValue[i]) * Df;
				 if (debug)
		 		 {
						d.write('<BR>OptionValue[' + i + '] = ' +  OptionValue[i] + '</BR>');				 
				 };								
			}
			else
			{
				var x1 = (z * (S * Math.pow(u, Math.max(i - j, 0)) * Math.pow(q, Math.max(j * 2 - j - i, 0)) - X));
				var x2 = (pu * OptionValue[i + 2] + pm * OptionValue[i + 1] + pd * OptionValue[i]) * Df;
                OptionValue[i] = Math.max(x1,x2);
				 if (debug)
		 		 {
						d.write('<BR>x1 = ' +  x1 + '</BR>');
						d.write('<BR>x2 = ' +  x2 + '</BR>');						
						d.write('<BR>OptionValue[' + i + '] = ' +  OptionValue[i] + '</BR>');
				 };								
			};
		  }; // for i
    }; // for j
    return OptionValue[0];
};
