public static BasicAssetValuation Add(BasicAssetValuation basicAssetValuation1, BasicAssetValuation basicAssetValuation2)
        {
            BasicAssetValuation result = BinarySerializerHelper.Clone(basicAssetValuation1);

            var proccessedMeasureTypes = new List <string>();

            foreach (BasicQuotation bq1 in result.quote)
            {
                proccessedMeasureTypes.Add(bq1.measureType.Value);

                BasicQuotation bq2 = GetQuotationByMeasureType(basicAssetValuation2, bq1.measureType.Value);

                if (null != bq2)
                {
                    bq1.value += bq2.value;
                }
            }

            var bqToAddToList = new List <BasicQuotation>();

            foreach (BasicQuotation bq2 in basicAssetValuation2.quote)
            {
                if (-1 == proccessedMeasureTypes.IndexOf(bq2.measureType.Value))//if hasn't been processed in the first pass
                {
                    bqToAddToList.Add(bq2);
                }
            }

            bqToAddToList.AddRange(result.quote);

            result.quote = bqToAddToList.ToArray();

            return(result);
        }
        /// <summary>
        /// Gets the closest non-zero volatility strike to money.
        /// </summary>
        /// <param name="expiry">The expiry.</param>
        /// <returns></returns>
        ///
        public static Strike GetClosestStrikeToMoney(ForwardExpiry expiry)
        {
            decimal fwdPrice   = expiry.FwdPrice;
            var     expiryCopy = BinarySerializerHelper.Clone(expiry);

            /* Bin search bitwise complement returns first element larger than search key
             * Returns Array Length + 1 if search key greater than all elements */
            expiryCopy.RawStrikePrices.Sort();
            double[] strikes = expiryCopy.RawStrikePrices.ToArray();
            int      index   = Array.BinarySearch(strikes, Convert.ToDouble(fwdPrice));

            if (index < 0)
            {
                index = ~index;
            }
            if (expiryCopy.Strikes.Length == 0)
            {
                return(null);
            }
            if (index < expiryCopy.Strikes.Length)
            {
                double dist1 = Math.Abs(strikes[index] - Convert.ToDouble(fwdPrice));
                double dist2 = 0.0;
                if (index >= 1)
                {
                    dist2 = Math.Abs(strikes[index - 1] - Convert.ToDouble(fwdPrice));
                }
                if (dist1 <= dist2 || index == 0)
                {
                    return(expiryCopy.Strikes[index]);
                }
                return(expiryCopy.Strikes[index - 1]);
            }
            return(expiryCopy.Strikes[expiryCopy.RawStrikePrices.Count - 1]);
        }
Exemple #3
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="dataType"></param>
 /// <param name="binaryClone"></param>
 /// <returns></returns>
 public object GetData(Type dataType, bool binaryClone)
 {
     // deserialise if required
     Deserialise(dataType);
     if (binaryClone)
     {
         return(BinarySerializerHelper.Clone(_data));
     }
     return(_data);
 }
