Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
gavbrennan committed Jul 31, 2018
1 parent 0fe3cdf commit 43ca1d7
Show file tree
Hide file tree
Showing 3 changed files with 429 additions and 0 deletions.
169 changes: 169 additions & 0 deletions AsianFunctions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ExcelDna.Integration;
using Qwack.Options;
using Qwack.Excel.Services;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Qwack.Options.VolSurfaces;
using Qwack.Excel.Utils;
using Qwack.Dates;
using Qwack.Core.Basic;

namespace Qwack.Excel.Options
{
public class AsianFunctions
{
private static readonly ILogger _logger = ContainerStores.GlobalContainer.GetService<ILoggerFactory>()?.CreateLogger<BlackFunctions>();

[ExcelFunction(Description = "Returns asian option PV using the Turnbull-Wakeman formula", Category = CategoryNames.Options, Name = CategoryNames.Options + "_" + nameof(TurnbullWakemanPV))]
public static object TurnbullWakemanPV(
[ExcelArgument(Description = "Time-to-expiry")] double T,
[ExcelArgument(Description = "Time-to-average start")] double TavgStart,
[ExcelArgument(Description = "Average-to-date")] double KnownAverage,
[ExcelArgument(Description = "Strike")] double K,
[ExcelArgument(Description = "Forward")] double F,
[ExcelArgument(Description = "Discounting rate")] double R,
[ExcelArgument(Description = "Volatility")] double V,
[ExcelArgument(Description = "Call or Put")] string CP)
{
return ExcelHelper.Execute(_logger, () =>
{
if (!Enum.TryParse(CP, out OptionType optType))
{
return $"Could not parse call or put flag - {CP}";
}
return Qwack.Options.Asians.TurnbullWakeman.PV(F, KnownAverage, V, K, TavgStart, T, R, optType);
});
}

[ExcelFunction(Description = "Returns asian option PV using the Turnbull-Wakeman formula", Category = CategoryNames.Options, Name = CategoryNames.Options + "_" + nameof(TurnbullWakemanPV2))]
public static object TurnbullWakemanPV2(
[ExcelArgument(Description = "Evaluation Date")] DateTime EvalDate,
[ExcelArgument(Description = "Average Start Date")] DateTime AverageStartDate,
[ExcelArgument(Description = "Average End Date")] DateTime AverageEndDate,
[ExcelArgument(Description = "Average-to-date")] double KnownAverage,
[ExcelArgument(Description = "Strike")] double K,
[ExcelArgument(Description = "Forward")] double F,
[ExcelArgument(Description = "Discounting rate")] double R,
[ExcelArgument(Description = "Volatility")] double V,
[ExcelArgument(Description = "Call or Put")] string CP)
{
return ExcelHelper.Execute(_logger, () =>
{
if (!Enum.TryParse(CP, out OptionType optType))
{
return $"Could not parse call or put flag - {CP}";
}
return Qwack.Options.Asians.TurnbullWakeman.PV(F, KnownAverage, V, K, EvalDate, AverageStartDate, AverageEndDate, R, optType);
});
}

[ExcelFunction(Description = "Returns asian option delta using the Turnbull-Wakeman formula", Category = CategoryNames.Options, Name = CategoryNames.Options + "_" + nameof(TurnbullWakemanDelta))]
public static object TurnbullWakemanDelta(
[ExcelArgument(Description = "Evaluation Date")] DateTime EvalDate,
[ExcelArgument(Description = "Average Start Date")] DateTime AverageStartDate,
[ExcelArgument(Description = "Average End Date")] DateTime AverageEndDate,
[ExcelArgument(Description = "Average-to-date")] double KnownAverage,
[ExcelArgument(Description = "Strike")] double K,
[ExcelArgument(Description = "Forward")] double F,
[ExcelArgument(Description = "Discounting rate")] double R,
[ExcelArgument(Description = "Volatility")] double V,
[ExcelArgument(Description = "Call or Put")] string CP)
{
return ExcelHelper.Execute(_logger, () =>
{
if (!Enum.TryParse(CP, out OptionType optType))
{
return $"Could not parse call or put flag - {CP}";
}
return Qwack.Options.Asians.TurnbullWakeman.Delta(F, KnownAverage, V, K, EvalDate, AverageStartDate, AverageEndDate, R, optType);
});
}

[ExcelFunction(Description = "Returns strike for asian option with specified PV, using the Turnbull-Wakeman formula", Category = CategoryNames.Options, Name = CategoryNames.Options + "_" + nameof(TurnbullWakemanStrikeForPV))]
public static object TurnbullWakemanStrikeForPV(
[ExcelArgument(Description = "Evaluation Date")] DateTime EvalDate,
[ExcelArgument(Description = "Average Start Date")] DateTime AverageStartDate,
[ExcelArgument(Description = "Average End Date")] DateTime AverageEndDate,
[ExcelArgument(Description = "Average-to-date")] double KnownAverage,
[ExcelArgument(Description = "Target PV")] double PV,
[ExcelArgument(Description = "Forward")] double F,
[ExcelArgument(Description = "Discounting rate")] double R,
[ExcelArgument(Description = "Volatility Surface")] string VolSurface,
[ExcelArgument(Description = "Call or Put")] string CP)
{
return ExcelHelper.Execute(_logger, () =>
{
if (!ContainerStores.GetObjectCache<IVolSurface>().TryGetObject(VolSurface, out var surface))
{
return $"Could not parse find vol surface {VolSurface} in the cache";
}
if (!Enum.TryParse(CP, out OptionType optType))
{
return $"Could not parse call or put flag - {CP}";
}
return Qwack.Options.Asians.TurnbullWakeman.StrikeForPV(PV, F, KnownAverage, surface.Value, EvalDate, AverageStartDate, AverageEndDate, R, optType);
});
}

[ExcelFunction(Description = "Returns asian option PV using the Clewlow/LME formula", Category = CategoryNames.Options, Name = CategoryNames.Options + "_" + nameof(ClewlowPV))]
public static object ClewlowPV(
[ExcelArgument(Description = "Evaluation Date")] DateTime EvalDate,
[ExcelArgument(Description = "Average Start Date")] DateTime AverageStartDate,
[ExcelArgument(Description = "Average End Date")] DateTime AverageEndDate,
[ExcelArgument(Description = "Average-to-date")] double KnownAverage,
[ExcelArgument(Description = "Strike")] double K,
[ExcelArgument(Description = "Forward")] double F,
[ExcelArgument(Description = "Discounting rate")] double R,
[ExcelArgument(Description = "Volatility")] double V,
[ExcelArgument(Description = "Call or Put")] string CP,
[ExcelArgument(Description = "Fixing Calendar")] object FixingCalendar)
{

return ExcelHelper.Execute(_logger, () =>
{
var fixCal = FixingCalendar.OptionalExcel<string>("Weekends");
if (!ContainerStores.SessionContainer.GetService<ICalendarProvider>().Collection.TryGetCalendar(fixCal, out var cal))
return $"Calendar {FixingCalendar} not found in cache";
if (!Enum.TryParse(CP, out OptionType optType))
{
return $"Could not parse call or put flag - {CP}";
}
return Qwack.Options.Asians.LME_Clewlow.PV(F, KnownAverage, V, K, EvalDate, AverageStartDate, AverageEndDate, R, optType, cal);
});
}

[ExcelFunction(Description = "Returns asian option delta using the Clewlow/LME formula", Category = CategoryNames.Options, Name = CategoryNames.Options + "_" + nameof(ClewlowDelta))]
public static object ClewlowDelta(
[ExcelArgument(Description = "Evaluation Date")] DateTime EvalDate,
[ExcelArgument(Description = "Average Start Date")] DateTime AverageStartDate,
[ExcelArgument(Description = "Average End Date")] DateTime AverageEndDate,
[ExcelArgument(Description = "Average-to-date")] double KnownAverage,
[ExcelArgument(Description = "Strike")] double K,
[ExcelArgument(Description = "Forward")] double F,
[ExcelArgument(Description = "Discounting rate")] double R,
[ExcelArgument(Description = "Volatility")] double V,
[ExcelArgument(Description = "Call or Put")] string CP,
[ExcelArgument(Description = "Fixing Calendar")] object FixingCalendar)
{

return ExcelHelper.Execute(_logger, () =>
{
var fixCal = FixingCalendar.OptionalExcel<string>("Weekends");
if (!ContainerStores.SessionContainer.GetService<ICalendarProvider>().Collection.TryGetCalendar(fixCal, out var cal))
return $"Calendar {FixingCalendar} not found in cache";
if (!Enum.TryParse(CP, out OptionType optType))
{
return $"Could not parse call or put flag - {CP}";
}
return Qwack.Options.Asians.LME_Clewlow.Delta(F, KnownAverage, V, K, EvalDate, AverageStartDate, AverageEndDate, R, optType, cal);
});
}
}
}
159 changes: 159 additions & 0 deletions LME_Clewlow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.Text;
using Qwack.Dates;
using Qwack.Core.Basic;
using System.Linq;

