/// <summary> /// Initializes a new instance of the <see cref="RateBasisCurve"/> class. /// </summary> /// <param name="logger">The logger.</param> /// <param name="cache">The cache.</param> /// <param name="nameSpace">The client namespace</param> /// <param name="referenceCurveData">The market data. This must contain both the underlying base curve and the spread curve. /// Otherwise the RateBasisInterpolator can not instantiate.</param> /// <param name="derivedCurveData">The spread Curve Data</param> /// <param name="fixingCalendar">The fixingCalendar.</param> /// <param name="rollCalendar">The rollCalendar.</param> public ClearedRateCurve(ILogger logger, ICoreCache cache, String nameSpace, Triplet <PricingStructure, PricingStructureValuation, NamedValueSet> referenceCurveData, Triplet <PricingStructure, PricingStructureValuation, NamedValueSet> derivedCurveData, IBusinessCalendar fixingCalendar, IBusinessCalendar rollCalendar) : base(derivedCurveData.Third, GenerateHolder(logger, cache, nameSpace, derivedCurveData.Third)) { PricingStructureData = new PricingStructureData(CurveType.Child, AssetClass.Rates, derivedCurveData.Third); var curveId = GetRateCurveId(); //Set the identifier. var nvs = derivedCurveData.Third; var pricingStructureId = GetRateCurveId(); var refCurveId = PropertyHelper.ExtractReferenceCurveUniqueId(nvs); ReferenceDiscountingCurveId = refCurveId != null ? new Identifier(refCurveId) : ReferenceDiscountingCurveId = null; if (pricingStructureId.PricingStructureType != PricingStructureTypeEnum.ClearedRateCurve) { return; } //Set the reference curve var baseCurveFpml = new Pair <PricingStructure, PricingStructureValuation>(referenceCurveData.First, referenceCurveData.Second); var baseCurveProps = referenceCurveData.Third; BaseDiscountingCurve = (IRateCurve)PricingStructureFactory.Create(logger, cache, nameSpace, fixingCalendar, rollCalendar, baseCurveFpml, baseCurveProps); //Get the spread Data var spreadCurveFpml = new Pair <PricingStructure, PricingStructureValuation>(derivedCurveData.First, derivedCurveData.Second); //Override properties. //var optimize = PropertyHelper.ExtractOptimizeBuildFlag(properties); var bootstrap = PropertyHelper.ExtractBootStrapOverrideFlag(nvs); var tempFpml = (YieldCurveValuation)spreadCurveFpml.Second; var spreadAssets = tempFpml.inputs; //This is to catch it when there are no discount factor points. var discountsAbsent = tempFpml.discountFactorCurve?.point == null || tempFpml.discountFactorCurve.point.Length == 0; var indexTenor = curveId.ForecastRateIndex?.indexTenor; if (bootstrap || discountsAbsent) { //There must be a valid quoted asset set in order to bootstrap. if (!XsdClassesFieldResolver.QuotedAssetSetIsValid(spreadAssets)) { return; } PriceableClearedRateAssets = PriceableAssetFactory.CreatePriceableClearedRateAssetsWithBasisSwaps(logger, cache, nameSpace, indexTenor, spreadAssets, pricingStructureId.BaseDate, fixingCalendar, rollCalendar); GetYieldCurveValuation().zeroCurve = null; TermCurve termCurve = tempFpml.discountFactorCurve ?? SetConfigurationData(); DateTime baseDate = GetYieldCurveValuation().baseDate.Value; termCurve.point = ClearedRateBootstrapper.Bootstrap(PriceableClearedRateAssets, BaseDiscountingCurve, baseDate, termCurve.extrapolationPermitted, termCurve.interpolationMethod, Tolerance); SetFpMLData(new Pair <PricingStructure, PricingStructureValuation>(PricingStructure, PricingStructureValuation), false); SetInterpolator(termCurve); } else { // the discount curve is already built, so don't rebuild PriceableClearedRateAssets = PriceableAssetFactory.CreatePriceableClearedRateAssetsWithBasisSwaps(logger, cache, nameSpace, indexTenor, spreadAssets, pricingStructureId.BaseDate, fixingCalendar, rollCalendar); //Order the assets. PriceableClearedRateAssets = PriceableClearedRateAssets.OrderBy(a => a.GetRiskMaturityDate()).ToList(); CreatePricingStructure(pricingStructureId, tempFpml.discountFactorCurve, spreadAssets); // CreatePricingStructure(pricingStructureId, tempFpml.discountFactorCurve, PriceableAssetFactory.Parse(PriceableClearedRateAssets)); SetInterpolator(GetYieldCurveValuation().discountFactorCurve); } }
/// <summary> /// Initializes a new instance of the <see cref="CommoditySpreadCurve2"/> class. /// </summary> /// <param name="logger">The logger.</param> /// <param name="cache">The cache.</param> /// <param name="nameSpace">The client namespace</param> /// <param name="referenceCurveData">The market data. This must contain both the underlying base curve and the spread curve. /// Otherwise the RateBasisInterpolator can not instantiate.</param> /// <param name="spreadCurveData">The spread Curve Data</param> /// <param name="rollCalendar">The rollCalendar.</param> public CommoditySpreadCurve2(ILogger logger, ICoreCache cache, String nameSpace, Triplet <PricingStructure, PricingStructureValuation, NamedValueSet> referenceCurveData, Triplet <PricingStructure, PricingStructureValuation, NamedValueSet> spreadCurveData, IBusinessCalendar rollCalendar) : base(spreadCurveData.Third, GenerateHolder(logger, cache, nameSpace, spreadCurveData.Third)) { PricingStructureData = new PricingStructureData(CurveType.Child, AssetClass.Rates, spreadCurveData.Third); //Set the identifier. var nvs = spreadCurveData.Third; var pricingStructureId = GetCommodityCurveId(); var refCurveId = PropertyHelper.ExtractReferenceCurveUniqueId(nvs); ReferenceCurveId = refCurveId != null ? new Identifier(refCurveId) : ReferenceCurveId = null; if (pricingStructureId.PricingStructureType != PricingStructureTypeEnum.CommoditySpreadCurve) { return; } //Set the reference curve var baseCurveFpml = new Pair <PricingStructure, PricingStructureValuation>(referenceCurveData.First, referenceCurveData.Second); var baseCurveProps = referenceCurveData.Third; BaseCurve = (ICommodityCurve)PricingStructureFactory.Create(logger, cache, nameSpace, rollCalendar, rollCalendar, baseCurveFpml, baseCurveProps); //Get the spread Data var spreadCurveFpml = new Pair <PricingStructure, PricingStructureValuation>(spreadCurveData.First, spreadCurveData.Second); //Override properties. //var optimize = PropertyHelper.ExtractOptimizeBuildFlag(properties); var bootstrap = PropertyHelper.ExtractBootStrapOverrideFlag(nvs); var tempFpml = (FxCurveValuation)spreadCurveFpml.Second; var spreadAssets = tempFpml.spotRate; //This is to catch it when there are no discount factor points. var discountsAbsent = tempFpml.fxForwardCurve == null || tempFpml.fxForwardCurve.point == null || tempFpml.fxForwardCurve.point.Length == 0; if (bootstrap || discountsAbsent) { //There must be a valid quotedassetset in order to bootstrap. if (!XsdClassesFieldResolver.QuotedAssetSetIsValid(spreadAssets)) { return; } PriceableCommoditySpreadAssets = PriceableAssetFactory.CreatePriceableCommoditySpreadAssets(logger, cache, nameSpace, pricingStructureId.BaseDate, spreadAssets, rollCalendar); Build(logger, cache, nameSpace, rollCalendar, rollCalendar); } else { // the discount curve is already built, so don't rebuild PriceableCommoditySpreadAssets = PriceableAssetFactory.CreatePriceableCommoditySpreadAssets(logger, cache, nameSpace, pricingStructureId.BaseDate, spreadAssets, rollCalendar); //Order the assets. PriceableCommoditySpreadAssets = PriceableCommoditySpreadAssets.OrderBy(a => a.GetRiskMaturityDate()).ToList(); CreatePricingStructure(pricingStructureId, tempFpml.fxForwardCurve, PriceableAssetFactory.Parse(PriceableCommoditySpreadAssets)); //SetInterpolator(BaseCurve, pricingStructureId.PricingStructureType); } }
/// <summary> /// Publishes a curve. /// </summary> /// <param name="structurePropertiesRange">The structure properties range.</param> /// <param name="publishPropertiesRange">The publish properties range.</param> /// <param name="valuesRange">The values range.</param> /// <returns></returns> public string PublishCurve(object[][] structurePropertiesRange, object[][] publishPropertiesRange, object[][] valuesRange) { // Create curve IPricingStructure pricingStructure = PricingStructureFactory.CreatePricingStructure(Logger.Target, Cache, NameSpace, structurePropertiesRange, valuesRange); // Get properties needed Market market = GetMarket(pricingStructure); string uniqueIdentifier = pricingStructure.GetPricingStructureId().UniqueIdentifier; NamedValueSet properties = pricingStructure.GetPricingStructureId().Properties; // Save Publish(market, uniqueIdentifier, properties, publishPropertiesRange); return(uniqueIdentifier); }
/// <summary> /// Create a Sortedlist of volatility curves from the data matrix /// </summary> /// <param name="logger">The logger.</param> /// <param name="cache">The cache.</param> /// <param name="nameSpace">The client namespace</param> /// <param name="properties">The properties, including the engine handle.</param> /// <param name="instruments">An array of instrument types.</param> /// <param name="rawVolatilityGrid">The raw grid used to build the engines. Assume that all volatility and strike values are 100x true</param> /// <returns></returns> private SortedList <decimal, VolatilityCurve> VolatilityCurveCreate(ILogger logger, ICoreCache cache, string nameSpace, NamedValueSet properties, String[] instruments, Decimal[] rawVolatilityGrid) { var clonedProperties = properties.Clone(); // Create engine var quotedAssetSet = AssetHelper.Parse(instruments, rawVolatilityGrid, null); var engines = new SortedList <decimal, VolatilityCurve>(); // Create a new ATM CapletBootstrap engine. The default decimal should be 0 var volatilityCurve = PricingStructureFactory.CreateCurve(logger, cache, nameSpace, null, null, clonedProperties, quotedAssetSet); // Add engine if (volatilityCurve is VolatilityCurve vCurve) { engines.Add(0, vCurve); } return(engines); }
/// <summary> /// Publishes the volatility cube. /// </summary> /// <param name="structurePropertiesRange">The structure properties range.</param> /// <param name="publishPropertiesRange">The publish properties range.</param> /// <param name="strikesOrTenorsRange">The strikes or tenors range.</param> /// <param name="valuesRange">The values range.</param> /// <returns></returns> public string PublishVolatilityCube(object[][] structurePropertiesRange, object[][] publishPropertiesRange, object[][] strikesOrTenorsRange, object[][] valuesRange) { // Translate into useful objects NamedValueSet structureProperties = structurePropertiesRange.ToNamedValueSet(); var data = (object[, ])PricingStructureFactory.TrimNulls(valuesRange.ConvertArrayToMatrix()); decimal[] strikes = strikesOrTenorsRange.ConvertToOneDimensionalArray <decimal>(); string[] expiries = PricingStructureFactory.ExtractExpiries(data).Distinct().ToArray(); string[] tenors = PricingStructureFactory.ExtractTenors(data).Distinct().ToArray(); decimal[,] vols = PricingStructureFactory.ConvertToDecimalArray(data, 2); // Create curve var volatilityCube = new VolatilityCube(structureProperties, expiries, tenors, vols, strikes); // Get properties needed Market market = GetMarket(volatilityCube); string uniqueIdentifier = volatilityCube.GetPricingStructureId().UniqueIdentifier; NamedValueSet properties = volatilityCube.GetPricingStructureId().Properties; // Save Publish(market, uniqueIdentifier, properties, publishPropertiesRange); return(uniqueIdentifier); }
/// <summary> /// Create a Sortedlist of bootstrap engines from the data matrix /// </summary> /// <param name="logger">The logger.</param> /// <param name="cache">The cache.</param> /// <param name="nameSpace">The client namespace</param> /// <param name="properties">The properties, including the engine handle.</param> /// <param name="instruments">An array of instrument types.</param> /// <param name="strikes">The strike array.</param> /// <param name="rawVolatilityGrid">The raw grid used to build the engines. Assume that all volatility and strike values are 100x true</param> /// <returns></returns> private SortedList <decimal, VolatilityCurve> VolatilityCurvesCreate(ILogger logger, ICoreCache cache, string nameSpace, NamedValueSet properties, String[] instruments, Decimal[] strikes, Decimal[,] rawVolatilityGrid) { var clonedProperties = properties.Clone(); // Check there are valid strikes if (strikes != null && rawVolatilityGrid != null) { //The matrix is zero based, but the upper bound returns the last column index. var volColumns = rawVolatilityGrid.GetUpperBound(1) + 1; var columns = Math.Min(strikes.Length, volColumns); var engines = new SortedList <decimal, VolatilityCurve>(); // Loop through the strikes to create each new engine for (var i = 0; i < columns; i++) { decimal[] adjustedRates = GenerateVolatilityMatrix(instruments, i, rawVolatilityGrid); clonedProperties.Set("Strike", strikes[i]); clonedProperties.Set("StrikeQuoteUnits", StrikeQuoteUnitsEnum.DecimalRate.ToString()); // Create engine var quotedAssetSet = AssetHelper.Parse(instruments, adjustedRates, null); var engine = PricingStructureFactory.CreateCurve(logger, cache, nameSpace, null, null, clonedProperties, quotedAssetSet) as VolatilityCurve; // Add engine engines.Add(strikes[i], engine); } return(engines); } { var engines = new SortedList <decimal, VolatilityCurve>(); // Create a new ATM CapletBootstrap engine. The default decimal should be 0 var engine = PricingStructureFactory.CreateCurve(logger, cache, nameSpace, null, null, clonedProperties, instruments, null, null) as VolatilityCurve; // Add engine engines.Add(0, engine); return(engines); } }
/// <summary> /// Initializes a new instance of the <see cref="RateXccySpreadCurve"/> class. /// </summary> /// <param name="logger">The logger.</param> /// <param name="cache">The cache.</param> /// <param name="nameSpace">THe client namespace</param> /// <param name="baseCurveData">The market data. This must contain both the underlying base curve and the spread curve. /// Otherwise the RateBasisInterpolator can not instantiate.</param> /// <param name="referenceFxCurveData">The fxcurve referenced.</param> /// <param name="currency2CurveData">The curve data for the non base curve. This is normally the domestic curve i.e. AUD, /// as FX is quotes as xccy basis swaps adjust on the non-USD leg.</param> /// <param name="spreadCurveData">The spread Curve Data</param> /// <param name="fixingCalendar">The fixingCalendar.</param> /// <param name="rollCalendar">The rollCalendar.</param> public RateXccySpreadCurve(ILogger logger, ICoreCache cache, string nameSpace, Triplet <PricingStructure, PricingStructureValuation, NamedValueSet> baseCurveData, Triplet <PricingStructure, PricingStructureValuation, NamedValueSet> referenceFxCurveData, Triplet <PricingStructure, PricingStructureValuation, NamedValueSet> currency2CurveData, Triplet <PricingStructure, PricingStructureValuation, NamedValueSet> spreadCurveData, IBusinessCalendar fixingCalendar, IBusinessCalendar rollCalendar) : base(logger, cache, nameSpace, spreadCurveData, fixingCalendar, rollCalendar) { //Set the identifier. var nvs = spreadCurveData.Third; var pricingStructureId = new RateCurveIdentifier(nvs); PricingStructureIdentifier = pricingStructureId; var refCurveId = nvs.GetValue <string>(CurveProp.ReferenceCurveUniqueId); ReferenceCurveId = refCurveId != null ? new Identifier(refCurveId) : ReferenceCurveId = null; if (pricingStructureId.PricingStructureType != PricingStructureTypeEnum.RateXccyCurve) { return; } //Set the curve term. var cutOverTerm = spreadCurveData.Third.GetValue <string>("CutOverTerm"); if (cutOverTerm != null) { CutOverTerm = PeriodHelper.Parse(cutOverTerm); } //Set the reference curve var baseCurveFpML = new Pair <PricingStructure, PricingStructureValuation>(baseCurveData.First, baseCurveData.Second); var baseCurveProps = baseCurveData.Third; BaseCurve = (IRateCurve)PricingStructureFactory.Create(logger, cache, nameSpace, fixingCalendar, rollCalendar, baseCurveFpML, baseCurveProps); var fxCurveFpML = new Pair <PricingStructure, PricingStructureValuation>(referenceFxCurveData.First, referenceFxCurveData.Second); var fxCurveProps = referenceFxCurveData.Third; ReferenceFxCurve = (IFxCurve)PricingStructureFactory.Create(logger, cache, nameSpace, fixingCalendar, rollCalendar, fxCurveFpML, fxCurveProps); //Set the reference curve var currency2CurveFpML = new Pair <PricingStructure, PricingStructureValuation>(currency2CurveData.First, currency2CurveData.Second); var currency2CurveProps = currency2CurveData.Third; Currency2Curve = (RateCurve)PricingStructureFactory.Create(logger, cache, nameSpace, fixingCalendar, rollCalendar, currency2CurveFpML, currency2CurveProps); //Get the spread Data var spreadCurveFpML = new Pair <PricingStructure, PricingStructureValuation>(spreadCurveData.First, spreadCurveData.Second); var spreadCurveProps = spreadCurveData.Third; IsCurrency1RateCurve = spreadCurveProps.GetValue <bool>("Currency1RateCurve"); //Override properties. //var optimize = PropertyHelper.ExtractOptimizeBuildFlag(properties);TODO add this later. var bootstrap = PropertyHelper.ExtractBootStrapOverrideFlag(nvs); var tempFpml = (YieldCurveValuation)spreadCurveFpML.Second; var spreadAssets = tempFpml.inputs; //This is to catch it when there are no discount factor points. var discountsAbsent = tempFpml.discountFactorCurve?.point == null || tempFpml.discountFactorCurve.point.Length == 0; if (cache == null) { bootstrap = false; } if (bootstrap || discountsAbsent) { //There must be a valid quoted asset set in order to bootstrap. if (!XsdClassesFieldResolver.QuotedAssetSetIsValid(spreadAssets)) { return; } PriceableRateSpreadAssets = PriceableAssetFactory.CreatePriceableRateSpreadAssets(logger, cache, nameSpace, pricingStructureId.BaseDate, spreadAssets, fixingCalendar, rollCalendar); Build(logger, cache, nameSpace, fixingCalendar, rollCalendar); } else { if (cache != null) { // the discount curve is already built, so don't rebuild PriceableRateSpreadAssets = PriceableAssetFactory.CreatePriceableRateSpreadAssets(logger, cache, nameSpace, pricingStructureId.BaseDate, spreadAssets, fixingCalendar, rollCalendar); CreatePricingStructure(pricingStructureId, tempFpml.discountFactorCurve, PriceableAssetFactory.Parse(PriceableRateSpreadAssets)); SetInterpolator(BaseCurve, pricingStructureId.PricingStructureType); } else { CreatePricingStructure(pricingStructureId, tempFpml.discountFactorCurve, spreadAssets); SetInterpolator(BaseCurve, pricingStructureId.PricingStructureType); } } }
public void ProcessRequest(RequestBase request, HandlerResponse response) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var tradeValRequest = request as TradeValuationRequest; if (tradeValRequest == null) { throw new InvalidCastException( $"{typeof(RequestBase).Name} is not a {typeof(TradeValuationRequest).Name}"); } DateTime lastStatusPublishedAt = DateTime.Now; var nameSpace = tradeValRequest.NameSpace; // common properties string reportingCurrency = tradeValRequest.ReportingCurrency; string market = tradeValRequest.MarketName; // build a single trade portfolio var tradeItemInfos = new Dictionary <string, ICoreItemInfo>(); ICoreItemInfo tradeItemInfo = Context.Cache.LoadItemInfo <Trade>(tradeValRequest.TradeItemName); if (tradeItemInfo != null) { tradeItemInfos[tradeValRequest.TradeItemName] = tradeItemInfo; } // define scenario loops // - always include un-stressed scenario (null) var irScenarios = new List <string> { null }; if (tradeValRequest.IRScenarioNames != null) { irScenarios.AddRange(tradeValRequest.IRScenarioNames); } string[] irScenarioNames = irScenarios.Distinct().ToArray(); var fxScenarios = new List <string> { null }; if (tradeValRequest.FXScenarioNames != null) { fxScenarios.AddRange(tradeValRequest.FXScenarioNames); } string[] fxScenarioNames = fxScenarios.Distinct().ToArray(); // update progress status response.ItemCount = irScenarios.Count * fxScenarios.Count * tradeItemInfos.Count; response.Status = RequestStatusEnum.InProgress; Context.Cache.SaveObject(response); // preload *all* curves into the cache // note: this is required to optimise all subsequent curve queries Context.Cache.LoadItems <Market>(Expr.ALL); // load and sort scenario definition rules var clauses = new List <IExpression> { Expr.IsEQU(EnvironmentProp.NameSpace, nameSpace) }; var scenarioRules = Context.Cache.LoadObjects <ScenarioRule>(Expr.BoolAND(clauses.ToArray())); var sortedScenarioRules = new List <CachedScenarioRule>(); { sortedScenarioRules.AddRange(from scenarioRule in scenarioRules where !scenarioRule.Disabled select new CachedScenarioRule(scenarioRule.ScenarioId, scenarioRule.RuleId, scenarioRule.Priority, (scenarioRule.FilterExpr != null) ? Expr.Create(scenarioRule.FilterExpr) : Expr.ALL, scenarioRule.StressId)); } sortedScenarioRules.Sort(); // build distinct lists of curve names and currencies required by the Trade var curvenamesList = new List <string>(); var currenciesList = new List <string>(); foreach (var item in tradeItemInfos.Values) { curvenamesList.AddRange(item.AppProps.GetArray <string>(TradeProp.RequiredPricingStructures)); currenciesList.AddRange(item.AppProps.GetArray <string>(TradeProp.RequiredCurrencies)); } curvenamesList = new List <string>(curvenamesList.Distinct().Where(x => !String.IsNullOrEmpty(x))); currenciesList = new List <string>(currenciesList.Distinct().Where(x => !String.IsNullOrEmpty(x))); IEnumerable <string> metrics = GetSwapMetrics(); // run the scenario rules ONCE for each IR and FX scenario to determine which // stressed curves to use when pricing. var resolvedCurveProps = new Dictionary <string, NamedValueSet>(); // IR loop var irScenarioCurveMap = new List <CurveStressPair> [irScenarioNames.Length]; for (int i = 0; i < irScenarioNames.Length; i++) { string irScenario = irScenarioNames[i]; irScenarioCurveMap[i] = new List <CurveStressPair>(); foreach (string curveName in curvenamesList) { string curveSignature = CurveLoader.IrCurveSignature(market, curveName, null); NamedValueSet curveProperties; if (!resolvedCurveProps.TryGetValue(curveSignature, out curveProperties)) { // not cached - resolve and cache curveProperties = PricingStructureFactory.GetInterestRateCurveProperties(Context.Logger, Context.Cache, request.NameSpace, market, curveName, null); resolvedCurveProps[curveSignature] = curveProperties; } string stressName = CachedScenarioRule.RunScenarioRules(sortedScenarioRules, irScenario, curveProperties); irScenarioCurveMap[i].Add(new CurveStressPair(curveName, stressName)); } } // FX loop var fxScenarioCurveMap = new List <CurveStressPair> [fxScenarioNames.Length]; for (int j = 0; j < fxScenarioNames.Length; j++) { string fxScenario = fxScenarioNames[j]; fxScenarioCurveMap[j] = new List <CurveStressPair>(); foreach (string currency in currenciesList) { string curveSignature = CurveLoader.FxCurveSignature(market, currency, reportingCurrency, null); NamedValueSet curveProperties; if (!resolvedCurveProps.TryGetValue(curveSignature, out curveProperties)) { // not cached - resolve and cache curveProperties = PricingStructureFactory.GetFxCurveProperties(Context.Logger, Context.Cache, request.NameSpace, market, currency, reportingCurrency); resolvedCurveProps[curveSignature] = curveProperties; } string stressName = CachedScenarioRule.RunScenarioRules(sortedScenarioRules, fxScenario, curveProperties); fxScenarioCurveMap[j].Add(new CurveStressPair(currency, stressName)); } } // iterate the scenario loops var resolvedCurveCache = new Dictionary <string, ICurve>(); var reportNameCache = new Dictionary <string, string>(); for (int i = 0; i < irScenarioNames.Length; i++) { string irScenario = irScenarioNames[i]; for (int j = 0; j < fxScenarioNames.Length; j++) { string fxScenario = fxScenarioNames[j]; // check for workflow cancellation (user abort, server shutdown etc.) if (Cancelled) { throw new OperationCanceledException(CancelReason); } // initialise the pricer with the IR/FX scenario curve maps var pricer = new PortfolioPricer(irScenarioCurveMap[i], fxScenarioCurveMap[j]); // now price the Trade if (metrics != null) { var enumerable = metrics.ToArray(); pricer.PriceAndPublish( Context.Logger, Context.Cache, resolvedCurveCache, reportNameCache, response, tradeItemInfos.Keys, tradeValRequest, irScenario, fxScenario, reportingCurrency, tradeValRequest.BaseParty, enumerable, false); } // export to valuation database //foreach (var valuationItem in valuationItems) //{ // ExportValuation(valuationItem); //} DateTime dtNow = DateTime.Now; if ((dtNow - lastStatusPublishedAt) > TimeSpan.FromSeconds(5)) { lastStatusPublishedAt = dtNow; response.Status = RequestStatusEnum.InProgress; Context.Cache.SaveObject(response); } } // foreach ir scenario } // foreach fx scenario // success response.Status = RequestStatusEnum.Completed; }
public void ProcessItems() { int count = Interlocked.Decrement(ref _queuedCalls); // exit if there are more callbacks following us //if (count % 10000 == 0) _loggerRef.Target.LogDebug("ProcessItems: Queued calls remaining: {0}", count); if (count != 0) { return; } ICoreItem item = null; _queuedItems.Locked(queue => { if (queue.Count > 0) { item = queue.Dequeue(); } }); while (item != null) { var qas = item.Data as QuotedAssetSet; if (qas != null) { // 1. Get the property values that uniquely identify the curves to refresh. // This is the process for the workflow request. Alternatively, a direct build of the curve can occur. // var nameSpace = item.AppProps.GetValue <string>(EnvironmentProp.NameSpace); var market = item.AppProps.GetValue <string>(CurveProp.Market);//For real time use Market and not MarketAndDate var curveType = item.AppProps.GetValue <string>(CurveProp.PricingStructureType); var curveName = item.AppProps.GetValue <string>(CurveProp.CurveName); var configIdentifier = FunctionProp.Configuration + ".PricingStructures." + market + "." + curveType + "." + curveName; var identifier = FunctionProp.Market + "." + market + "." + curveType + "." + curveName; List <ICoreItem> items = null; // 2.Check if the dependent curves should be refreshed // if (chkBoxDependentCurves.Checked) { //Find all the QAS's where the ReferenceCurveName is equal to the curveType.curveName! var requestProperties = new NamedValueSet(); requestProperties.Set(EnvironmentProp.NameSpace, NameSpace); requestProperties.Set(CurveProp.Market, market); requestProperties.Set(EnvironmentProp.Function, FunctionProp.Configuration); requestProperties.Set(CurveProp.ReferenceCurveName, curveType + '.' + curveName); IExpression queryExpr = Expr.BoolAND(requestProperties); _loggerRef.Target.LogDebug("Dependent curve property request set at {0}", DateTime.Now.ToLongTimeString()); items = _cache.LoadItems <Market>(queryExpr); } // 3. If the build is a local build then use the curve engine. // if (!chkBoxWorkflow.Checked) { _loggerRef.Target.LogDebug("Request to build base curve {0} locally at : {1}", identifier, DateTime.Now.ToLongTimeString()); var curve = CurveEngine.RefreshPricingStructureFromConfiguration(_loggerRef.Target, _cache, nameSpace, configIdentifier, identifier, qas, DateTime.Now, DateTime.Now); _loggerRef.Target.LogDebug("Built the base curve {0} locally at : {1}", curve, DateTime.Now.ToLongTimeString()); if (items != null) { foreach (var dataItem in items) { var spreadCurve = dataItem.Data as Market; if (spreadCurve == null) { continue; } //var bootstrap = dataItem.AppProps.GetValue<bool>(CurveProp.BootStrap, false); //if (!bootstrap) { dataItem.AppProps.Set(CurveProp.BootStrap, true); } try { var curveId = spreadCurve.id; if (String.IsNullOrEmpty(curveId)) { curveId = spreadCurve.Items[0].id; //use yieldCurve.id, CurveGen 1.X compatible } dataItem.AppProps.Set(CurveProp.BaseDate, DateTime.Now); dataItem.AppProps.Set(CurveProp.BuildDateTime, DateTime.Now); var marketData = new Pair <PricingStructure, PricingStructureValuation>(spreadCurve.Items[0], spreadCurve.Items1[0]); var ps = PricingStructureFactory.Create(_loggerRef.Target, _cache, nameSpace, null, null, marketData, dataItem.AppProps); if (ps != null) { CurveEngine.SaveCurve(_cache, nameSpace, ps); } _loggerRef.Target.LogDebug("Built the spread curve {0} locally at : {1}", curveId, DateTime.Now.ToLongTimeString()); } catch (Exception e) { _loggerRef.Target.LogDebug(e.ToString()); } } } } else { // 4. Set the parameters for the work request. // var curveGenRequest = new OrdinaryCurveGenRequest { NameSpace = nameSpace, BaseDate = DateTime.Now, RequestId = Guid.NewGuid().ToString(), RequesterId = new UserIdentity { Name = _cache.ClientInfo.Name, DisplayName = _cache.ClientInfo.UserFullName //Name = _clientRef.Target.ClientInfo.Name, //DisplayName = _clientRef.Target.ClientInfo.UserFullName }, UseSavedMarketData = true, ForceGenerateEODCurves = true }; // 5. Set the base curve in the curve selection for the work request. // var curveSelector = new List <CurveSelection> { new CurveSelection { NameSpace = nameSpace, MarketName = market, CurveType = curveType, CurveName = curveName } }; // 6.Include all other dependent curvenames i.e. spread curves. // if (items != null) { curveSelector.AddRange(from childCurve in items let spreadCurveType = childCurve.AppProps.GetValue <string>( CurveProp.PricingStructureType) let spreadCurveName = childCurve.AppProps.GetValue <string>(CurveProp.CurveName) select new CurveSelection { NameSpace = nameSpace, MarketName = market, CurveType = spreadCurveType, CurveName = spreadCurveName }); } curveGenRequest.CurveSelector = curveSelector.ToArray(); // 7. Set the actual work request. // IWorkContext context = new WorkContext(_loggerRef.Target, _cache, "DEV"); //IWorkContext context = new WorkContext(_loggerRef.Target, _clientRef.Target, "DEV"); _loggerRef.Target.LogDebug("WorkContext set at {0}", DateTime.Now.ToLongTimeString()); using (var workflow = new WFGenerateOrdinaryCurve()) { workflow.Initialise(context); WorkflowOutput <HandlerResponse> output = workflow.Execute(curveGenRequest); WorkflowHelper.ThrowErrors(output.Errors); foreach (var error in output.Errors) { _loggerRef.Target.LogInfo("WorkFlow error: {0} at {1}", error.Message, DateTime.Now.ToLongTimeString()); } } _loggerRef.Target.LogDebug("WorkFlow executed at {0}", DateTime.Now.ToLongTimeString()); //item = null; //_queuedItems.Locked(queue => // { // if (queue.Count > 0) // item = queue.Dequeue(); // }); } } } }
public void ProcessRequest(RequestBase baseRequest, HandlerResponse response) { if (baseRequest == null) { throw new ArgumentNullException(nameof(baseRequest)); } if (!(baseRequest is PortfolioValuationRequest request)) { throw new InvalidCastException( $"{typeof(RequestBase).Name} is not a {typeof(PortfolioValuationRequest).Name}"); } DateTime lastStatusPublishedAt = DateTime.Now; // common properties var nameSpace = request.NameSpace; string reportingCurrency = request.ReportingCurrency; string baseParty = request.BaseParty; string market = request.MarketName; // resolve portfolio valuation request var identifier = (new PortfolioSpecification(request.PortfolioId, request.NameSpace)).NetworkKey; var portfolio = Context.Cache.LoadObject <PortfolioSpecification>(identifier); if (portfolio == null) { throw new ArgumentException($"Unknown portfolio id: '{request.PortfolioId}'"); } // build trade query from portfolio definition var tradeItemInfos = new Dictionary <string, ICoreItemInfo>(); if (portfolio.PortfolioSubqueries != null) { foreach (var subQuery in portfolio.PortfolioSubqueries.OrderBy(x => x.SequenceOrder)) { var clauses = new List <IExpression> { Expr.IsEQU(EnvironmentProp.NameSpace, nameSpace) }; if (subQuery.CounterpartyId != null) { clauses.Add(Expr.IsEQU(TradeProp.CounterPartyId, subQuery.CounterpartyId)); } if (subQuery.TradingBookId != null) { clauses.Add(Expr.IsEQU(TradeProp.TradingBookId, subQuery.TradingBookId)); } // load trades defined by the query if (clauses.Count <= 0) { continue; } List <ICoreItemInfo> subQueryItems = Context.Cache.LoadItemInfos <Trade>(Expr.BoolAND(clauses.ToArray())); //TODO again have to handle confirmation foreach (var tradeItemInfo in subQueryItems) { if (subQuery.ExcludeItems) { tradeItemInfos.Remove(tradeItemInfo.Name); } else { tradeItemInfos[tradeItemInfo.Name] = tradeItemInfo; } } } } // process included/excluded trades ids if (portfolio.ExcludeOverridesInclude) { // add included names if (portfolio.IncludedTradeItemNames != null) { foreach (var name in portfolio.IncludedTradeItemNames) { var tradeItemInfo = name.Contains(FpML5R10NameSpaces.Confirmation) ? Context.Cache.LoadItemInfo <FpML.V5r10.Confirmation.Trade>(name) : Context.Cache.LoadItemInfo <Trade>(name); if (tradeItemInfo != null) { tradeItemInfos[name] = tradeItemInfo; } } } } // remove excluded names if (portfolio.ExcludedTradeItemNames != null) { foreach (var name in portfolio.ExcludedTradeItemNames) { tradeItemInfos.Remove(name); } } if (!portfolio.ExcludeOverridesInclude) { // add included names if (portfolio.IncludedTradeItemNames != null) { foreach (var name in portfolio.IncludedTradeItemNames) { var tradeItemInfo = name.Contains(FpML5R10NameSpaces.Confirmation) ? Context.Cache.LoadItemInfo <FpML.V5r10.Confirmation.Trade>(name) : Context.Cache.LoadItemInfo <Trade>(name); if (tradeItemInfo != null) { tradeItemInfos[name] = tradeItemInfo; } } } } // define scenario loops // - always include un-stressed scenario (null) var irScenarios = new List <string> { null }; if (request.IRScenarioNames != null) { irScenarios.AddRange(request.IRScenarioNames); } string[] irScenarioNames = irScenarios.Distinct().ToArray(); var fxScenarios = new List <string> { null }; if (request.FXScenarioNames != null) { fxScenarios.AddRange(request.FXScenarioNames); } string[] fxScenarioNames = fxScenarios.Distinct().ToArray(); // update progress status response.ItemCount = irScenarios.Count * fxScenarios.Count * tradeItemInfos.Count; response.Status = RequestStatusEnum.InProgress; Context.Cache.SaveObject(response); // preload *all* curves into the cache // note: this is required to optimise all subsequent curve queries if (market.Contains(CurveConst.NAB_EOD) || market.Contains(CurveConst.TEST_EOD)) { Context.Cache.LoadItems <Market>(Expr.ALL);//TODO make specific to the namespace } // load and sort scenario definition rules var scenarioRules = Context.Cache.LoadObjects <ScenarioRule>(Expr.IsEQU(EnvironmentProp.NameSpace, nameSpace)); var sortedScenarioRules = new List <CachedScenarioRule>(); { sortedScenarioRules.AddRange(from scenarioRule in scenarioRules where !scenarioRule.Disabled select new CachedScenarioRule(scenarioRule.ScenarioId, scenarioRule.RuleId, scenarioRule.Priority, (scenarioRule.FilterExpr != null) ? Expr.Create(scenarioRule.FilterExpr) : Expr.ALL, scenarioRule.StressId)); } sortedScenarioRules.Sort(); // build distinct lists of curve names and currencies required by the portfolio var curvenamesList = new List <string>(); var currenciesList = new List <string>(); foreach (var item in tradeItemInfos.Values) { curvenamesList.AddRange(item.AppProps.GetArray <string>(TradeProp.RequiredPricingStructures)); currenciesList.AddRange(item.AppProps.GetArray <string>(TradeProp.RequiredCurrencies)); } curvenamesList = new List <string>(curvenamesList.Distinct().Where(x => !String.IsNullOrEmpty(x))); currenciesList = new List <string>(currenciesList.Distinct().Where(x => !String.IsNullOrEmpty(x))); var metrics = GetSwapMetrics(); // run the scenario rules ONCE for each IR and FX scenario to determine which // stressed curves to use when pricing. var resolvedCurveProps = new Dictionary <string, NamedValueSet>(); // IR loop var irScenarioCurveMap = new List <CurveStressPair> [irScenarioNames.Length]; for (int i = 0; i < irScenarioNames.Length; i++) { string irScenario = irScenarioNames[i]; irScenarioCurveMap[i] = new List <CurveStressPair>(); foreach (string curveName in curvenamesList) { string curveSignature = CurveLoader.IrCurveSignature(market, curveName, null); if (!resolvedCurveProps.TryGetValue(curveSignature, out var curveProperties)) { // not cached - resolve and cache curveProperties = PricingStructureFactory.GetInterestRateCurveProperties(Context.Logger, Context.Cache, request.NameSpace, market, curveName, null);//TODO not this namespace. Use the curves. resolvedCurveProps[curveSignature] = curveProperties; } var stressName = CachedScenarioRule.RunScenarioRules(sortedScenarioRules, irScenario, curveProperties); irScenarioCurveMap[i].Add(new CurveStressPair(curveName, stressName)); } } // FX loop var fxScenarioCurveMap = new List <CurveStressPair> [fxScenarioNames.Length]; for (var j = 0; j < fxScenarioNames.Length; j++) { string fxScenario = fxScenarioNames[j]; fxScenarioCurveMap[j] = new List <CurveStressPair>(); foreach (string currency in currenciesList) { string curveSignature = CurveLoader.FxCurveSignature(market, currency, reportingCurrency, null); if (!resolvedCurveProps.TryGetValue(curveSignature, out var curveProperties)) { // not cached - resolve and cache if (currency != reportingCurrency) { curveProperties = PricingStructureFactory.GetFxCurveProperties(Context.Logger, Context.Cache, request.NameSpace, market, currency, reportingCurrency); resolvedCurveProps[curveSignature] = curveProperties; } } string stressName = CachedScenarioRule.RunScenarioRules(sortedScenarioRules, fxScenario, curveProperties); fxScenarioCurveMap[j].Add(new CurveStressPair(currency, stressName)); } } // iterate the scenario loops var resolvedCurveCache = new Dictionary <string, ICurve>(); var reportNameCache = new Dictionary <string, string>(); for (int i = 0; i < irScenarioNames.Length; i++) { string irScenario = irScenarioNames[i]; for (int j = 0; j < fxScenarioNames.Length; j++) { string fxScenario = fxScenarioNames[j]; // check for workflow cancellation (user abort, server shutdown etc.) if (Cancelled) { throw new OperationCanceledException(CancelReason); } // initialise the pricer with the IR/FX scenario curve maps var portfolioPricer = new PortfolioPricer(irScenarioCurveMap[i], fxScenarioCurveMap[j]); // now price the portfolio portfolioPricer.PriceAndPublish( Context.Logger, Context.Cache, resolvedCurveCache, reportNameCache, response, tradeItemInfos.Keys, request, irScenario, fxScenario, reportingCurrency, baseParty, metrics, false); var dtNow = DateTime.Now; if ((dtNow - lastStatusPublishedAt) <= TimeSpan.FromSeconds(5)) { continue; } lastStatusPublishedAt = dtNow; response.Status = RequestStatusEnum.InProgress; Context.Cache.SaveObject(response); } // foreach ir scenario } // foreach fx scenario // success response.Status = RequestStatusEnum.Completed; }
/// <summary> /// Create intial Curve /// store it in _initialCurve /// </summary> private void SetInitialCurve(ILogger logger, ICoreCache cache, string nameSpace, IBusinessCalendar fixingCalendar, IBusinessCalendar rollCalendar, NamedValueSet properties, string[] instruments, decimal[] rates) { _initialCurve = PricingStructureFactory.CreateCurve(logger, cache, nameSpace, fixingCalendar, rollCalendar, properties, instruments, rates, null) as RateCurve; }