Skip to content

Commit

Permalink
TRS integrations
Browse files Browse the repository at this point in the history
  • Loading branch information
gavbrennan committed Oct 8, 2023
1 parent d64666e commit 133a7e2
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 8 deletions.
25 changes: 19 additions & 6 deletions src/Qwack.Core/Instruments/Asset/AssetTRS.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Qwack.Core.Basic;
using Qwack.Core.Instruments.Funding;
Expand All @@ -15,9 +16,9 @@ public class AssetTrs : IAssetInstrument
{
public AssetTrs() { }

public AssetTrs(ITrsUnderlying underlying, TrsLegType assetLegResetType, SwapLegType fundingLegType, TrsLegType fundingLegResetType, FloatRateIndex rateIndex,
double notional, double fundingFixedRateOrMargin, FxConversionType fxConversionType, DateTime startDate, DateTime endDate, Currency currency, Calendar settleCalendar,
SwapPayReceiveType assetLegDirection=SwapPayReceiveType.Rec, string paymentOffset = "2b", double? initialFixing = null)
public AssetTrs(ITrsUnderlying underlying, TrsLegType assetLegResetType, SwapLegType fundingLegType, TrsLegType fundingLegResetType, FloatRateIndex rateIndex,
double notional, double fundingFixedRateOrMargin, FxConversionType fxConversionType, DateTime startDate, DateTime endDate, Currency currency, Calendar settleCalendar,
SwapPayReceiveType assetLegDirection = SwapPayReceiveType.Rec, string paymentOffset = "2b", double? initialFixing = null)
{
Underlying = underlying;
AssetLegResetType = assetLegResetType;
Expand All @@ -34,7 +35,7 @@ public AssetTrs(ITrsUnderlying underlying, TrsLegType assetLegResetType, SwapLeg
InitialAssetFixing = initialFixing;

FundingLegPaymentOffset = new Frequency(paymentOffset);
AssetLegPaymentOffset = new Frequency(paymentOffset);
AssetLegPaymentOffset = new Frequency(paymentOffset);

FundingLeg = new GenericSwapLeg(StartDate, EndDate, rateIndex.HolidayCalendars, rateIndex.Currency,
rateIndex.ResetTenor, rateIndex.DayCountBasis)
Expand All @@ -58,7 +59,7 @@ public AssetTrs(ITrsUnderlying underlying, TrsLegType assetLegResetType, SwapLeg
AssetId = Underlying.AssetIds[0],
PaymentOffset = AssetLegPaymentOffset,
PaymentCalendar = SettleCalendar
};
};

FlowScheduleFunding = FundingLeg.GenerateSchedule();
FlowScheduleAsset = AssetLeg.GenerateSchedule();
Expand Down Expand Up @@ -112,7 +113,7 @@ public AssetTrs(TO_AssetTrs to, ICurrencyProvider currencyProvider, ICalendarPro
public GenericSwapLeg AssetLeg { get; set; }
public CashFlowSchedule FlowScheduleAsset { get; set; }

public string TradeId { get; set; }
public string TradeId { get; set; }
public string Counterparty { get; set; }
public string PortfolioName { get; set; }

Expand Down Expand Up @@ -190,6 +191,18 @@ public Dictionary<string, List<DateTime>> PastFixingDates(DateTime valDate)

public IAssetInstrument SetStrike(double strike) => throw new NotImplementedException();

public double FlowsT0(IAssetFxModel model)
{
var flowsAsset = FlowScheduleAsset.FlowsT0(Currency, model, model.BuildDate);
var flowsFunding = FlowScheduleFunding.FlowsT0(Currency, model.FundingModel, ForecastFundingCurve, RateIndex.DayCountBasis, model.BuildDate);
return flowsAsset + flowsFunding;
}

public List<CashFlow> ExpectedCashFlows(IAssetFxModel model)
=> FlowScheduleAsset.ExpectedFlows(Currency, model, model.BuildDate)
.Concat(FlowScheduleFunding.ExpectedFlows(Currency, model.FundingModel, ForecastFundingCurve, RateIndex.DayCountBasis, model.BuildDate))
.ToList();

public TO_Instrument ToTransportObject() => new()
{
AssetInstrumentType = AssetInstrumentType.AssetTrs,
Expand Down
243 changes: 243 additions & 0 deletions src/Qwack.Core/Instruments/CashflowSchedule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -311,5 +311,248 @@ public static double PV(this CashFlowSchedule schedule, Currency reportingCCy, I
return totalPv;
}


public static double FlowsT0(this CashFlowSchedule schedule, Currency reportingCCy, IFundingModel model, string forecastCurve, DayCountBasis basisFloat, DateTime filterDate)
{
var totalPv = 0.0;
for (var i = 0; i < schedule.Flows.Count; i++)
{
var flow = schedule.Flows[i];

if (flow.SettleDate != filterDate)
continue;

double fv, pv;
var df = model.GetDf(reportingCCy, model.BuildDate, flow.SettleDate);
var fwdFxRate = model.GetFxRate(flow.SettleDate, flow.Currency, reportingCCy);

switch (flow.FlowType)
{
case FlowType.FixedRate:
{
var rateLin = flow.FixedRateOrMargin;
var yf = flow.YearFraction;
fv = rateLin * yf * flow.Notional;
fv *= fwdFxRate;
pv = fv * df;
totalPv += pv;
break;
}
case FlowType.FloatRate:
{
var s = flow.AccrualPeriodStart;
var e = flow.AccrualPeriodEnd;
var rateLin = model.GetCurve(forecastCurve).GetForwardRate(s, e, RateType.Linear, basisFloat);
rateLin += flow.FixedRateOrMargin;
var yf = flow.YearFraction;
fv = rateLin * yf * flow.Notional;
fv *= fwdFxRate;
pv = fv * df;
totalPv += pv;
break;
}
case FlowType.FixedAmount:
{
fv = flow.Notional;
fv *= fwdFxRate;
pv = fv * df;
totalPv += pv;
break;
}
}

}

return totalPv;
}

public static double FlowsT0(this CashFlowSchedule schedule, Currency reportingCCy, IAssetFxModel model, DateTime filterDate)
{
var totalPv = 0.0;
for (var i = 0; i < schedule.Flows.Count; i++)
{
var flow = schedule.Flows[i];

if (string.IsNullOrEmpty(flow.AssetId))
continue;
if (flow.SettleDate != filterDate)
continue;

double fv, pv;
var df = model.FundingModel.GetDf(reportingCCy, model.BuildDate, flow.SettleDate);
var fwdFxRate = model.FundingModel.GetFxRate(flow.SettleDate, flow.Currency, reportingCCy);
var curve = model.GetPriceCurve(flow.AssetId);
if (!model.TryGetFixingDictionary(flow.AssetId, out var assetFixings))
assetFixings = new FixingDictionary(new Dictionary<DateTime, double>());

switch (flow.FlowType)
{
case FlowType.AssetNotional:
{
var price = curve.GetPriceForFixingDate(flow.AccrualPeriodEnd);
var rateLin = flow.FixedRateOrMargin;
var yf = flow.YearFraction;
fv = rateLin * yf * flow.Notional * price;
fv *= fwdFxRate;
pv = fv * df;
totalPv += pv;
break;
}
case FlowType.AssetPerformance:
{
var s = flow.AccrualPeriodStart;
var e = flow.AccrualPeriodEnd;
var priceS = flow.InitialFixing ?? (assetFixings.TryGetValue(s, out var fs) ? fs : curve.GetPriceForFixingDate(s));
var priceE = assetFixings.TryGetValue(e, out var fe) ? fe : curve.GetPriceForFixingDate(e);
var rateLin = priceE / priceS - 1.0;
rateLin += flow.FixedRateOrMargin;
var yf = flow.YearFraction;
fv = rateLin * yf * flow.Notional;
fv *= fwdFxRate;
pv = fv * df;
totalPv += pv;
break;
}
case FlowType.FixedRate:
{
var rateLin = flow.FixedRateOrMargin;
var yf = flow.YearFraction;
fv = rateLin * yf * flow.Notional;
fv *= fwdFxRate;
pv = fv * df;
totalPv += pv;
break;
}
case FlowType.FixedAmount:
{
fv = flow.Notional;
fv *= fwdFxRate;
pv = fv * df;
totalPv += pv;
break;
}
}

}

return totalPv;
}

public static CashFlow[] ExpectedFlows(this CashFlowSchedule schedule, Currency reportingCCy, IFundingModel model, string forecastCurve, DayCountBasis basisFloat, DateTime filterDate)
{
List<CashFlow> flows = new(); ;
for (var i = 0; i < schedule.Flows.Count; i++)
{
var flow = schedule.Flows[i].Clone();
flows.Add(flow);
if (flow.SettleDate != filterDate)
continue;

var df = model.GetDf(reportingCCy, model.BuildDate, flow.SettleDate);
var fwdFxRate = model.GetFxRate(flow.SettleDate, flow.Currency, reportingCCy);

switch (flow.FlowType)
{
case FlowType.FixedRate:
{
var rateLin = flow.FixedRateOrMargin;
var yf = flow.YearFraction;
flow.Fv = rateLin * yf * flow.Notional;
flow.Fv *= fwdFxRate;
flow.Pv = flow.Fv * df;
break;
}
case FlowType.FloatRate:
{
var s = flow.AccrualPeriodStart;
var e = flow.AccrualPeriodEnd;
var rateLin = model.GetCurve(forecastCurve).GetForwardRate(s, e, RateType.Linear, basisFloat);
rateLin += flow.FixedRateOrMargin;
var yf = flow.YearFraction;
flow.Fv = rateLin * yf * flow.Notional;
flow.Fv *= fwdFxRate;
flow.Pv = flow.Fv * df;
break;
}
case FlowType.FixedAmount:
{
flow.Fv = flow.Notional * fwdFxRate;
flow.Pv = flow.Fv * df;
break;
}
}

}

return flows.ToArray();
}

public static CashFlow[] ExpectedFlows(this CashFlowSchedule schedule, Currency reportingCCy, IAssetFxModel model, DateTime filterDate)
{
var flows = new List<CashFlow>();
for (var i = 0; i < schedule.Flows.Count; i++)
{
var flow = schedule.Flows[i].Clone();
flows.Add(flow);
if (string.IsNullOrEmpty(flow.AssetId))
continue;
if (flow.SettleDate != filterDate)
continue;

var df = model.FundingModel.GetDf(reportingCCy, model.BuildDate, flow.SettleDate);
var fwdFxRate = model.FundingModel.GetFxRate(flow.SettleDate, flow.Currency, reportingCCy);
var curve = model.GetPriceCurve(flow.AssetId);
if (!model.TryGetFixingDictionary(flow.AssetId, out var assetFixings))
assetFixings = new FixingDictionary(new Dictionary<DateTime, double>());

switch (flow.FlowType)
{
case FlowType.AssetNotional:
{
var price = curve.GetPriceForFixingDate(flow.AccrualPeriodEnd);
var rateLin = flow.FixedRateOrMargin;
var yf = flow.YearFraction;
flow.Fv = rateLin * yf * flow.Notional * price;
flow.Fv *= fwdFxRate;
flow.Pv = flow.Fv * df;
break;
}
case FlowType.AssetPerformance:
{
var s = flow.AccrualPeriodStart;
var e = flow.AccrualPeriodEnd;
var priceS = flow.InitialFixing ?? (assetFixings.TryGetValue(s, out var fs) ? fs : curve.GetPriceForFixingDate(s));
var priceE = assetFixings.TryGetValue(e, out var fe) ? fe : curve.GetPriceForFixingDate(e);
var rateLin = priceE / priceS - 1.0;
rateLin += flow.FixedRateOrMargin;
var yf = flow.YearFraction;
flow.Fv = rateLin * yf * flow.Notional;
flow.Fv *= fwdFxRate;
flow.Pv = flow.Fv * df;
break;
}
case FlowType.FixedRate:
{
var rateLin = flow.FixedRateOrMargin;
var yf = flow.YearFraction;
flow.Fv = rateLin * yf * flow.Notional;
flow.Fv *= fwdFxRate;
flow.Pv = flow.Fv * df;
break;
}
case FlowType.FixedAmount:
{
flow.Fv = flow.Notional;
flow.Fv *= fwdFxRate;
flow.Pv = flow.Fv * df;
break;
}
}

}

return flows.ToArray();
}

}
}
2 changes: 2 additions & 0 deletions src/Qwack.Core/Instruments/InstrumentFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public static IInstrument GetInstrument(this TO_Instrument transportObject, ICur
return new EuropeanOption(transportObject.EuropeanOption, calendarProvider, currencyProvider);
case AssetInstrumentType.CashWrapper:
return new CashWrapper(transportObject.CashWrapper, currencyProvider, calendarProvider);
case AssetInstrumentType.AssetTrs:
return new AssetTrs(transportObject.AssetTrs, currencyProvider, calendarProvider);
}
}
else if(transportObject.FundingInstrumentType != FundingInstrumentType.None)
Expand Down
13 changes: 13 additions & 0 deletions src/Qwack.Models/Models/AssetProductEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,9 @@ public static (double Financing, double Option) Theta(this IInstrument ins, IAss
case FloatingRateLoanDepo loanDepoFl:
pv = loanDepoFl.Pv(model.FundingModel, false);
break;
case AssetTrs trs:
pv = trs.PV(model);
break;
case IFundingInstrument fundInst:
pv = fundInst.Pv(model.FundingModel, false);
break;
Expand Down Expand Up @@ -1084,6 +1087,9 @@ private static (double pv, string ccy, string tradeId, string tradeType) Compute
case InflationSwap cpi2:
pv = (cpi2.Clone() as InflationSwap).Pv(model.FundingModel, true);
break;
case AssetTrs trs:
pv = (trs.Clone() as AssetTrs).PV(model);
break;
case CashWrapper wrapper:
(pv, ccy, tradeId, tradeType) = ComputePV(wrapper.UnderlyingInstrument, model, pvCcy, ignoreTodayFlows);
if (reportingCurrency != null)
Expand Down Expand Up @@ -1168,6 +1174,9 @@ private static (double flow, string tradeId, string tradeType, string ccy) Compu
case InflationPerformanceSwap ips:
flow = ips.FlowsT0(model.FundingModel);
break;
case AssetTrs trs:
flow = trs.FlowsT0(model);
break;
case CashBalance:
case CashAsset:
case STIRFuture:
Expand Down Expand Up @@ -1226,6 +1235,9 @@ private static (List<CashFlow> flows, string tradeId, string tradeType) ComputeE
case Forward fwd:
flows = fwd.ExpectedCashFlows(model);
break;
case AssetTrs trs:
flows = trs.ExpectedCashFlows(model);
break;
case CashWrapper wrapper:
(flows, tradeId, tradeType) = ComputeExpectedCashFlows(wrapper.UnderlyingInstrument, model);
flows = flows.Concat(wrapper.CashBalances.SelectMany(cb => cb.ExpectedCashFlows(model))).ToList();
Expand Down Expand Up @@ -1271,6 +1283,7 @@ public static string TradeType(this IInstrument ins)
IrBasisSwap => "IRBasisSwap",
InflationPerformanceSwap => "InfPerfSwap",
InflationSwap => "InfSwap",
AssetTrs => "TRS",
CashWrapper wrapper => TradeType(wrapper.UnderlyingInstrument),
_ => throw new Exception($"Unable to handle product of type {ins.GetType()}"),
};
Expand Down
2 changes: 1 addition & 1 deletion version.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project>
<PropertyGroup>
<VersionPrefix>0.7.42</VersionPrefix>
<VersionPrefix>0.7.43</VersionPrefix>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.7.42
0.7.43

0 comments on commit 133a7e2

Please sign in to comment.