public static double GetATMfwd(ZeroCurve myZero, DivList myDivList, double spot, double t) { double spotstar = 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)); spotstar -= d1 * t1; } } } //gross up to expiry to get atfwd if (myZero != null) { double r = myZero.LinInterp(t); return(spotstar * 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 DivList UnpackDiv(DateTime today, DateTime expiry, DateTime[] dates, double[] amts) { int n1 = dates.Length; int n2 = dates.Length; double timetoexp = expiry.Subtract(today).Days / 365.0; if (n1 != n2) { throw new Exception("Rate ranges must be of the same length"); } var dl = new DivList { Divpoints = n1 }; dl.MakeArrays(); for (int idx = 0; idx < n1; idx++) { double time = dates[idx].Subtract(today).Days / 365.0; double rate = amts[idx]; if (time > 0 & time <= timetoexp) { dl.SetD(_kdx, rate, time); _kdx++; } } return(dl); }
//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); } } }
//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 = Spotstar; SetSpotMatrix(0, 0, sv + get_div(0)); //now march forward in time for (int idx = 1; idx <= Gridsteps; idx++) { for (int jdx = 0; jdx <= idx; jdx++) { sv = Spotstar * Math.Pow(get_up(idx - 1), jdx) * Math.Pow(get_dn(idx - 1), idx - jdx); sv += (idx == Gridsteps) ? 0.0 : get_div(idx); //get_div(idx); SetSpotMatrix(idx, jdx, sv); } } }
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 = sig; 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 = sig; T2.Spot = spot; T2.MakeGrid(myZero, myDiv); PriceT.MakeGrid(T2); double P2 = PriceT.Price(); Theta = (P2 - P1); }
public void MakeDeltaGamma(Tree SpotT, Pricer PriceT, ZeroCurve myZero, DivList myDiv) { SetParam(SpotT, PriceT); Tree treeD = new Tree { Gridsteps = Gridsteps + 2, Spot = spot, Sig = sig, 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.Get_PriceMatrix(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 * sig; T1.Spot = spot; T1.MakeGrid(myZero, myDiv); PriceT.MakeGrid(T1); double P1 = PriceT.Price(); T2.Tau = tau; T2.Gridsteps = Gridsteps; T2.Sig = 1.01 * sig; T2.Spot = spot; T2.MakeGrid(myZero, myDiv); PriceT.MakeGrid(T2); double P2 = PriceT.Price(); if (sig != 0) { Vega = 0.01 * (P2 - P1) / (2 * 0.01 * sig); } }
//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); }
//public spotStar private void MakeSpotStar(ZeroCurve myZero, DivList myDivList) { Spotstar = 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)); Spotstar -= 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 nGridsteps = (gridsteps < 20.0) ? 20 : Convert.ToInt32(gridsteps); myTree.Gridsteps = nGridsteps; 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); }
/// <summary> /// /// </summary> /// <param name="today"></param> /// <param name="spot"></param> /// <param name="strike"></param> /// <param name="sig"></param> /// <param name="dexp"></param> /// <param name="sPay"></param> /// <param name="sStyle"></param> /// <param name="nGrid"></param> /// <param name="tStep"></param> /// <param name="iNum"></param> /// <param name="divamsAsArray"></param> /// <param name="divdatesAsArray"></param> /// <param name="zeramsAsArray"></param> /// <param name="zerdatesAsArray"></param> /// <returns></returns> public double GetEquityGreeks(DateTime today, double spot, double strike, double sig, DateTime dexp, string sPay, string sStyle, int nGrid, double tStep, int iNum, Excel.Range divamsAsArray, Excel.Range divdatesAsArray, Excel.Range zeramsAsArray, Excel.Range zerdatesAsArray ) { //Map the ranges var divams = DataRangeHelper.StripDoubleRange(divamsAsArray); var divdates = DataRangeHelper.StripDateTimeRange(divamsAsArray); var zerams = DataRangeHelper.StripDoubleRange(zeramsAsArray); var zerdates = DataRangeHelper.StripDateTimeRange(zerdatesAsArray); //set up the DivList int nd = divdates.Count; //GetUpperBound(0) + 1; var myDiv = new DivList { Divpoints = nd }; myDiv.MakeArrays(); for (int idx = 0; idx != nd; idx++) { double r = divams[idx]; DateTime dp = divdates[idx]; TimeSpan ts = dp - today; myDiv.SetD(idx, r, ts.Days / 365.0); } //set up the zero int nz = zerdates.Count;//GetUpperBound(0) + 1; var myZero = new ZeroCurve { Ratepoints = nz }; myZero.MakeArrays(); for (int idx = 0; idx != nz; idx++) { double r = zerams[idx]; DateTime dp = zerdates[idx]; TimeSpan ts = dp - today; myZero.SetR(idx, r, ts.Days / 365.0); } //compute the discounted dividends to expiry and work out continuous TimeSpan tsE = dexp - today; double texp = tsE.Days / 365.0; for (int idx = 0; idx != nd; idx++) { if (myDiv.GetT(idx) <= texp) { double d = myDiv.GetD(idx) * Math.Exp(-myDiv.GetT(idx) * myZero.LinInterp(myDiv.GetT(idx))); } } //double qc = -Math.Log((spot - sum) / spot) / texp; //double rc = myZero.linInterp(texp); var myG = new Grid { XL = Math.Log(spot) - 8.0 * sig * Math.Sqrt(texp), Xu = Math.Log(spot) + 8.0 * sig * Math.Sqrt(texp), Steps = nGrid, Strike = strike, Spot = spot, SPay = sPay, SStyle = sStyle, T = texp }; myG.NTsteps = Convert.ToInt32(myG.T / tStep); myG.Sig = sig; var greeks = new double[4]; double price = myG.Pricer(myZero, myDiv, ref greeks, true); myG.Sig += 0.01; double priceUp = myG.Pricer(myZero, myDiv, ref greeks, false); greeks[3] = priceUp - price; return(greeks[iNum]); }
/// <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); }