public void NonFlatRates() { ZeroCurve myZero = new ZeroCurve(); myZero.Ratepoints = 2; myZero.MakeArrays(); myZero.SetR(0, 0.05, 1.0); myZero.SetR(1, 0.075, 2.0); //test interpolation priot to point 0 double tTime = 0.5; double val = myZero.LinInterp(tTime); Assert.IsTrue(val > 0.0499999999); Assert.IsTrue(val < 0.050000001); //test interpolation prior to point 1 tTime = 1.5; val = myZero.LinInterp(tTime); Assert.IsTrue(val > 0.062499999999); Assert.IsTrue(val < 0.06250000001); //test interpolation post point 1 tTime = 2.5; val = myZero.LinInterp(tTime); Assert.IsTrue(val > 0.07499999999); Assert.IsTrue(val < 0.0750000001); //test forward rates //test interpolation priot to point 0 double tl = 0.25; tTime = 0.5; val = myZero.ForwardRate(tl, tTime); Assert.IsTrue(val > 0.0499999999); Assert.IsTrue(val < 0.050000001); //test interpolation prior to point 1 tTime = 1.5; val = myZero.ForwardRate(tl, tTime); Assert.IsTrue(val > 0.06499999); /// 0.065 Assert.IsTrue(val < 0.065000001); //test interpolation post point 1 tTime = 2.5; val = myZero.ForwardRate(tl, tTime); ///0.077778 Assert.IsTrue(val > 0.0777777); Assert.IsTrue(val < 0.07777778); }
//public spotStar private void MakeDivArray(ZeroCurve myZero, DivList myDivList) { double dt = Tau / Gridsteps; if ((myDivList != null) && (myZero != null)) { for (int idx = 0; idx < Gridsteps; idx++) { double temp = 0.0; for (int kdx = 0; kdx < myDivList.Divpoints; kdx++) { if ((myDivList.GetT(kdx) > idx * dt) && (myDivList.GetT(kdx) < Tau)) { temp += myDivList.GetD(kdx) * Math.Exp(-myZero.ForwardRate(idx * dt, myDivList.GetT(kdx)) * (myDivList.GetT(kdx) - idx * dt)); } } set_div(idx, temp, dt * idx); } } else //missing either div or zero, load in 0 for _div on tree { for (int idx = 0; idx <= Gridsteps; idx++) { set_div(idx, 0.0, dt * idx); } } }
//compute Sstar for the BC's private double ComputeDiscDiv(double tTemp, double T, ZeroCurve myZero, DivList mydiv) { double temp = 0.0; for (int idx = 0; idx < mydiv.Divpoints; idx++) { if ((tTemp < mydiv.GetT(idx)) && (mydiv.GetT(idx) < T)) { double fwdRate = myZero.ForwardRate(tTemp, mydiv.GetT(idx)); temp += mydiv.GetD(idx) * Math.Exp(-fwdRate * (mydiv.GetT(idx) - tTemp)); } } return temp; }
//fill grid forward rates private void FillForwardRate(ZeroCurve myZero) { double dt = Tau / Gridsteps; if (myZero != null) { if (flatFlag) { flatRate = myZero.LinInterp(Tau); } for (int idx = 0; idx < Gridsteps; idx++) { SetR(idx, flatFlag ? flatRate : myZero.ForwardRate(idx * dt, (idx + 1) * dt)); } } }
/// <summary> /// main pricer /// </summary> /// <param name="myZero"></param> /// <param name="myDiv"></param> /// <param name="greeks"></param> /// <param name="bGreeks"></param> /// <returns></returns> public double Pricer(ZeroCurve myZero, DivList myDiv, ref double[] greeks, bool bGreeks) { _x = new List<double>(); _v = new List<double>(); double tTemp = T; //real time double tau = 0.0; //backward time double dtnom = T / (double) NTsteps; double dt = dtnom; double tempInt=0.0; //start the pricer CreateGrid(); TerminalCondition(); while( tau < T) { //set the increment double t1 = tTemp - dtnom; t1 = (t1 >= 0.0) ? t1 : 0.0; //make sure t1 >= 0.0 double divPay = 0.0; dt = CheckBetweenDiv(t1, tTemp, ref divPay, myDiv); //compute the real time and backward time tau tTemp -= dt; tau = T - tTemp; //compute the increment forward rate _domR = myZero.ForwardRate(tTemp, tTemp + dt); _forR = 0.0; //compute the forward rate from real time tTemp to expiry for the BC'c double domRbc = myZero.ForwardRate(tTemp, T); //compute discounted dividends for the bc's double DiscDiv = ComputeDiscDiv(tTemp, T, myZero, myDiv); //save the value at the spot for use in theta calcuation int nKeyInt = (int)((Math.Log(Spot) - XL) / _dx); double fracInt = (Math.Log(Spot) - _x[nKeyInt]) / (_x[nKeyInt + 1] - _x[nKeyInt]); tempInt = _v[nKeyInt] * (1.0 - fracInt) + _v[nKeyInt + 1] * fracInt; //get the fwd _lnfwd = Math.Log(GetATMfwd(myZero, myDiv, tTemp)); //build the matrix OneStepSetUp(dt, tTemp); //compute the q vec MakeQVec(); if (SStyle.ToUpper().Equals("E")) { // set the exlicit BC _v[0] = MakeLowerBC(tau, Math.Exp(_x[0]), domRbc, DiscDiv); _v[Steps - 1] = MakeUpperBC(tau, Math.Exp(_x[Steps - 1]), domRbc, DiscDiv); SORmethod(); //subract from q(1) and q(_steps-2) for explicit BC //'_q[1] -= _SubDiagL[0] * _v[0]; //'_q[_msteps - 1] -= _SuperDiagL[_steps - 1] * _v[_steps - 1]; //this commented out info is used for the zero curvature condition //_DiagL[1] += 2.0 * _SubDiagL[1]; //_SuperDiagL[1] -= _SubDiagL[1]; //_DiagL[_steps - 2] += 2.0 * _SuperDiagL[_steps - 2]; //_SubDiagL[_steps - 2] -= _SuperDiagL[_steps - 2]; //call LU decomp //LUDecomp(); //Call the LU sOlver //LUSolution(); //for zero curvature //_v[0] = 2.0 * _v[1] - _v[2]; //_v[_steps - 1] = 2.0 * _v[_steps - 2] - _v[_steps - 3]; } else { _v[0] = MakeLowerBC(tau, Math.Exp(_x[0]), domRbc, DiscDiv); _v[Steps - 1] = MakeUpperBC(tau, Math.Exp(_x[Steps - 1]), domRbc, DiscDiv); SORmethod(); } //after having incremented back, apply a grid shift if needed if (divPay != 0.0) { ApplyGridShift(tau, divPay, domRbc, DiscDiv); } } int nKey = (int) ((Math.Log(Spot) - XL) / _dx); double frac = (Math.Log(Spot) - _x[nKey])/ (_x[nKey+1] - _x[nKey]); double temp = _v[nKey] * (1.0 - frac) + _v[nKey+1] * frac; if (bGreeks) { double[,] a = new double[4, 4]; double[] b = new double[4]; a[0,0] = 1.0; a[1,0] = 1.0; a[2,0] = 1.0; a[3,0] = 1.0; a[0, 1] = Math.Exp(_x[nKey-1]); a[1, 1] = Math.Exp(_x[nKey]); a[2, 1] = Math.Exp(_x[nKey +1]); a[3, 1] = Math.Exp(_x[nKey +2]); a[0, 2] = Math.Exp(_x[nKey - 1]) * Math.Exp(_x[nKey - 1]); a[1, 2] = Math.Exp(_x[nKey]) * Math.Exp(_x[nKey]); a[2, 2] = Math.Exp(_x[nKey + 1])*Math.Exp(_x[nKey + 1]); a[3, 2] = Math.Exp(_x[nKey + 2]) * Math.Exp(_x[nKey + 1]); a[0, 3] = Math.Exp(_x[nKey - 1])*Math.Exp(_x[nKey - 1])*Math.Exp(_x[nKey - 1]); a[1, 3] = Math.Exp(_x[nKey]) * Math.Exp(_x[nKey]) * Math.Exp(_x[nKey]); a[2, 3] = Math.Exp(_x[nKey + 1]) * Math.Exp(_x[nKey + 1]) * Math.Exp(_x[nKey +1]); a[3, 3] = Math.Exp(_x[nKey + 2] )* Math.Exp(_x[nKey + 2] )* Math.Exp(_x[nKey + 2]); b[0] = _v[nKey-1]; b[1] = _v[nKey]; b[2] = _v[nKey+1]; b[3] = _v[nKey+2]; int info = NewtonGauss(4, ref a, ref b); greeks[0] = b[1] + 2.0 * b[2] * Spot +3.0 * b[3] * Spot * Spot; greeks[1] =2.0*b[2] +6.0* b[3] * Spot ; greeks[2] = (tempInt - temp) / (365.0 * dt); /* nKey = (int)((Math.Log(_spot) * 1.001 - _xl) / _dx); frac = (Math.Log(_spot )* 1.001 - _x[nKey]) / (_x[nKey + 1] - _x[nKey]); double tempUp = _v[nKey] * (1.0 - frac) + _v[nKey + 1] * frac; nKey = (int)((Math.Log(_spot) * 0.999 - _xl) / _dx); frac = (Math.Log(_spot) * 0.999 - _x[nKey]) / (_x[nKey + 1] - _x[nKey]); double tempDn = _v[nKey] * (1.0 - frac) + _v[nKey + 1] * frac; greeks[0] = (tempUp - tempDn) / (0.002 *Math.Log(spot))/spot ; greeks[1] = (tempUp + tempDn - 2.0 * temp) / Math.Pow(0.001 * _spot * Math.Log(_spot), 2.0) - greeks[0]/_spot; greeks[2] = (tempInt - temp) / (365.0 * dt); */ } return temp; }