Exemple #4
0
        public static BasicQuotation Add(BasicQuotation basicQuotation1, BasicQuotation basicQuotation2)
        {
            if (basicQuotation1.measureType.Value != basicQuotation2.measureType.Value)
            {
                string errorMessage =
                    $"Error: can't add BasicQuotations with different 'measureTypes'. MeasureType for basicQuotation1 is {basicQuotation1.measureType.Value}, MeasureType for basicQuotation2 is {basicQuotation2.measureType.Value}";
                throw new System.Exception(errorMessage);
            }
            BasicQuotation result = BinarySerializerHelper.Clone(basicQuotation1);

            result.value += basicQuotation2.value;
            return(result);
        }
        public void AddQuotedAssetSet(QuotedAssetSet quotedAssetSet)
        {
            quotedAssetSet = BinarySerializerHelper.Clone(quotedAssetSet);

            //_lastQuotedAssetSet = quotedAssetSet;
            if (null == _lastQuotedAssetSet)
            {
                _lastQuotedAssetSet = quotedAssetSet;
            }
            else
            {
                MergeQuotedAssetSet(quotedAssetSet);
            }
        }
        ///// <summary>
        ///// Creates the surface from expiry node list.
        ///// </summary>
        ///// <param name="assetId">The asset id.</param>
        ///// <param name="expiryNodes">The expiry nodes.</param>
        ///// <returns></returns>
        //public static IVolatilitySurface CreateSurfaceFromNodalExpiryNodeList(string assetId, XmlNodeList expiryNodes)
        //{
        //    IVolatilitySurface surface = new VolatilitySurface(assetId);
        //    List<ForwardExpiry> expiries = ForwardExpiryHelper.CreateExpiriesFromExpiryNodeList(expiryNodes);

        //    if (expiries != null)
        //    {
        //        foreach (ForwardExpiry expiry in expiries)
        //        {
        //            surface.AddExpiry(expiry);
        //        }
        //    }
        //    else
        //    {
        //        throw new IncompleteInputDataException("Surface has no expiries");
        //    }
        //    return surface;

        //}



        /// <summary>
        /// Gets the closest non-zero volatility strike to money.
        /// </summary>
        /// <param name="expiry">The expiry.</param>
        /// <returns></returns>
        ///
        public static double GetClosestNonZeroVolStrikeToMoney(ForwardExpiry expiry)
        {
            decimal fwdPrice   = expiry.FwdPrice;
            var     expiryCopy = BinarySerializerHelper.Clone(expiry);

            //Remove strikes with zero vol in the search object
            //Want to return the location of the nearest *non-zero* strike
            foreach (Strike strike in expiryCopy.Strikes)
            {
                if (strike.Volatility.Value == 0)
                {
                    expiryCopy.RemoveStrike(strike.StrikePrice);
                }
            }

            /* Bin search bitwise complement returns first element larger than search key
             * Returns Array Length + 1 if search key greater than all elements */

            expiryCopy.RawStrikePrices.Sort();
            double[] strikes = expiryCopy.RawStrikePrices.ToArray();
            int      index   = Array.BinarySearch(strikes, Convert.ToDouble(fwdPrice));

            if (index < 0)
            {
                index = ~index;
            }
            if (expiryCopy.RawStrikePrices.Count == 0)
            {
                return(0.0);
            }
            if (index < expiryCopy.RawStrikePrices.Count)
            {
                double dist1 = Math.Abs(strikes[index] - Convert.ToDouble(fwdPrice));
                double dist2 = 0.0;
                if (index >= 1)
                {
                    dist2 = Math.Abs(strikes[index - 1] - Convert.ToDouble(fwdPrice));
                }
                if (dist1 <= dist2 || index == 0)
                {
                    return(expiryCopy.RawStrikePrices[index]);
                }
                return(expiryCopy.RawStrikePrices[index - 1]);
            }
            return(expiryCopy.RawStrikePrices[expiryCopy.RawStrikePrices.Count - 1]);
        }
Exemple #7
0
 public static void ResolveBusinessCenters(object objectGraph)
 {
     foreach (BusinessDayAdjustments businessDayAdjustment in GetBusinessDayAdjustments(objectGraph))
     {
         // "NONE" adjustments have neither businessCenters nor businessCentersReference.
         //
         if ((null != businessDayAdjustment) &&
             (null == businessDayAdjustment.businessCenters) &&
             (null != businessDayAdjustment.businessCentersReference) &&
             (!String.IsNullOrEmpty(businessDayAdjustment.businessCentersReference.href)))
         {
             var businessCenters = ObjectLookupHelper.GetById <BusinessCenters>(objectGraph, businessDayAdjustment.businessCentersReference.href);
             var businessCentersCloneWithNoId = BinarySerializerHelper.Clone(businessCenters);
             businessCentersCloneWithNoId.id       = null;
             businessDayAdjustment.businessCenters = businessCentersCloneWithNoId;
         }
     }
 }
