//SOR method private void SORmethod() { int noits = 0; double tol = 0.000001; // 0.0000001; double err = 1.0; //double[] temp = new double[_v.Count]; double temp = 0.0; bool bAm = (SStyle.ToUpper().Equals("A")) ? true : false; while (Math.Sqrt(err) > tol) { err = 0.0; for (int idx = 1; idx < _msteps; idx++) { temp = (_q[idx] - _superDiagL[idx] * _v[idx + 1] - _subDiagL[idx] * _v[idx - 1]) / _diagL[idx]; temp = bAm ? Math.Max(temp, AmPay(idx)) : temp; //if (_sPay.ToUpper().Equals("P")) // temp = bAm ? Math.Max(temp, AmPay(idx)) : temp; err += (temp - _v[idx]) * (temp - _v[idx]); _v[idx] = temp; } noits += 1; //temp[0] = _v[0]; //temp[_msteps] = _v[_msteps]; //for( int idx = 0; idx != _steps; idx++) // _v[idx] = temp[idx]; } }
private double MakeUpperBC(double tau, double S, double domRbc, double DiscDiv) { double temp = 0.0; if (UbFlag) return 0.0; switch (SPay.ToUpper()) { case "C": temp = (S - DiscDiv - Math.Exp(-domRbc * tau) * Strike); temp = (SStyle.ToUpper().Equals("A")) ? Math.Max(temp, S - Strike) : temp; break; case "P": break; case "A": temp = Math.Exp(-domRbc * tau); break; case "B": break; case "T": break; default: break; } return temp; }
//apply the BC private double MakeLowerBC(double tau, double S, double domRbc, double discDiv) { double temp = 0.0; if (LbFlag) { return(0.0); } switch (SPay.ToUpper()) { case "C": break; case "P": temp = (SStyle.ToUpper().Equals("E")) ? Math.Exp(-domRbc * tau) * Strike - Math.Max(S - discDiv, 0.0) : Strike - S; break; case "A": break; case "B": temp = Math.Exp(-domRbc * tau); break; case "T": break; } return(temp); }
//Apply grid shift for disc divs private void ApplyGridShift(double tau, double divPay, double domRbc, double DiscDiv) { //set up the new list List <double> _vn = new List <double>(); double temp; //for lower boundary, assign the lower bc using the immediate exercise temp = MakeLowerBC(tau, Math.Max(Math.Exp(_x[0]) - divPay, 0.0), domRbc, DiscDiv); if (SStyle.ToUpper().Equals("A")) { _vn.Add(Math.Max(temp, AmPay(0))); } else { _vn.Add(temp); } for (int idx = 1; idx < Steps; idx++) { double xshift = Math.Log(Math.Exp(_x[idx]) - divPay); if (xshift >= XL) { int idNew = (int)((xshift - XL) / _dx); double frac = (xshift - _x[idNew]) / (_x[idNew + 1] - _x[idNew]); temp = (1.0 - frac) * _v[idNew] + frac * _v[idNew + 1]; _vn.Add(SStyle.ToUpper().Equals("A") ? Math.Max(temp, AmPay(idx)) : temp); } else // the new points are still below the grid { temp = MakeLowerBC(tau, Math.Max(Math.Exp(_x[idx]) - divPay, 0.0), domRbc, DiscDiv); _vn.Add(SStyle.ToUpper().Equals("A") ? Math.Max(temp, AmPay(idx)) : temp); } } //for upper boundary add the upper //_vn.Add(MakeUpperBC(tau, Math.Exp(_x[_steps-1]) - divPay, domRbc, DiscDiv)); _v = _vn; }
/// <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; }