namespace Qwack.Options.Asians
{
public static class LME_Clewlow
{
public static double PV(double forward, double knownAverage, double sigma, double K, DateTime evalDate, DateTime avgStartDate, DateTime avgEndDate, double riskFree, OptionType callPut, Calendar fixingCalendar)
{
if (avgEndDate == evalDate)
if (callPut == OptionType.C)
return System.Math.Max(knownAverage - K, 0);
else
return System.Math.Max(K - knownAverage, 0);

else if (avgEndDate < evalDate)
return 0;
else if (avgStartDate == avgEndDate)
{
var t = (avgEndDate - evalDate).TotalDays / 365.0;
return BlackFunctions.BlackPV(forward, K, riskFree, t, sigma, callPut);
}

//Build Vector of Observation Dates
var resetDates = avgStartDate.BusinessDaysInPeriod(avgEndDate, fixingCalendar);
var RT = resetDates.Count;

//Initialise Variables
double E1 = 0.0, E2 = 0.0, E3 = 0.0, E4 = 0.0, E5 = 0.0;
double DeltaTPrime = 0.0, DeltaT = 0.0;

var FBar = forward;
var tvs = resetDates.Count(x => x < evalDate);

if (tvs > 0)
DeltaTPrime = (resetDates[tvs + 1] - resetDates[tvs]).TotalDays / 365.0;
else
DeltaTPrime = ((resetDates[0] - evalDate).TotalDays) / 365.0;

if (tvs + 2 >= RT)
DeltaT = DeltaTPrime;
else
DeltaT = (avgEndDate - resetDates[tvs+1]).TotalDays / 365.0 / (RT - tvs);

var Ak = knownAverage * tvs / RT;
E5 = 2 * Ak * FBar * (RT - tvs) / RT + (Ak * Ak);

if (tvs < RT)
{
E4 = (1 + System.Math.Exp(sigma * sigma * DeltaT)) * (System.Math.Exp((RT - tvs) * sigma * sigma * DeltaT) - 1);
E4 += 2 * (RT - tvs) * (1 - System.Math.Exp(sigma * sigma * DeltaT));
E4 /= (System.Math.Pow(System.Math.Exp(sigma * sigma * DeltaT) - 1, 2));
}
else
E4 = 1;


E3 = System.Math.Pow(FBar / RT, 2) * System.Math.Exp(sigma * sigma * DeltaTPrime);
E2 = E3 * E4 + E5;
E1 = FBar * (RT - tvs) / RT + Ak;

var EA = Ak + FBar * (RT - tvs) / RT;

var b = System.Math.Log(E2) - 2 * System.Math.Log(E1);
var d1 = (System.Math.Log(EA / K) + 0.5 * b) / System.Math.Sqrt(b);
var d2 = d1 - System.Math.Sqrt(b);


var df = System.Math.Exp(-riskFree * (avgEndDate - evalDate).TotalDays / 365.0);

//Main Option valuation
if (callPut == OptionType.Call)
{
d1 = Math.Statistics.NormSDist(d1);
d2 = Math.Statistics.NormSDist(d2);
return (EA * d1 - K * d2) * df;
}
else
{
d1 = Math.Statistics.NormSDist(-d1);
d2 = Math.Statistics.NormSDist(-d2);
return (K * d2 - EA * d1) * df;
}

}

public static double Delta(double forward, double knownAverage, double sigma, double K, DateTime evalDate, DateTime avgStartDate, DateTime avgEndDate, double riskFree, OptionType callPut, Calendar fixingCalendar)
{
//Build Vector of Observation Dates
var resetDates = avgStartDate.BusinessDaysInPeriod(avgEndDate, fixingCalendar);
var RT = resetDates.Count;

if (avgEndDate == evalDate)
if (callPut == OptionType.C)
return knownAverage > K ? 1.0 / RT : 0;
else
return knownAverage < K ? -1.0 / RT : 0;
else if (avgEndDate < evalDate)
return 0;
else if (avgStartDate == avgEndDate)
{
var t = (avgEndDate - evalDate).TotalDays / 365.0;
return BlackFunctions.BlackDelta(forward, K, riskFree, t, sigma, callPut);
}


//Initialise Variables
double E1 = 0.0, E2 = 0.0, E3 = 0.0, E4 = 0.0, E5 = 0.0;
double DeltaTPrime = 0.0, DeltaT = 0.0;

var FBar = forward;
var tvs = resetDates.Count(x => x < evalDate);

if (tvs > 0)
DeltaTPrime = (resetDates[tvs + 1] - resetDates[tvs]).TotalDays / 365.0;
else
DeltaTPrime = ((resetDates[0] - evalDate).TotalDays) / 365.0;

if (tvs + 2 >= RT)
DeltaT = DeltaTPrime;
else
DeltaT = (avgEndDate - resetDates[tvs + 1]).TotalDays / 365.0 / (RT - tvs);

var Ak = knownAverage * tvs / RT;
E5 = 2 * Ak * FBar * (RT - tvs) / RT + (Ak * Ak);

if (tvs < RT)
{
E4 = (1 + System.Math.Exp(sigma * sigma * DeltaT)) * (System.Math.Exp((RT - tvs) * sigma * sigma * DeltaT) - 1);
E4 += 2 * (RT - tvs) * (1 - System.Math.Exp(sigma * sigma * DeltaT));
E4 /= (System.Math.Pow(System.Math.Exp(sigma * sigma * DeltaT) - 1, 2));
}
else
E4 = 1;


E3 = System.Math.Pow(FBar / RT, 2) * System.Math.Exp(sigma * sigma * DeltaTPrime);
E2 = E3 * E4 + E5;
E1 = FBar * (RT - tvs) / RT + Ak;

var EA = Ak + FBar * (RT - tvs) / RT;

var b = System.Math.Log(E2) - 2 * System.Math.Log(E1);
var d1 = (System.Math.Log(EA / K) + 0.5 * b) / System.Math.Sqrt(b);

var df = System.Math.Exp(-riskFree * (avgEndDate - evalDate).TotalDays / 365.0);

d1 = Math.Statistics.NormSDist(d1 *
(callPut == OptionType.Call ? 1.0 : -1.0));

var delta = d1 * df;
return delta;
}
}
}
Loading

0 comments on commit 43ca1d7

Please sign in to comment.