public static double GetATMfwd(ZeroCurve myZero, DivList myDivList, double spot, double t) { double spotStart = spot; //compute the discounted dividends and take off spot if ((myDivList != null) && (myZero != null)) { for (int idx = 0; idx < myDivList.Divpoints; idx++) { if (myDivList.GetT(idx) <= t) { double d1 = myDivList.GetD(idx); double r1 = myZero.LinInterp(myDivList.GetT(idx)); double t1 = Math.Exp(-r1 * myDivList.GetT(idx)); spotStart -= d1 * t1; } } } //gross up to expiry to get atfwd if (myZero != null) { double r = myZero.LinInterp(t); return(spotStart * Math.Exp(r * t)); } return(0); }
public static double FindZeroCostCall(ZeroCurve myZero, DivList myDiv, OrcWingVol myVol, double t, double strike, double spot, string style, string payStyle, double gridSteps) { //compute the cost of the put double callPrice = 0.0; double putPrice = FindPrice(myZero, myDiv, myVol, t, strike, spot, style, "p", gridSteps); //start looking for the call using the ATM strike //double callStrike = GetATMfwd(myZero, myDiv, spot, t); double callStrike = strike; const double tol = 0.0001; for (int idx = 0; idx < 1000; idx++) { callPrice = FindPrice(myZero, myDiv, myVol, t, callStrike, spot, style, "c", gridSteps); if (Math.Abs(callPrice - putPrice) < tol) { break; } //apply newton double dk = 0.001 * callStrike; double callPriceUp = FindPrice(myZero, myDiv, myVol, t, callStrike + dk, spot, style, "c", gridSteps); callStrike -= (callPrice - putPrice) * dk / (callPriceUp - callPrice); } if (Math.Abs(callPrice - putPrice) > tol) { throw new Exception("Price did not converge"); } return(callStrike); }
public void MakeDeltaGamma(Tree spotT, Pricer priceT, ZeroCurve myZero, DivList myDiv) { SetParam(spotT, priceT); Tree treeD = new Tree { GridSteps = GridSteps + 2, Spot = Spot, Sig = Sigma, Tau = Tau * (1 + 2 / GridSteps) }; treeD.MakeGrid(myZero, myDiv); priceT.MakeGrid(treeD); double[] s = new double[3]; double[] c = new double[3]; for (int i = 0; i <= 2; ++i) { s[i] = treeD.GetSpotMatrix(2, i); c[i] = priceT.GetPriceMatrix(2, i); } Delta = (s[0] * (2 * s[1] - s[0]) * (c[1] - c[2]) + (s[1] * s[1]) * (c[2] - c[0]) + s[2] * (2 * s[1] - s[2]) * (c[0] - c[1])) / (s[1] - s[0]) / (s[2] - s[0]) / (s[2] - s[1]); Gamma = 2 * (s[0] * (c[1] - c[2]) + s[1] * (c[2] - c[0]) + s[2] * (c[0] - c[1])) / (s[1] - s[0]) / (s[2] - s[0]) / (s[2] - s[1]); }
public void MakeVega(Tree spotT, Pricer priceT, ZeroCurve myZero, DivList myDiv) { SetParam(spotT, priceT); Tree t1 = new Tree(), t2 = new Tree(); t1.Tau = Tau; t1.GridSteps = GridSteps; t1.Sig = .99 * Sigma; t1.Spot = Spot; t1.MakeGrid(myZero, myDiv); priceT.MakeGrid(t1); double p1 = priceT.Price(); t2.Tau = Tau; t2.GridSteps = GridSteps; t2.Sig = 1.01 * Sigma; t2.Spot = Spot; t2.MakeGrid(myZero, myDiv); priceT.MakeGrid(t2); double p2 = priceT.Price(); if (Sigma != 0) { Vega = 0.01 * (p2 - p1) / (2 * 0.01 * Sigma); } }
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)); } } SetDividends(idx, temp, dt * idx); } } else //missing either div or zero, load in 0 for _div on tree { for (int idx = 0; idx <= GridSteps; idx++) { SetDividends(idx, 0.0, dt * idx); } } }
//public MakeGrid public void MakeGrid(ZeroCurve myZero, DivList myDivList) { EmptyArrays(); MakeArrays(); MakeSpotStar(myZero, myDivList); MakeDivArray(myZero, myDivList); FillForwardRate(myZero); FillUpDown(Sig); //make the spot grid double sv = SpotStart; SetSpotMatrix(0, 0, sv + GetDividends(0)); //now march forward in time for (int idx = 1; idx <= GridSteps; idx++) { for (int jdx = 0; jdx <= idx; jdx++) { sv = SpotStart * Math.Pow(GetUp(idx - 1), jdx) * Math.Pow(GetDn(idx - 1), idx - jdx); sv += (idx == GridSteps) ? 0.0 : GetDividends(idx); //get_div(idx); SetSpotMatrix(idx, jdx, sv); } } }
//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; }
//determine if dt needs adjusted because a div occurs in proposed interval private double CheckBetweenDiv(double t1, double t2, ref double discDiv, DivList myDiv) //t1 & t2 are real times { double temp = t2-t1; for (int idx = 0; idx < myDiv.Divpoints; idx++) { if ((t1 <= myDiv.GetT(idx)) && (t2 > myDiv.GetT(idx))) { temp = t2 - myDiv.GetT(idx); discDiv = myDiv.GetD(idx); break; } } return temp; }
private void MakeSpotStar(ZeroCurve myZero, DivList myDivList) { SpotStart = Spot; if ((myDivList != null) && (myZero != null)) { for (int idx = 0; idx < myDivList.Divpoints; idx++) { if (myDivList.GetT(idx) <= Tau) { double d1 = myDivList.GetD(idx); double r1 = myZero.LinInterp(myDivList.GetT(idx)); double t1 = Math.Exp(-r1 * myDivList.GetT(idx)); SpotStart -= d1 * t1; } } } }
/// <summary> /// /// </summary> /// <param name="price"></param> /// <param name="myZero"></param> /// <param name="myDiv"></param> /// <returns></returns> public double ImpVol(double price, ZeroCurve myZero, DivList myDiv) { double[] greeks = new double[4]; double temp = Pricer(myZero, myDiv, ref greeks, false); for (int idx = 0; idx < 20; idx++) { temp = Pricer(myZero, myDiv, ref greeks, false); if (Math.Abs(temp - price) < 0.0001) break; double sigold = Sig; double dsig = 0.01 * Sig; Sig += dsig; double tempUp = Pricer(myZero, myDiv, ref greeks, false); sigold -= (temp - price) * dsig / (tempUp - temp); Sig = sigold; } return Sig; }
public static double FindPrice(ZeroCurve myZero, DivList myDiv, OrcWingVol myVol, double t, double strike, double spot, string style, string paystyle, double gridsteps) { //get the atfwd double atFwd = GetATMfwd(myZero, myDiv, spot, t); //set up the tree var myTree = new Tree(); int numGridSteps = (gridsteps < 20.0) ? 20 : Convert.ToInt32(gridsteps); myTree.GridSteps = numGridSteps; myTree.Tau = t; myTree.Sig = myVol.orcvol(atFwd, strike); myTree.Spot = spot; myTree.MakeGrid(myZero, myDiv); //create pricer var myPrice = new Pricer { Strike = strike, Payoff = paystyle, Smoothing = "y", Style = style }; myPrice.MakeGrid(myTree); double pr = myPrice.Price(); return(pr); }
public void MakeTheta(Tree spotT, Pricer priceT, ZeroCurve myZero, DivList myDiv) { SetParam(spotT, priceT); Tree t1 = new Tree(), t2 = new Tree(); t1.Tau = Tau; t1.GridSteps = GridSteps; t1.Sig = Sigma; t1.Spot = Spot; t1.MakeGrid(myZero, myDiv); priceT.MakeGrid(t1); double p1 = priceT.Price(); double t = Tau - 1.00 / 365.00; t2.Tau = t; t2.GridSteps = GridSteps; t2.Sig = Sigma; t2.Spot = Spot; t2.MakeGrid(myZero, myDiv); priceT.MakeGrid(t2); double p2 = priceT.Price(); Theta = (p2 - p1); }
/// <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; }