public static double Delta(double forward, double knownAverage, double sigma, double K, double tAvgStart, double tExpiry, double riskFree, OptionType callPut) { var tau = Max(0, tAvgStart); var M = 2 * (Exp(sigma * sigma * tExpiry) - Exp(sigma * sigma * tau) * (1 + sigma * sigma * (tExpiry - tau))); M /= Pow(sigma, 4.0) * (tExpiry - tau) * (tExpiry - tau); var sigma_a = Sqrt(Log(M) / tExpiry); K = AsianUtils.AdjustedStrike(K, knownAverage, tExpiry, tAvgStart); if (K <= 0) { if (callPut == OptionType.P) { return(0); } var t2 = tExpiry - tAvgStart; var expAvg = knownAverage * (t2 - tExpiry) / t2 + forward * tExpiry / t2; var df = Exp(-riskFree * tExpiry); return(df * (expAvg - K)); } var delta = BlackFunctions.BlackDelta(forward, K, riskFree, tExpiry, sigma_a, callPut); if (tAvgStart < 0) { delta *= tExpiry / (tExpiry - tAvgStart); } return(delta); }
public static double PV(double forward, double knownAverage, double sigma, double K, double tAvgStart, double tExpiry, double riskFree, OptionType callPut) { if (tExpiry <= 0) //work out intrinsic { return(callPut == OptionType.Call ? Max(0, knownAverage - K) : Max(0, K - knownAverage)); } var tau = Max(0, tAvgStart); var M = 2 * (Exp(sigma * sigma * tExpiry) - Exp(sigma * sigma * tau) * (1 + sigma * sigma * (tExpiry - tau))); M /= Pow(sigma, 4.0) * (tExpiry - tau) * (tExpiry - tau); //hack to fix deep ITM options have imaginary vol var sigma_a = tExpiry == 0 ? 0.0 : Sqrt(Log(M) / tExpiry); K = AsianUtils.AdjustedStrike(K, knownAverage, tExpiry, tAvgStart); if (K <= 0 && tAvgStart < 0) { if (callPut == OptionType.P) { return(0); } var t2 = tExpiry - tAvgStart; var expAvg = knownAverage * (t2 - tExpiry) / t2 + forward * tExpiry / t2; var df = Exp(-riskFree * tExpiry); return(df * expAvg); } var pv = BlackFunctions.BlackPV(forward, K, riskFree, tExpiry, sigma_a, callPut); if (tAvgStart < 0) { pv *= tExpiry / (tExpiry - tAvgStart); } return(pv); }
public static double PV(double[] forwards, DateTime[] fixingDates, DateTime evalDate, DateTime payDate, double[] sigmas, double K, double riskFree, OptionType callPut, bool todayFixed = false) { if (payDate < evalDate) { return(0.0); } if (forwards.Length != fixingDates.Length || fixingDates.Length != sigmas.Length) { throw new DataMisalignedException(); } var nFixed = evalDate < fixingDates.First() ? 0 : fixingDates.Where(x => (todayFixed ? x <= evalDate : x < evalDate)).Count(); var nFloat = fixingDates.Length - nFixed; var m1 = forwards.Skip(nFixed).Average(); var wholeAverage = forwards.Average(); var tExpiry = evalDate.CalculateYearFraction(fixingDates.Last(), DayCountBasis.Act365F, false); var tPay = evalDate.CalculateYearFraction(payDate, DayCountBasis.Act365F, false); var df = Exp(-riskFree * tPay); if (tExpiry <= 0) //work out intrinsic { return(df * (callPut == OptionType.Call ? Max(0, wholeAverage - K) : Max(0, K - wholeAverage))); } var m2 = 0.0; var ts = fixingDates.Select(x => Max(0, evalDate.CalculateYearFraction(x, DayCountBasis.Act365F, false))).ToArray(); for (var i = nFixed; i < fixingDates.Length; i++) { for (var j = nFixed; j < fixingDates.Length; j++) { m2 += forwards[i] * forwards[j] * Exp(sigmas[i] * sigmas[j] * ts[Min(i, j)]); } } m2 /= nFloat * nFloat; var sigma_a = Sqrt(1 / tExpiry * Log(m2 / (m1 * m1))); var tAvgStart = evalDate.CalculateYearFraction(fixingDates.First(), DayCountBasis.Act365F, false); var knownAverage = nFixed == 0 ? 0.0 : forwards.Take(nFixed).Average(); var k0 = K; K = AsianUtils.AdjustedStrike(K, knownAverage, tExpiry, tAvgStart); if (K <= 0) { return((callPut == OptionType.P) ? 0.0 : df *Max(wholeAverage - k0, 0)); } var pv = BlackFunctions.BlackPV(m1, K, 0.0, tExpiry, sigma_a, callPut); if (tAvgStart < 0) { pv *= tExpiry / (tExpiry - tAvgStart); } return(df * pv); }