Exemple #8
0
        public static BasicQuotation Sum(List <BasicQuotation> basicQuotationList)
        {
            if (0 == basicQuotationList.Count)
            {
                throw new ArgumentException("basicQuotationList is empty");
            }
            if (1 == basicQuotationList.Count)
            {
                return(BinarySerializerHelper.Clone(basicQuotationList[0]));
            }
            // clone collection internally - just to keep invariant of the method.
            //
            List <BasicQuotation> clonedCollection = BinarySerializerHelper.Clone(basicQuotationList);
            BasicQuotation        firstElement     = clonedCollection[0];

            clonedCollection.RemoveAt(0);
            BasicQuotation sumOfTheTail = Sum(clonedCollection);

            return(Add(firstElement, sumOfTheTail));
        }
        /// <summary>
        /// Gets the  i-th closest non-zero volatility strike to money.
        /// </summary>
        /// <param name="expiry">The expiry.</param>
        /// <param name="i"></param>
        /// <returns></returns>
        public static double GetClosestNonZeroVolStrikeToMoney(ForwardExpiry expiry, int i)
        {
            decimal fwdPrice   = expiry.FwdPrice;
            var     expiryCopy = BinarySerializerHelper.Clone(expiry);

            //Remove strikes with zero vol in the search object
            //Want to return the location of the nearest *non-zero* strike
            foreach (Strike strike in expiryCopy.Strikes)
            {
                if (strike.Volatility.Value == 0)
                {
                    expiryCopy.RemoveStrike(strike.StrikePrice);
                }
            }
            var newStrikes = new double[expiryCopy.RawStrikePrices.Count];

            expiryCopy.RawStrikePrices.Sort();
            double[] strikes = expiryCopy.RawStrikePrices.ToArray();

            if (strikes.Length < i)
            {
                return(0);
            }
            var keys = new int[strikes.Length];

            for (int idx = 0; idx < strikes.Length; idx++)
            {
                newStrikes[idx] = strikes[idx] - (double)fwdPrice;
                keys[idx]       = idx;
            }
            //Get min distance to forward
            Array.Sort(newStrikes, keys, new DistanceComparer());
            if (i > 0)
            {
                return(expiryCopy.Strikes[keys[i - 1]].StrikePrice);
            }
            return(0);

            /* Bin search bitwise complement returns first element larger than search key
             * Returns Array Length + 1 if search key greater than all elements */
        }
