Skip to content

Commit

Permalink
Qwack / Excel work on Inflation
Browse files Browse the repository at this point in the history
  • Loading branch information
gavbrennan committed May 15, 2023
1 parent 020d194 commit 3fe212e
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 173 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ExcelDeploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ jobs:
files: ./clients/Qwack.Excel.Next/bin/Release/net6.0-windows
dest: QwackExcel.zip

- name: Create Artifact
uses: actions/upload-artifact@v2
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: excelArtifact
name: QwackExcel.Next
path: ./QwackExcel.zip
18 changes: 9 additions & 9 deletions clients/Qwack.Excel.Next/Curves/IRCurveFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ public static object CreateDiscountCurveFromDFs(
var ccy = ContainerStores.GlobalContainer.GetRequiredService<ICurrencyProvider>()[ccyStr];
var zeroRates = DiscountFactors
.Select((df, ix) =>
DateTime.FromOADate(Pillars[ix])==BuildDate ? 0.0
: IrCurve.RateFromDF(BuildDate.CalculateYearFraction(DateTime.FromOADate(Pillars[ix]), DayCountBasis.ACT365F),df, rType))
.Select((df, ix) =>
DateTime.FromOADate(Pillars[ix]) == BuildDate ? 0.0
: IrCurve.RateFromDF(BuildDate.CalculateYearFraction(DateTime.FromOADate(Pillars[ix]), DayCountBasis.ACT365F), df, rType))
.ToArray();
if (DateTime.FromOADate(Pillars[0]) == BuildDate && zeroRates.Length > 1)
Expand All @@ -151,7 +151,7 @@ public static object GetDF(
{
if (ContainerStores.GetObjectCache<IIrCurve>().TryGetObject(ObjectName, out var curve))
{
return curve.Value.GetDf(StartDate,EndDate);
return curve.Value.GetDf(StartDate, EndDate);
}
return $"IR curve {ObjectName} not found in cache";
Expand Down Expand Up @@ -253,7 +253,7 @@ public static object CreateFundingModel(
}
var model = new FundingModel(BuildDate, emptyCurves.Values.ToArray(), ContainerStores.CurrencyProvider, ContainerStores.CalendarProvider);
if (!(FxMatrix is ExcelMissing))
model.SetupFx(fxMatrix);
Expand Down Expand Up @@ -379,7 +379,7 @@ public static object MergeFundingModels(
return ExcelHelper.Execute(_logger, () =>
{
var modelCache = ContainerStores.GetObjectCache<IFundingModel>();
if(!modelCache.TryGetObject(FundingModelA,out var modelA))
if (!modelCache.TryGetObject(FundingModelA, out var modelA))
{
return $"Could not find funding model {FundingModelA}";
}
Expand All @@ -390,7 +390,7 @@ public static object MergeFundingModels(
var combinedCurves = modelA.Value.Curves.Values.Concat(modelB.Value.Curves.Values).ToArray();
if(combinedCurves.Length != combinedCurves.Select(x=>x.Name).Distinct().Count())
if (combinedCurves.Length != combinedCurves.Select(x => x.Name).Distinct().Count())
{
return $"Not all curves have unique names";
}
Expand Down Expand Up @@ -437,14 +437,14 @@ public static object ListCurvesInModel(
var modelCache = ContainerStores.GetObjectCache<IFundingModel>();
var model = modelCache.GetObject(FundingModelName).Value;
return model.Curves.Keys.Select(x=>x as string).ToArray().ReturnExcelRangeVector();
return model.Curves.Keys.Select(x => x as string).ToArray().ReturnExcelRangeVector();
});
}

[ExcelFunction(Description = "Extracts a curve from a funding model", Category = CategoryNames.Curves, Name = CategoryNames.Curves + "_" + nameof(ExtractCurveFromModel), IsThreadSafe = false)]
public static object ExtractCurveFromModel(
[ExcelArgument(Description = "Funding model name")] string FundingModelName,
[ExcelArgument(Description = "Curve name")] string CurveName,
[ExcelArgument(Description = "Curve name")] string CurveName,
[ExcelArgument(Description = "Output curve object name")] string OutputName)
{
return ExcelHelper.Execute(_logger, () =>
Expand Down
74 changes: 74 additions & 0 deletions clients/Qwack.Excel.Next/Curves/InflationCurveFunctions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ExcelDna.Integration;
using Qwack.Core.Curves;
using Qwack.Excel.Services;
using Qwack.Excel.Utils;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Qwack.Transport.BasicTypes;
using Qwack.Core.Basic;
using Qwack.Dates;
using Qwack.Core.Models;
using Qwack.Models.Calibrators;
using Qwack.Core.Instruments.Funding;
using Qwack.Models;

namespace Qwack.Excel.Curves
{

public class InflationCurveFunctions
{
private static readonly ILogger _logger = ContainerStores.GlobalContainer.GetService<ILoggerFactory>()?.CreateLogger<InflationCurveFunctions>();

[ExcelFunction(Description = "Creates a CPI curve from CPI forecasts", Category = CategoryNames.Curves, Name = CategoryNames.Curves + "_" + nameof(CreateCPICurveFromForecasts), IsThreadSafe = false)]
public static object CreateCPICurveFromForecasts(
[ExcelArgument(Description = "Object name")] string ObjectName,
[ExcelArgument(Description = "Curve name")] object CurveName,
[ExcelArgument(Description = "Build date")] DateTime BuildDate,
[ExcelArgument(Description = "Array of pillar dates")] double[] Pillars,
[ExcelArgument(Description = "Array of CPI forecasts")] double[] CPIForecasts,
[ExcelArgument(Description = "Type of interpolation")] object InterpolationType,
[ExcelArgument(Description = "Inflation Index")] string InfIndex,
[ExcelArgument(Description = "Fixing Dictionary")] string FixingDict,
[ExcelArgument(Description = "Collateral Spec - default LIBOR.3M")] object CollateralSpec)
{
return ExcelHelper.Execute(_logger, () =>
{
var curveName = CurveName.OptionalExcel(ObjectName);
var curveTypeStr = InterpolationType.OptionalExcel("Linear");
var colSpecStr = CollateralSpec.OptionalExcel("LIBOR.3M");
if (!Enum.TryParse(curveTypeStr, out Interpolator1DType iType))
{
return $"Could not parse interpolator type - {curveTypeStr}";
}
if (!ContainerStores.GetObjectCache<InflationIndex>().TryGetObject(InfIndex, out var rIndex))
{
_logger?.LogInformation("Rate index {index} not found in cache", InfIndex);
return $"Rate index {InfIndex} not found in cache";
}
var fixings = new Dictionary<DateTime, double>();
if(ContainerStores.GetObjectCache<IFixingDictionary>().TryGetObject(FixingDict, out var fixDict))
{
foreach(var kv in fixDict.Value)
fixings.Add(kv.Key, kv.Value);
}
var pDates = Pillars.ToDateTimeArray();
var cObj = new CPICurve(BuildDate, pDates, CPIForecasts, rIndex.Value, fixings)
{
Name = curveName,
};
var cache = ContainerStores.GetObjectCache<IIrCurve>();
cache.PutObject(ObjectName, new SessionItem<IIrCurve> { Name = ObjectName, Value = cObj });
return ObjectName + '¬' + cache.GetObject(ObjectName).Version;
});
}
}
}
97 changes: 97 additions & 0 deletions clients/Qwack.Excel.Next/Instruments/FundingInstrumentFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -681,5 +681,102 @@ public static object CreateFxPair(
return ExcelHelper.PushToCache(pair, ObjectName);
});
}

#region Inflation

[ExcelFunction(Description = "Creates a standard inflation swap object following conventions for the given rate index",
Category = CategoryNames.Instruments, Name = CategoryNames.Instruments + "_" + nameof(CreateInflationBenchmarkSwap), IsThreadSafe = Parallel)]
public static object CreateInflationBenchmarkSwap(
[ExcelArgument(Description = "Object name")] string ObjectName,
[ExcelArgument(Description = "Value date")] DateTime ValDate,
[ExcelArgument(Description = "Tenor")] string SwapTenor,
[ExcelArgument(Description = "Inflation Index")] string InfIndex,
[ExcelArgument(Description = "Par Rate")] double ParRate,
[ExcelArgument(Description = "Notional")] double Notional,
[ExcelArgument(Description = "Forecast Curve (CPI)")] string ForecastCurve,
[ExcelArgument(Description = "Discount Curve")] string DiscountCurve,
[ExcelArgument(Description = "Pay / Receive")] object PayRec,
[ExcelArgument(Description = "Solve Curve name ")] object SolveCurve,
[ExcelArgument(Description = "Solve Pillar Date")] object SolvePillarDate)
{
return ExcelHelper.Execute(_logger, () =>
{
var payRec = PayRec.OptionalExcel("Pay");
if (!ContainerStores.GetObjectCache<InflationIndex>().TryGetObject(InfIndex, out var rIndex))
{
_logger?.LogInformation("Rate index {index} not found in cache", InfIndex);
return $"Rate index {InfIndex} not found in cache";
}
if (!Enum.TryParse(payRec, out SwapPayReceiveType pType))
{
return $"Could not parse pay/rec - {payRec}";
}
var tenor = new Frequency(SwapTenor);
var product = new InflationPerformanceSwap(ValDate, tenor, rIndex.Value, ParRate, Notional, pType, ForecastCurve, DiscountCurve)
{
TradeId = ObjectName,
SolveCurve = SolveCurve.OptionalExcel(rIndex.Name),
Notional = Notional
};
product.PillarDate = SolvePillarDate.OptionalExcel(product.EndDate);
return ExcelHelper.PushToCache(product, ObjectName);
});
}

[ExcelFunction(Description = "Creates a new inflation index object", Category = CategoryNames.Instruments,
Name = CategoryNames.Instruments + "_" + nameof(CreateInflationIndex), IsVolatile = true, IsThreadSafe = Parallel)]
public static object CreateInflationIndex(
[ExcelArgument(Description = "Index name")] string IndexName,
[ExcelArgument(Description = "Currency")] string Currency,
[ExcelArgument(Description = "Rate forecast tenor")] string FixingInterpolation,
[ExcelArgument(Description = "Day count basis, float leg")] string DaycountBasisFloat,
[ExcelArgument(Description = "Day count basis, fixed leg")] string DaycountBasisFixed,
[ExcelArgument(Description = "Reset Frequency")] string ResetFrequency,
[ExcelArgument(Description = "Holiday calendars")] string HolidayCalendars,
[ExcelArgument(Description = "Fixing offset, e.g. 2b")] string FixingOffset,
[ExcelArgument(Description = "Roll convention")] string RollConvention)
{
return ExcelHelper.Execute(_logger, () =>
{
if (!Enum.TryParse(DaycountBasisFixed, out DayCountBasis dFixed))
return $"Could not parse fixed daycount - {DaycountBasisFixed}";
if (!Enum.TryParse(DaycountBasisFloat, out DayCountBasis dFloat))
return $"Could not parse float daycount - {DaycountBasisFloat}";
if (!Enum.TryParse(RollConvention, out RollType rConv))
return $"Could not parse roll convention - {RollConvention}";
if (!Enum.TryParse(FixingInterpolation, out Interpolator1DType iType))
return $"Could not parse fixing interpolation - {FixingInterpolation}";
var resetFrequency = new Frequency(ResetFrequency);
var fixOffset = new Frequency(FixingOffset);
if (!ContainerStores.SessionContainer.GetService<ICalendarProvider>().Collection.TryGetCalendar(HolidayCalendars, out var cal))
{
_logger?.LogInformation("Calendar {HolidayCalendars} not found in cache", HolidayCalendars);
return $"Calendar {HolidayCalendars} not found in cache";
}
var infIndex = new InflationIndex
{
Currency = ContainerStores.GlobalContainer.GetRequiredService<ICurrencyProvider>()[Currency],
RollConvention = rConv,
FixingInterpolation = iType,
FixingLag = fixOffset,
ResetFrequency = resetFrequency,
HolidayCalendars = cal,
DayCountBasis = dFloat,
DayCountBasisFixed = dFixed
};
return ExcelHelper.PushToCache(infIndex, IndexName);
});
}

#endregion
}
}
8 changes: 4 additions & 4 deletions clients/Qwack.Excel.Next/Qwack.Excel.Next.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ExcelDna.AddIn" Version="1.6.0" />
<PackageReference Include="Microsoft.Office.Interop.Excel" Version="15.0.4795.1001" />
<PackageReference Include="System.Resources.Extensions" Version="7.0.0" />
<PackageReference Include="Microsoft.Windows.Compatibility" Version="7.0.0" />
<PackageReference Include="System.Resources.Extensions" Version="6.0.0" />
<PackageReference Include="Microsoft.Windows.Compatibility" Version="6.0.0" />
<PackageReference Include="Azure.Identity" Version="1.8.0" />
</ItemGroup>

Expand Down
4 changes: 2 additions & 2 deletions clients/Qwack.Excel.Next/QwackDna.dna
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
<group id='Info' label='Info' visible='true'>
<button id='About' label='About' size='large' imageMso='CustomActionsMenu' onAction='DisplayAbout' visible='true'/>
</group >
<group id='Settings' label='Settings' visible='true'>
<group id='Settings' label='Settings' visible='true'>
<button id='ToggleThreading' label='Toggle MT' size='large' imageMso='CustomActionsMenu' onAction='ToggleThreadding' visible='true'/>
<button id='FlushCaches' label='Flush Caches' size='large' imageMso='CustomActionsMenu' onAction='FlushCaches' visible='true'/>
</group >
</group >
</tab>
</tabs>
</ribbon>
Expand Down
Loading

0 comments on commit 3fe212e

Please sign in to comment.