Exemple #10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PriceableFxOptionPremium"/> class.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <param name="receiverPartyReference">The receiver.</param>
        /// <param name="payerIsBase">The flag determining if the payer is the base party.</param>
        /// <param name="amount">The amount.</param>
        /// <param name="settlementDate">The adjusted payment date.</param>
        /// <param name="payerPartyReference">The payer.</param>
        /// <param name="premiumQuote">The premium quote </param>
        /// <param name="settlementInformation">The settlement information. </param>
        /// <param name="paymentCalendar">Type paymentCalendar.</param>
        public PriceableFxOptionPremium
        (
            string id
            , string payerPartyReference
            , string receiverPartyReference
            , bool payerIsBase
            , Money amount
            , DateTime settlementDate
            , PremiumQuote premiumQuote
            , SettlementInformation settlementInformation
            , IBusinessCalendar paymentCalendar) :
            base(id, "DiscountedCashflow", payerIsBase, amount,
                 AdjustableOrAdjustedDateHelper.CreateAdjustedDate(settlementDate),
                 PaymentTypeHelper.Create("Certain"), CashflowTypeHelper.Create(CashflowTypeEnum.Premium.ToString()), false, paymentCalendar)
        {
            PayerPartyReference    = PartyReferenceFactory.Create(payerPartyReference);
            ReceiverPartyReference = PartyReferenceFactory.Create(receiverPartyReference);
            OrderedPartyNames.Add(PayerPartyReference.href);
            OrderedPartyNames.Add(ReceiverPartyReference.href);
            if (premiumQuote != null)
            {
                PremiumQuote = new PremiumQuote
                {
                    quoteBasis          = premiumQuote.quoteBasis,
                    quoteBasisSpecified = true,
                    value          = premiumQuote.value,
                    valueSpecified = true
                };
            }
            if (settlementInformation == null)
            {
                return;
            }
            SettlementInformation = new SettlementInformation();
            var item = BinarySerializerHelper.Clone(settlementInformation.Item);

            SettlementInformation.Item = item;
        }
        public void ProcessRequest(RequestBase baseRequest, HandlerResponse response)
        {
            if (baseRequest == null)
            {
                throw new ArgumentNullException(nameof(baseRequest));
            }
            var request = baseRequest as StressedCurveGenRequest;

            if (request == null)
            {
                throw new InvalidCastException(
                          $"{typeof(RequestBase).Name} is not a {typeof(StressedCurveGenRequest).Name}");
            }
            // check for workflow cancellation
            if (Cancelled)
            {
                throw new OperationCanceledException(CancelReason);
            }
            DateTime lastStatusPublishedAt = DateTime.Now;

            CurveSelection[] curveSelectors = request.CurveSelector ?? new List <CurveSelection>().ToArray();

            #region Load stress rules

            //find the uniques namespaces
            var uniquesNameSpaces = new List <string>();
            foreach (CurveSelection curveSelector in curveSelectors)
            {
                if (!uniquesNameSpaces.Contains(curveSelector.NameSpace))
                {
                    uniquesNameSpaces.Add(curveSelector.NameSpace);
                }
            }
            var cachedStressRules = new Dictionary <string, List <CachedStressRule> >();
            {
                IExpression       queryExpr         = Expr.IsEQU(EnvironmentProp.NameSpace, uniquesNameSpaces[0]);//TODO only does the first namespace....
                List <StressRule> storedStressRules = Context.Cache.LoadObjects <StressRule>(queryExpr);
                foreach (StressRule storedStressRule in storedStressRules)
                {
                    if ((storedStressRule.Disabled) || (storedStressRule.StressId == null))
                    {
                        continue;
                    }
                    string key = storedStressRule.StressId.ToLower();
                    List <CachedStressRule> rules;
                    if (!cachedStressRules.TryGetValue(key, out rules))
                    {
                        rules = new List <CachedStressRule>();
                        cachedStressRules[key] = rules;
                    }
                    rules.Add(new CachedStressRule(storedStressRule));
                    rules.Sort();
                }
            }
            #endregion

            response.ItemCount = curveSelectors.Length * cachedStressRules.Count;
            // iterate selected base curves
            foreach (CurveSelection curveSelector in curveSelectors)
            {
                // check for workflow cancellation
                if (Cancelled)
                {
                    throw new OperationCanceledException(CancelReason);
                }
                // publish 'intermediate' in-progress result (throttled)
                if ((DateTime.Now - lastStatusPublishedAt) > TimeSpan.FromSeconds(5))
                {
                    lastStatusPublishedAt = DateTime.Now;
                    response.Status       = RequestStatusEnum.InProgress;
                    Context.Cache.SaveObject(response);
                }
                string nameSpace       = curveSelector.NameSpace;
                string inputMarketName = curveSelector.MarketName;
                var    marketDate      = curveSelector.MarketDate;
                if (marketDate != null && marketDate != DateTime.MinValue)
                {
                    inputMarketName += "." + ((DateTime)marketDate).ToString(CurveProp.MarketDateFormat);
                }
                string inputCurveName = curveSelector.CurveName;
                string inputCurveType = curveSelector.CurveType;
                Context.Logger.LogDebug("Building stressed curve(s): {0}.{1}.{2}", inputMarketName, inputCurveType, inputCurveName);

                #region Load base curve

                var curveGenProps = new NamedValueSet();
                curveGenProps.Set(CurveProp.BaseDate, request.BaseDate);
                IPricingStructureIdentifier baseCurveId =
                    PricingStructureIdentifier.CreateMarketCurveIdentifier(curveGenProps, inputMarketName, null, inputCurveType, inputCurveName, null);
                var       baseCurveUniqueId = baseCurveId.Properties.GetValue <string>(CurveProp.UniqueIdentifier, true);
                ICoreItem baseCurveItem     = LoadAndCheckMarketItem(Context.Cache, nameSpace, baseCurveUniqueId);
                var       stressNameProp    = baseCurveItem.AppProps.GetValue <string>(CurveProp.StressName, null);
                if (stressNameProp != null)
                {
                    throw new ApplicationException("The Market with name '" + baseCurveUniqueId + "' is NOT a base curve! (Stress name is not null)");
                }
                var baseCurveFpml = (Market)baseCurveItem.Data;
                var baseCurveType = PropertyHelper.ExtractPricingStructureType(baseCurveItem.AppProps);

                #endregion

                #region Load the reference curves - if required

                string        fxCurveName = null, refCurveName = null, quoteCurveName = null;
                NamedValueSet fxProperties = null, refProperties = null, quoteProperties = null;
                Market        fxMarket = null, refMarket = null, quoteMarket = null;
                if (baseCurveType == PricingStructureTypeEnum.RateBasisCurve ||
                    baseCurveType == PricingStructureTypeEnum.RateXccyCurve)
                {
                    // rate basis curves require a reference curve
                    refCurveName = baseCurveItem.AppProps.GetValue <string>(CurveProp.ReferenceCurveUniqueId, true);
                    // load the reference curve
                    var refCurveItem = LoadAndCheckMarketItem(Context.Cache, nameSpace, refCurveName);
                    refMarket     = (Market)refCurveItem.Data;
                    refProperties = refCurveItem.AppProps;
                }
                if (baseCurveType == PricingStructureTypeEnum.RateXccyCurve)
                {
                    // rate basis curves require an fx curve
                    fxCurveName = baseCurveItem.AppProps.GetValue <string>(CurveProp.ReferenceFxCurveUniqueId, true);
                    // load the reference curve
                    var fxCurveItem = LoadAndCheckMarketItem(Context.Cache, nameSpace, fxCurveName);
                    fxMarket     = (Market)fxCurveItem.Data;
                    fxProperties = fxCurveItem.AppProps;
                    // rate basis curves require a reference curve
                    quoteCurveName = baseCurveItem.AppProps.GetValue <string>(CurveProp.ReferenceCurrency2CurveId, true);
                    // load the reference curve
                    var quoteCurveItem = LoadAndCheckMarketItem(Context.Cache, nameSpace, quoteCurveName);
                    quoteMarket     = (Market)quoteCurveItem.Data;
                    quoteProperties = quoteCurveItem.AppProps;
                }
                #endregion

                // process stress rules
                foreach (var kvp in cachedStressRules)
                {
                    CachedStressRule stressRule = kvp.Value.FirstOrDefault(item => (item.FilterExpr == null) || (Expr.CastTo(item.FilterExpr.Evaluate(baseCurveItem.AppProps), false)));
                    // find stress rule that applies
                    if (stressRule == null)
                    {
                        // this stress does not apply to this base curve
                        Context.Logger.LogWarning("Stress '{0}' does not apply to base curve '{1}'!", kvp.Key, baseCurveUniqueId);
                        response.IncrementItemsPassed();
                        continue;
                    }
                    // apply the stress rule
                    //_Context.Logger.LogDebug("Applying stress '{0}' (rule {1}) to base curve '{2}'", stressRule.StressId, stressRule.RuleId, baseCurveUniqueId);
                    var stressDefProps = new NamedValueSet(baseCurveItem.AppProps, curveGenProps);
                    stressDefProps.Set("Identifier", null);//THis is done for backward compatability eith the old ratecurves.
                    stressDefProps.Set(CurveProp.BaseCurveType, baseCurveType);
                    IPricingStructureIdentifier stressCurveId = PricingStructureIdentifier.CreateMarketCurveIdentifier(
                        stressDefProps, inputMarketName, null, baseCurveType.ToString(), inputCurveName, stressRule.StressId);
                    NamedValueSet stressCurveProps = stressCurveId.Properties;
                    var           stressCurveName  = stressCurveProps.GetValue <string>(CurveProp.UniqueIdentifier, true);
                    // from here on a curve will be published (with error details included)
                    var stressCurve = new Market(); // empty
                    try
                    {
                        // clone the base curve and adjust the market quotes
                        var ps = BinarySerializerHelper.Clone(baseCurveFpml.Items[0]);
                        PricingStructureValuation psv = ApplyStress(stressRule, baseCurveFpml.Items1[0]);
                        // hack - supply base date
                        psv.baseDate = new IdentifiedDate {
                            Value = request.BaseDate
                        };
                        Triplet <PricingStructure, PricingStructureValuation, NamedValueSet> refCurveFpmlTriplet = null;
                        if (baseCurveType == PricingStructureTypeEnum.RateBasisCurve ||
                            baseCurveType == PricingStructureTypeEnum.RateXccyCurve)
                        {
                            var psRef = BinarySerializerHelper.Clone(refMarket.Items[0]);
                            //var psvRef = BinarySerializerHelper.Clone<PricingStructureValuation>(refcurveFpml.Items1[0]);
                            var psvRef = ApplyStress(stressRule, refMarket.Items1[0]);
                            refCurveFpmlTriplet =
                                new Triplet <PricingStructure, PricingStructureValuation, NamedValueSet>(
                                    psRef, psvRef, refProperties);
                        }
                        IPricingStructure ips;
                        switch (baseCurveType)
                        {
                        case PricingStructureTypeEnum.RateBasisCurve:
                            stressCurveProps.Set(CurveProp.ReferenceCurveUniqueId, refCurveName);
                            var basisCurveFpmlTriplet =
                                new Triplet <PricingStructure, PricingStructureValuation, NamedValueSet>(
                                    ps, psv, stressCurveProps);
                            //create and set the pricingstructure
                            ips = CurveLoader.LoadInterestRateCurve(Context.Logger, Context.Cache, nameSpace, refCurveFpmlTriplet, basisCurveFpmlTriplet);
                            //Creator.Create(refCurveFpmlTriplet, basisCurveFpmlTriplet);
                            break;

                        case PricingStructureTypeEnum.RateXccyCurve:
                            stressCurveProps.Set(CurveProp.ReferenceCurveUniqueId, refCurveName);
                            stressCurveProps.Set(CurveProp.ReferenceFxCurveUniqueId, fxCurveName);
                            stressCurveProps.Set(CurveProp.ReferenceCurrency2CurveId, quoteCurveName);
                            var xccyCurveFpmlTriplet =
                                new Triplet <PricingStructure, PricingStructureValuation, NamedValueSet>(ps, psv,
                                                                                                         stressCurveProps);
                            //Format the ref curve data and call the pricing structure helper.
                            var psvFx = ApplyStress(stressRule, fxMarket.Items1[0]);
                            var fxCurveFpmlTriplet
                                = new Triplet <PricingStructure, PricingStructureValuation, NamedValueSet>(
                                      fxMarket.Items[0],
                                      psvFx, fxProperties);

                            var psvRef = ApplyStress(stressRule, quoteMarket.Items1[0]);
                            var quoteCurveFpmlTriplet
                                = new Triplet <PricingStructure, PricingStructureValuation, NamedValueSet>(
                                      quoteMarket.Items[0],
                                      psvRef, quoteProperties);
                            //create and set the pricingstructure
                            ips = CurveLoader.LoadInterestRateCurve(Context.Logger, Context.Cache, nameSpace, refCurveFpmlTriplet, fxCurveFpmlTriplet, quoteCurveFpmlTriplet,
                                                                    xccyCurveFpmlTriplet);
                            //Creator.Create(refCurveFpmlTriplet, fxCurveFpmlTriplet, quoteCurveFpmlTriplet, xccyCurveFpmlTriplet);
                            break;

                        default:
                            ips = CurveLoader.LoadCurve(Context.Logger, Context.Cache,
                                                        nameSpace, new Pair <PricingStructure, PricingStructureValuation>(ps, psv),
                                                        stressCurveProps);
                            //Creator.Create( new Pair<PricingStructure, PricingStructureValuation>(ps, psv), stressCurveProps);
                            break;
                        }
                        var identifier = ips.GetPricingStructureId().UniqueIdentifier;
                        // retrieve curve
                        stressCurve = PricingStructureHelper.CreateMarketFromFpML(
                            identifier,
                            ips.GetFpMLData());
                        // curve done
                        response.IncrementItemsPassed();
                    }
                    catch (Exception innerExcp)
                    {
                        response.IncrementItemsFailed();
                        Context.Logger.Log(innerExcp);
                        stressCurveProps.Set(WFPropName.ExcpName, WFHelper.GetExcpName(innerExcp));
                        stressCurveProps.Set(WFPropName.ExcpText, WFHelper.GetExcpText(innerExcp));
                    }
                    // save stressed curve with same lifetime as base curve
                    stressCurveProps.Set(EnvironmentProp.NameSpace, nameSpace);
                    Context.Cache.SaveObject(stressCurve, nameSpace + "." + stressCurveName, stressCurveProps, true, baseCurveItem.Expires);
                } // foreach stress rule
            }     // foreach base curve

            // success
            response.Status = RequestStatusEnum.Completed;
        }
        private static PricingStructureValuation ApplyStress(CachedStressRule stressRule, PricingStructureValuation psvInput)
        {
            string marketQuote = AssetMeasureScheme.GetEnumString(AssetMeasureEnum.MarketQuote);
            string decimalRate = PriceQuoteUnitsScheme.GetEnumString(PriceQuoteUnitsEnum.DecimalRate);
            var    psv         = BinarySerializerHelper.Clone(psvInput);
            // extract the market quotes from the cloned base curve
            QuotedAssetSet curveDefinition;

            if (psv is YieldCurveValuation yieldCurveValuation)
            {
                curveDefinition = yieldCurveValuation.inputs;
            }
            else
            {
                if (psv is FxCurveValuation curveValuation)
                {
                    curveDefinition = new QuotedAssetSet
                    {
                        instrumentSet = curveValuation.spotRate.instrumentSet,
                        assetQuote    = curveValuation.spotRate.assetQuote
                    };
                }
                else
                {
                    throw new NotSupportedException("Unsupported PricingStructureValuation type: " +
                                                    psv.GetType().Name);
                }
            }
            // stress the market quotes
            foreach (BasicAssetValuation asset in curveDefinition.assetQuote)
            {
                var stressDefQuotes = new List <BasicQuotation>();
                foreach (BasicQuotation quote in asset.quote)
                {
                    if (quote.measureType.Value.Equals(marketQuote) &&
                        quote.quoteUnits.Value.Equals(decimalRate))
                    {
                        var exprProps = new NamedValueSet(new NamedValue("MarketQuote", quote.value));
                        quote.valueSpecified = true;
                        quote.value          = Convert.ToDecimal(stressRule.UpdateExpr.Evaluate(exprProps));
                    }
                    quote.informationSource      = null;
                    quote.timeSpecified          = false;
                    quote.valuationDateSpecified = false;
                    stressDefQuotes.Add(quote);
                }
                asset.quote = stressDefQuotes.ToArray();
            }
            // replace the market quotes in the cloned base curve with the stressed values
            if (psv is YieldCurveValuation valuation)
            {
                valuation.inputs = curveDefinition;
                valuation.discountFactorCurve = null;
                valuation.zeroCurve           = null;
            }
            else
            {
                ((FxCurveValuation)psv).spotRate
                    = new FxRateSet
                    {
                    instrumentSet = curveDefinition.instrumentSet,
                    assetQuote    = curveDefinition.assetQuote
                    };
            }
            return(psv);
        }