Пример #1
0
        public override IPricingResult Calculate(SwapLeg premiumLeg, IMarketCondition market, PricingRequest request)
        {
            var valuationDate = market.ValuationDate;
            var result        = new PricingResult(valuationDate, request);

            if (result.IsRequested(PricingRequest.Pv))
            {
                result.Pv = CalcRPv(premiumLeg, market);
            }

            var accDates = premiumLeg.Accruals.ToArray();

            if (result.IsRequested(PricingRequest.Ai))
            {
                if (!accDates.Any() || valuationDate >= accDates.Last() || valuationDate <= premiumLeg.StartDate)
                {
                    result.Ai = 0.0;
                }
                else
                {
                    var idx = Array.FindIndex(accDates, x => x > valuationDate) - 1;
                    var dcf = premiumLeg.DayCount.CalcDayCountFraction(accDates[idx], valuationDate);
                    CfCalculationDetail[] temp;
                    var coupon = premiumLeg.Coupon.GetCoupon(accDates[idx], accDates[idx + 1], market.FixingCurve.Value, market.HistoricalIndexRates, out temp);
                    result.Ai = premiumLeg.Notional * coupon * dcf;
                }
            }

            return(result);
        }
Пример #2
0
 public static bool isHighOrderPricing(PricingResult result)
 {
     if (result.IsRequested(PricingRequest.DDeltaDt) ||
         result.IsRequested(PricingRequest.DVegaDt) ||
         result.IsRequested(PricingRequest.DDeltaDvol) ||
         result.IsRequested(PricingRequest.DVegaDvol))
     {
         return(true);
     }
     else
     {
         return(false);
     }
 }
Пример #3
0
 public static bool isBasicPricing(PricingResult result)
 {
     if (result.IsRequested(PricingRequest.Delta) ||
         result.IsRequested(PricingRequest.Gamma) ||
         result.IsRequested(PricingRequest.Vega) ||
         result.IsRequested(PricingRequest.Theta) ||
         result.IsRequested(PricingRequest.Rho))
     {
         return(true);
     }
     else
     {
         return(false);
     }
 }
Пример #4
0
        public override IPricingResult Calculate(CreditDefaultSwap creditDefaultSwap, IMarketCondition market, PricingRequest request)
        {
            var valuationDate = market.ValuationDate;

            var result = new PricingResult(valuationDate, request);

            if (result.IsRequested(PricingRequest.Pv))
            {
                result.Pv = _premiumLegEngine.Calculate(creditDefaultSwap.PremiumLeg, market, PricingRequest.Pv).Pv
                            + _protectionLegEngine.Calculate(creditDefaultSwap.ProtectionLeg, market, PricingRequest.Pv).Pv;
            }

            if (result.IsRequested(PricingRequest.Ai))
            {
                result.Ai = _premiumLegEngine.Calculate(creditDefaultSwap.PremiumLeg, market, PricingRequest.Ai).Ai;
            }

            return(result);
        }
Пример #5
0
        public override IPricingResult Calculate(CallableBond callableBond, IMarketCondition market, PricingRequest request)
        {
            var result = new PricingResult(market.ValuationDate, request);

            if (result.IsRequested(PricingRequest.Pv))
            {
                result.Pv = CalcPv(callableBond, market);
            }

            return(result);
        }
Пример #6
0
        public override IPricingResult Calculate(Forward <TUnderlying> trade, IMarketCondition market, PricingRequest request)
        {
            var result = new PricingResult(market.ValuationDate, request);

            if (result.IsRequested(PricingRequest.Pv))
            {
                result.Pv = CalcPv(trade, market);
            }

            if (result.IsRequested(PricingRequest.Dv01))
            {
                result.Dv01 = GetRisks(trade, market, PricingRequest.Dv01).Dv01;
            }

            if (result.IsRequested(PricingRequest.Dv01Underlying))
            {
                result.Dv01 = GetRisks(trade, market, PricingRequest.Dv01Underlying).Dv01Underlying;
            }

            return(result);
        }
Пример #7
0
        public override IPricingResult Calculate(Loan trade, IMarketCondition market, PricingRequest request)
        {
            var result = new PricingResult(market.ValuationDate, request);

            if (result.IsRequested(PricingRequest.Cashflow))
            {
                result.Cashflows    = trade.GetCashflows(market);
                result.CashflowDict = result.Cashflows.ToDictionary(x => x.ToCfKey(), x => x.PaymentAmount);
            }

            return(result);
        }
Пример #8
0
        public override IPricingResult Calculate(EquityLinkedNote <TOption> trade, IMarketCondition market, PricingRequest request)
        {
            var result = new PricingResult(market.ValuationDate, request);

            var optionResult = OptionEngine.Calculate(trade.Option, market, request);

            if (result.IsRequested(PricingRequest.Pv))
            {
                result.Pv = optionResult.Pv + trade.Notional * market.DiscountCurve.Value.GetDf(market.ValuationDate, trade.UnderlyingMaturityDate);
            }
            if (result.IsRequested(PricingRequest.Delta))
            {
                result.Delta = optionResult.Delta;
            }
            if (result.IsRequested(PricingRequest.Gamma))
            {
                result.Gamma = optionResult.Gamma;
            }
            if (result.IsRequested(PricingRequest.Rho))
            {
                result.Rho = optionResult.Rho;
            }
            if (result.IsRequested(PricingRequest.Vega))
            {
                result.Vega = optionResult.Vega;
            }
            if (result.IsRequested(PricingRequest.Theta))
            {
                result.Theta = optionResult.Theta;
            }
            return(result);
        }
Пример #9
0
        public override IPricingResult Calculate(AbsWithRepurchase trade, IMarketCondition market, PricingRequest request)
        {
            var result = new PricingResult(market.ValuationDate, request);

            if (result.IsRequested(PricingRequest.Cashflow))
            {
                var underlyingLoanCfs = trade.GetCashflows(market, false).ToArray();

                var surplus            = 0.0;
                var repurchasedLoanCfs = new List <Cashflow[]> {
                    underlyingLoanCfs
                };
                var underlyingLoanPayDates = repurchasedLoanCfs.SelectMany(x => x.Select(cf => cf.PaymentDate)).Distinct().ToArray();

                var payOutCashflows = trade.Tranches.SelectMany(x => x.GetCashflows(market, false)).ToArray();

                //assumption: repurchased loans have same features as the original loan excepth the startDate and mautirytDate
                for (var i = 0; i < underlyingLoanPayDates.Length - 1; ++i)
                {
                    //repurchase prior to the final cash flow
                    var tCfs = repurchasedLoanCfs.SelectMany(x => x).Where(x => x.PaymentDate == underlyingLoanPayDates[i] && (x.CashflowType == CashflowType.Principal || x.CashflowType == CashflowType.Coupon || x.CashflowType == CashflowType.Tax)).ToArray();
                    surplus += tCfs.Sum(x => x.PaymentAmount);
                    var payOutAmount = payOutCashflows.Where(x => x.PaymentDate >= underlyingLoanPayDates[i] && x.PaymentDate < underlyingLoanPayDates[i + 1]).Sum(x => x.PaymentAmount);

                    surplus -= payOutAmount;
                    var endDate = trade.PayOutDates.Where(x => x > underlyingLoanPayDates[i]);
                    if (endDate.Any())
                    {
                        repurchasedLoanCfs.Add(RepurchasedLoanCashflow(underlyingLoanPayDates[i + 1], surplus * trade.RepurchaseRatio, trade.Loan, market, underlyingLoanPayDates[i], endDate.First()));
                    }

                    surplus *= (1.0 - trade.RepurchaseRatio);
                }

                var payOutCf =
                    payOutCashflows.Select(
                        x =>
                        new Cashflow(x.AccrualEndDate, x.AccrualEndDate, x.PaymentDate, -x.PaymentAmount, x.PaymentCurrency,
                                     x.CashflowType, x.IsFixed, market.GetDf(x.PaymentDate), x.CalculationDetails, x.RefStartDate, x.RefEndDate, x.StartPrincipal, x.CouponRate));
                result.Cashflows = repurchasedLoanCfs.SelectMany(x => x).Union(payOutCf).ToArray();
            }

            return(result);
        }
Пример #10
0
        public override IPricingResult Calculate(InterestRateSwap trade, IMarketCondition market, PricingRequest request)
        {
            var cfEngine   = new CashflowProductEngine <SwapLeg>();
            var leg1Result = cfEngine.Calculate(trade.FixedLeg, market, PricingRequest.All);

            var mkt4Leg2 = market.UpdateCondition(new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, market.FgnDiscountCurve.Value),
                                                  new UpdateMktConditionPack <IYieldCurve>(x => x.FixingCurve, market.FgnFixingCurve.Value));
            var leg2Result = cfEngine.Calculate(trade.FloatingLeg, mkt4Leg2, PricingRequest.All);

            var result = new PricingResult(market.ValuationDate, request);

            if (result.IsRequested(PricingRequest.Pv))
            {
                result.Pv = leg1Result.Pv + leg2Result.Pv;
            }

            if (result.IsRequested(PricingRequest.Dv01))
            {
                result.Dv01 = leg1Result.Dv01 + leg2Result.Dv01;
            }

            if (result.IsRequested(PricingRequest.Pv01))
            {
                var bumpedIrs = trade.Bump(1);
                var bumpedPv  = new CashflowProductEngine <InterestRateSwap>().Calculate(bumpedIrs, market, PricingRequest.Pv).Pv;
                result.Pv01 = bumpedPv - result.Pv;
            }

            if (result.IsRequested(PricingRequest.Ai))
            {
                result.Ai = leg1Result.Ai + leg2Result.Ai;
            }

            if (result.IsRequested(PricingRequest.Cashflow))
            {
                result.Cashflows = leg1Result.Cashflows.Union(leg2Result.Cashflows).ToArray();
            }

            if (result.IsRequested(PricingRequest.KeyRateDv01))
            {
                result.KeyRateDv01 = PricingResultExtension.Aggregate(leg1Result.KeyRateDv01, leg2Result.KeyRateDv01);
            }

            return(result);
        }
Пример #11
0
        public override IPricingResult Calculate(BondFutures bondFuture, IMarketCondition market, PricingRequest request)
        {
            var beginValuation = DateTime.Now;
            var pricingRequest = CheckParameterCondition(bondFuture, market, request);

            //if (result.IsRequested(PricingRequest.Dv01))
            //{
            //	result.Dv01 = CalcDv01(bondFuture, market);
            //}

            var result = new PricingResult(market.ValuationDate, pricingRequest);

            //if (result.IsRequested(PricingRequest.Pv))
            //{
            //    result.Pv = CalcPv(bondFuture, market);
            //}

            if (result.IsRequested(PricingRequest.DirtyPrice))
            {
                result.DirtyPrice = market.MktQuote.Value.Where(x => x.Key == bondFuture.Id).Select(x => x.Value.Item2).First() * bondFuture.Notional / 100;
            }

            if (result.IsRequested(PricingRequest.ConvertFactors))
            {
                result.ConvertFactors = CalcConvertFactors(bondFuture, market);
            }

            if (result.IsRequested(PricingRequest.Irr) || result.IsRequested(PricingRequest.Pv01) ||
                result.IsRequested(PricingRequest.KeyRateDv01) ||
                result.IsRequested(PricingRequest.ZeroSpread) || result.IsRequested(PricingRequest.ZeroSpreadDelta) ||
                result.IsRequested(PricingRequest.UnderlyingPv) || result.IsRequested(PricingRequest.Basis) ||
                result.IsRequested(PricingRequest.Convexity) || result.IsRequested(PricingRequest.Ytm) ||
                result.IsRequested(PricingRequest.CheapestToDeliver) ||
                result.IsRequested(PricingRequest.ModifiedDuration) || result.IsRequested(PricingRequest.MacDuration)
                )
            {
                //TODO:  wierd update logic, why bother?
                var mktQuote     = market.MktQuote.Value.Keys.Where(quoteKey => !quoteKey.Contains(bondFuture.Id + "_")).ToDictionary(quoteKey => quoteKey, quoteKey => market.MktQuote.Value[quoteKey]);
                var updateMarket = market.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, mktQuote));
                var yieldPricer  = new BondFuturesYieldPricer(bondFuture, updateMarket);

                //calculate convert factors
                if (!result.ConvertFactors.Any())
                {
                    result.ConvertFactors = CalcConvertFactors(bondFuture, market);
                }
                var convertFactors = result.ConvertFactors;

                //calculate IRR
                result.ProductSpecific = yieldPricer.CalcEquation("FromFuturesPriceAndBondPrice");

                //calculate pv01
                var maxIrr    = result.ProductSpecific["Irr"].Values.Select(x => x.Rate).Max();
                var ctdBondId = result.ProductSpecific["Irr"].First(x => x.Value.Rate == maxIrr).Key;
                var ctdBond   = bondFuture.Deliverables.First(x => x.Id == ctdBondId);
                var cf        = convertFactors[ctdBondId];
                var scaling   = bondFuture.Notional / (100.0 * cf);

                var engine = new BondEngineCn();

                result.CheapestToDeliver = ctdBondId;

                //two risks here are CTD risk, not bond futures risk
                var resultCTD = engine.Calculate(ctdBond, market, PricingRequest.All);
                result.ZeroSpread   = resultCTD.ZeroSpread;
                result.UnderlyingPv = resultCTD.Pv * scaling;
                result.Basis        = yieldPricer.CalcFutureCtdBasis(ctdBond, cf);
                result.Ytm          = resultCTD.Ytm;
                result.MacDuration  = resultCTD.MacDuration;

                result.ModifiedDuration       = resultCTD.ModifiedDuration;
                result.Convexity              = resultCTD.Convexity;
                result.DollarConvexity        = resultCTD.DollarConvexity * scaling;        // 1% price impact
                result.DollarModifiedDuration = resultCTD.DollarModifiedDuration * scaling; // same order of magnitutude of CTD dollar modifiedDuration, good for pnl attribution

                //convert to bond futures risk
                result.Pv01 = resultCTD.Pv01 * scaling;   // underlying pv01 is
                foreach (var kvp in resultCTD.KeyRateDv01)
                {
                    foreach (var risk in kvp.Value)
                    {
                        risk.Risk *= scaling;
                    }
                }
                result.KeyRateDv01     = resultCTD.KeyRateDv01;
                result.ZeroSpreadDelta = resultCTD.ZeroSpreadDelta * scaling;
            }
            if (result.IsRequested(PricingRequest.FairQuote))
            {
                var mktQuote     = market.MktQuote.Value.Keys.Where(quoteKey => !quoteKey.Equals(bondFuture.Id)).ToDictionary(quoteKey => quoteKey, quoteKey => market.MktQuote.Value[quoteKey]);
                var updateMarket = market.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, mktQuote));
                var yieldPricer  = new BondFuturesYieldPricer(bondFuture, updateMarket);
                result.ProductSpecific = yieldPricer.CalcEquation("FromBondPriceAndIrr");
            }
            if (result.IsRequested(PricingRequest.MktQuote))
            {
                result.ProductSpecific = CalcMktFuturePrice(bondFuture, market);
            }
            if (result.IsRequested(PricingRequest.UnderlyingFairQuote))
            {
                var mktQuote     = market.MktQuote.Value.Keys.Where(quoteKey => quoteKey.Contains(bondFuture.Id)).ToDictionary(quoteKey => quoteKey, quoteKey => market.MktQuote.Value[quoteKey]);
                var updateMarket = market.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, mktQuote));
                var yieldPricer  = new BondFuturesYieldPricer(bondFuture, updateMarket);
                result.ProductSpecific = yieldPricer.CalcEquation("FromFuturesPriceAndIrr");
            }


            var endValuation = DateTime.Now;

            result.CalcTimeInMilliSecond = (endValuation - beginValuation).TotalMilliseconds;
            return(result);
        }
Пример #12
0
        public override IPricingResult Calculate(HoldingPeriod holdingPeriod, IMarketCondition market, PricingRequest request)
        {
            var beginValuation = DateTime.Now;
            var result         = new PricingResult(market.ValuationDate, request);
            var psDict         = new Dictionary <string, Dictionary <string, RateRecord> >();

            var bondId    = holdingPeriod.Id;
            var startDate = holdingPeriod.StartDate;
            var endDate   = holdingPeriod.UnderlyingMaturityDate;
            var bond      = holdingPeriod.UnderlyingBond;

            _roundCleanPrice = holdingPeriod.UnderlyingBond.RoundCleanPrice;

            var startBondId = bondId + "_Start";
            var endBondId   = bondId + "_End";

            // Create start and end bond market
            var startMarket = CreateMarketCondition(bondId, startBondId, startDate, market, holdingPeriod.StartFixingRate);
            var endMarket   = CreateMarketCondition(bondId, endBondId, endDate, market, holdingPeriod.EndFixingRate);

            // Calc Ai
            var startAiCashflow      = CalcBond(bond, startMarket);
            var endAiCashflow        = CalcBond(bond, endMarket);
            var principalBetweenTemp = startAiCashflow.Cashflows.Where(x => x.CashflowType == CashflowType.Principal && x.AccrualEndDate > startDate && x.AccrualEndDate <= endDate).Sum(cashflow => cashflow.PaymentAmount);
            var interestBetweenTemp  = startAiCashflow.Cashflows.Where(x => x.CashflowType == CashflowType.Coupon && x.AccrualEndDate > startDate && x.AccrualEndDate <= endDate).Sum(cashflow => cashflow.PaymentAmount);
            var yieldPricer          = new HoldingPeriodYieldPricer(holdingPeriod, startAiCashflow.Ai, endAiCashflow.Ai, principalBetweenTemp, interestBetweenTemp);

            var holdingPeriodResult = new Dictionary <string, double>();

            holdingPeriodResult["holdingCost"]          = double.IsNaN(holdingPeriod.HoldingCost) ? 0.0 : holdingPeriod.HoldingCost;
            holdingPeriodResult["startFrontCommission"] = double.IsNaN(holdingPeriod.StartFrontCommission) ? 0.0 : holdingPeriod.StartFrontCommission;
            holdingPeriodResult["startBackCommission"]  = double.IsNaN(holdingPeriod.StartBackCommission) ? 0.0 : holdingPeriod.StartBackCommission;
            holdingPeriodResult["endFrontCommission"]   = double.IsNaN(holdingPeriod.EndFrontCommission) ? 0.0 : holdingPeriod.EndFrontCommission;
            holdingPeriodResult["endBackCommission"]    = double.IsNaN(holdingPeriod.EndBackCommission) ? 0.0 : holdingPeriod.EndBackCommission;
            // option date
            holdingPeriodResult["hasStartOption"] = ExecutionOptionDate(startDate, holdingPeriod.UnderlyingBond, startAiCashflow.Cashflows) == null ? 1.0 : 0.0;
            holdingPeriodResult["hasEndOption"]   = ExecutionOptionDate(endDate, holdingPeriod.UnderlyingBond, endAiCashflow.Cashflows) == null ? 1.0 : 0.0;

            var    isCalcStartCleanPrice = false;
            var    isCalcEndCleanPrice   = false;
            string functionType          = "";
            double inputPar1             = 0.0;
            double inputPar2             = 0.0;

            if (result.IsRequested(PricingRequest.NetAnnualizedYield))
            {
                var startResult = CalcStartBond(startMarket, bondId, bond, holdingPeriodResult);
                var endResult   = CalcEndBond(endMarket, bondId, bond, holdingPeriodResult);

                var startCleanPrice = _roundCleanPrice ? Math.Round(startResult.CleanPrice, 4, MidpointRounding.AwayFromZero) : startResult.CleanPrice;
                var endCleanPrice   = _roundCleanPrice ? Math.Round(endResult.CleanPrice, 4, MidpointRounding.AwayFromZero) : endResult.CleanPrice;
                // Calc
                functionType = "AnnualYieldFromCleanPrice";
                inputPar1    = startCleanPrice;
                inputPar2    = endCleanPrice;
            }
            else if (result.IsRequested(PricingRequest.CleanPrice) && market.MktQuote.Value[bondId].Item1 == PriceQuoteType.None)
            {
                if (market.MktQuote.Value.ContainsKey(startBondId))
                {
                    var startResult     = CalcStartBond(startMarket, bondId, bond, holdingPeriodResult);
                    var startCleanPrice = _roundCleanPrice ? Math.Round(startResult.CleanPrice, 4, MidpointRounding.AwayFromZero) : startResult.CleanPrice;
                    var annualizedYield = market.MktQuote.Value[bondId].Item2;
                    // Calc
                    functionType        = "EndCleanPriceFromAnnual";
                    inputPar1           = startCleanPrice;
                    inputPar2           = annualizedYield;
                    isCalcEndCleanPrice = true;
                }
                else if (market.MktQuote.Value.ContainsKey(endBondId))
                {
                    var endResult       = CalcEndBond(endMarket, bondId, bond, holdingPeriodResult);
                    var annualizedYield = market.MktQuote.Value[bondId].Item2;
                    var endCleanPrice   = _roundCleanPrice ? Math.Round(endResult.CleanPrice, 4, MidpointRounding.AwayFromZero) : endResult.CleanPrice;
                    // Calc
                    functionType          = "StartCleanPriceFromAnnual";
                    inputPar1             = endCleanPrice;
                    inputPar2             = annualizedYield;
                    isCalcStartCleanPrice = true;
                }
            }
            else if (result.IsRequested(PricingRequest.CleanPrice) && market.MktQuote.Value.ContainsKey(bondId) &&
                     market.MktQuote.Value[bondId].Item1 == PriceQuoteType.NetPnl)
            {
                if (market.MktQuote.Value.ContainsKey(startBondId))
                {
                    var startResult     = CalcStartBond(startMarket, bondId, bond, holdingPeriodResult);
                    var netPnl          = market.MktQuote.Value[bondId].Item2;
                    var startCleanPrice = _roundCleanPrice ? Math.Round(startResult.CleanPrice, 4, MidpointRounding.AwayFromZero) : startResult.CleanPrice;
                    // Calc
                    functionType        = "EndCleanPriceFromPnl";
                    inputPar1           = startCleanPrice;
                    inputPar2           = netPnl;
                    isCalcEndCleanPrice = true;
                }
                else if (market.MktQuote.Value.ContainsKey(endBondId))
                {
                    var endResult     = CalcEndBond(endMarket, bondId, bond, holdingPeriodResult);
                    var netPnl        = market.MktQuote.Value[bondId].Item2;
                    var endCleanPrice = _roundCleanPrice ? Math.Round(endResult.CleanPrice, 4, MidpointRounding.AwayFromZero) : endResult.CleanPrice;
                    // Calc
                    functionType          = "StartCleanPriceFromPnl";
                    inputPar1             = endCleanPrice;
                    inputPar2             = netPnl;
                    isCalcStartCleanPrice = true;
                }
            }
            else
            {
                CalcStartBond(startMarket, bondId, bond, holdingPeriodResult);
                CalcEndBond(endMarket, bondId, bond, holdingPeriodResult);
            }

            // Calc
            yieldPricer.CalcAnnualizedYieldCleanPrice(functionType, inputPar1, inputPar2, holdingPeriodResult);
            if (isCalcStartCleanPrice)
            {
                // Calc startDate bond
                var mktQuote = new Dictionary <string, Tuple <PriceQuoteType, double> > {
                    { bondId, Tuple.Create(PriceQuoteType.Clean, holdingPeriodResult["startCleanPrice"]) }
                };
                var newMarket = startMarket.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, mktQuote));
                CalcStartBond(newMarket, bondId, bond, holdingPeriodResult);
            }
            if (isCalcEndCleanPrice)
            {
                // Calc endDate bond
                var mktQuote = new Dictionary <string, Tuple <PriceQuoteType, double> > {
                    { bondId, Tuple.Create(PriceQuoteType.Clean, holdingPeriodResult["endCleanPrice"]) }
                };
                var newMarket = endMarket.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, mktQuote));
                CalcEndBond(newMarket, bondId, bond, holdingPeriodResult);
            }

            ParseResult(psDict, bondId, holdingPeriodResult);

            result.ProductSpecific = psDict;
            var endValuation = DateTime.Now;

            result.CalcTimeInMilliSecond = (endValuation - beginValuation).TotalMilliseconds;
            return(result);
        }
Пример #13
0
        public override IPricingResult Calculate(Bond bond, IMarketCondition market, PricingRequest request)
        {
            var beginValuation    = DateTime.Now;
            var result            = new PricingResult(market.ValuationDate, request);
            var isCleanPriceRound = bond.RoundCleanPrice;

            var            bondQuote        = market.MktQuote.Value.ContainsKey(bond.Id) ? market.MktQuote.Value[bond.Id] : null;
            var            bMktQuote        = new Dictionary <string, Tuple <PriceQuoteType, double> >();
            IPricingResult resultOptionBond = new PricingResult(market.ValuationDate, request);
            IPricingResult resultSimpleBond;

            if (bondQuote != null && (bondQuote.Item1 == PriceQuoteType.YtmExecution || bondQuote.Item1 == PriceQuoteType.YtmCallExecution || bondQuote.Item1 == PriceQuoteType.YtmPutExecution))
            {
                bMktQuote[bond.Id] = Tuple.Create(PriceQuoteType.Ytm, bondQuote.Item2);
                var ytmMarket = market.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, bMktQuote));
                // Get Call or Put cleanprice
                var pricingRequest = PricingRequest.CleanPrice;
                if (result.IsRequested(PricingRequest.AiEod))
                {
                    pricingRequest = pricingRequest | PricingRequest.AiEod;
                }
                resultOptionBond = CalcOptionBond(bond, ytmMarket, pricingRequest, bondQuote.Item1);
                // Parse market
                var cleanMarket = UpdateCleanPriceMarket(bond.Id, resultOptionBond.CleanPrice, isCleanPriceRound, market);
                resultSimpleBond = _bondEngine.Calculate(bond, cleanMarket, request);
            }
            else
            {
                if (isCleanPriceRound && bondQuote != null)
                {
                    if (bondQuote.Item1 == PriceQuoteType.Clean)
                    {
                        var cleanPriceMarket = UpdateCleanPriceMarket(bond.Id, bondQuote.Item2, isCleanPriceRound,
                                                                      market);
                        resultSimpleBond = _bondEngine.Calculate(bond, cleanPriceMarket, request);
                    }
                    else
                    {
                        resultSimpleBond = _bondEngine.Calculate(bond, market, request);
                        var cleanPriceMarket = UpdateCleanPriceMarket(bond.Id, resultSimpleBond.CleanPrice, isCleanPriceRound, market);
                        resultSimpleBond = _bondEngine.Calculate(bond, cleanPriceMarket, request);
                    }
                }
                else
                {
                    resultSimpleBond = _bondEngine.Calculate(bond, market, request);
                }
                // Parse market
                bMktQuote[bond.Id] = Tuple.Create(PriceQuoteType.Clean, double.IsNaN(resultSimpleBond.CleanPrice) ? 0.0 : resultSimpleBond.CleanPrice);
                var executionYieldPricingRequest = PricingRequest.Ytm;
                if (result.IsRequested(PricingRequest.AiEod))
                {
                    executionYieldPricingRequest = PricingRequest.Ytm | PricingRequest.AiEod;
                }
                var newMarket = market.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, bMktQuote));
                if (result.IsRequested(PricingRequest.YtmExecution))
                {
                    resultOptionBond = CalcOptionBond(bond, newMarket, executionYieldPricingRequest, PriceQuoteType.YtmExecution);
                }
            }
            result             = (PricingResult)resultSimpleBond;
            result.YieldToCall = resultOptionBond.YieldToCall;
            result.YieldToPut  = resultOptionBond.YieldToPut;
            result.CallDate    = resultOptionBond.CallDate;
            result.PutDate     = resultOptionBond.PutDate;

            var endValuation = DateTime.Now;

            result.CalcTimeInMilliSecond = (endValuation - beginValuation).TotalMilliseconds;
            return(result);
        }
Пример #14
0
        public override IPricingResult GetRisks(Forward <Bond> trade, IMarketCondition market, PricingRequest pricingRequest)
        {
            var result     = new PricingResult(market.ValuationDate, pricingRequest);
            var bondEngine = new BondEngine();
            var bMarket    = market.UpdateCondition(new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, market.UnderlyingDiscountCurve.Value));

            if (result.IsRequested(PricingRequest.Dv01))
            {
                var bondZeroSpread = BondPricingFunctions.ZeroSpread(trade.Underlying, bMarket);
                IMarketCondition bondMktUp;
                IMarketCondition bondMktDown;
                if (market.FixingCurve.HasValue)
                {
                    bondMktUp = bMarket.UpdateCondition(
                        new UpdateMktConditionPack <IYieldCurve>(x => x.FixingCurve, bMarket.FixingCurve.Value.Shift(1)),
                        new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, bMarket.DiscountCurve.Value.Shift(1).GetSpreadedCurve(new ZeroSpread(bondZeroSpread)))
                        );
                    bondMktDown = bMarket.UpdateCondition(
                        new UpdateMktConditionPack <IYieldCurve>(x => x.FixingCurve, bMarket.FixingCurve.Value.Shift(-1)),
                        new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, bMarket.DiscountCurve.Value.Shift(-1).GetSpreadedCurve(new ZeroSpread(bondZeroSpread)))
                        );
                }
                else
                {
                    bondMktUp = bMarket.UpdateCondition(
                        new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, bMarket.DiscountCurve.Value.Shift(1).GetSpreadedCurve(new ZeroSpread(bondZeroSpread)))
                        );
                    bondMktDown = bMarket.UpdateCondition(
                        new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, bMarket.DiscountCurve.Value.Shift(-1).GetSpreadedCurve(new ZeroSpread(bondZeroSpread)))
                        );
                }

                var fwdMarket = market.UpdateCondition(new UpdateMktConditionPack <ISpread>(x => x.CreditSpread, new ZeroSpread(bondZeroSpread)));
                var upPv      = bondEngine.Calculate(trade.Underlying, bondMktUp, PricingRequest.Pv).Pv;
                var downPv    = bondEngine.Calculate(trade.Underlying, bondMktDown, PricingRequest.Pv).Pv;

                if (fwdMarket.FixingCurve.HasValue)
                {
                    var fwdMktUp = fwdMarket.UpdateCondition(
                        new UpdateMktConditionPack <IYieldCurve>(x => x.FixingCurve, bMarket.FixingCurve.Value.Shift(1)),
                        new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, bMarket.DiscountCurve.Value.Shift(1)),
                        new UpdateMktConditionPack <IYieldCurve>(x => x.UnderlyingDiscountCurve, bMarket.UnderlyingDiscountCurve.Value.Shift(1)),
                        new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, bMarket.MktQuote.Value.UpdateKey(trade.Underlying.Id, Tuple.Create(PriceQuoteType.Dirty, upPv)))
                        );
                    var fwdMktDown = fwdMarket.UpdateCondition(
                        new UpdateMktConditionPack <IYieldCurve>(x => x.FixingCurve, bMarket.FixingCurve.Value.Shift(-1)),
                        new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, bMarket.DiscountCurve.Value.Shift(-1)),
                        new UpdateMktConditionPack <IYieldCurve>(x => x.UnderlyingDiscountCurve, bMarket.UnderlyingDiscountCurve.Value.Shift(-1)),
                        new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, bMarket.MktQuote.Value.UpdateKey(trade.Underlying.Id, Tuple.Create(PriceQuoteType.Dirty, downPv)))
                        );
                    result.Dv01 = (CalcPv(trade, fwdMktDown) - CalcPv(trade, fwdMktUp)) / 2.0;
                }
                else
                {
                    var fwdMktUp = fwdMarket.UpdateCondition(
                        new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, bMarket.DiscountCurve.Value.Shift(1)),
                        new UpdateMktConditionPack <IYieldCurve>(x => x.UnderlyingDiscountCurve, bMarket.UnderlyingDiscountCurve.Value.Shift(1)),
                        new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, bMarket.MktQuote.Value.UpdateKey(trade.Underlying.Id, Tuple.Create(PriceQuoteType.Dirty, upPv)))
                        );
                    var fwdMktDown = fwdMarket.UpdateCondition(
                        new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, bMarket.DiscountCurve.Value.Shift(-1)),
                        new UpdateMktConditionPack <IYieldCurve>(x => x.UnderlyingDiscountCurve, bMarket.UnderlyingDiscountCurve.Value.Shift(-1)),
                        new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, bMarket.MktQuote.Value.UpdateKey(trade.Underlying.Id, Tuple.Create(PriceQuoteType.Dirty, downPv)))
                        );
                    result.Dv01 = (CalcPv(trade, fwdMktDown) - CalcPv(trade, fwdMktUp)) / 2.0;
                }
            }

            if (result.IsRequested(PricingRequest.Dv01Underlying))
            {
                var factor = trade.Notional / trade.Underlying.Notional;
                result.Dv01Underlying = bondEngine.Calculate(trade.Underlying, bMarket, PricingRequest.Dv01).Dv01 *factor;
            }

            return(result);
        }
Пример #15
0
        public override IPricingResult Calculate(BinaryOption trade, IMarketCondition market, PricingRequest request)
        {
            var result = new PricingResult(market.ValuationDate, request);

            if (trade.BinaryOptionPayoffType == BinaryOptionPayoffType.CashOrNothing)
            {
                var factor     = (double)BinaryOptionReplicationStrategy;
                var lowStrike  = trade.Strike + Offset * (factor - 1.0) / 2.0;
                var highStrike = trade.Strike + Offset * (factor + 1.0) / 2.0;

                //if call, replicate by call spreads,
                //if put, replicate by put spreads

                var lowStrikeOption  = new VanillaOption(trade.StartDate, trade.UnderlyingMaturityDate, trade.Exercise, trade.OptionType, lowStrike, trade.UnderlyingProductType, trade.Calendar, trade.DayCount, trade.PayoffCcy, trade.SettlementCcy, trade.ExerciseDates, trade.ObservationDates, trade.Notional);
                var highStrikeOption = new VanillaOption(trade.StartDate, trade.UnderlyingMaturityDate, trade.Exercise, trade.OptionType, highStrike, trade.UnderlyingProductType, trade.Calendar, trade.DayCount, trade.PayoffCcy, trade.SettlementCcy, trade.ExerciseDates, trade.ObservationDates, trade.Notional);
                var engine           = new AnalyticalVanillaEuropeanOptionEngine();
                var lowResult        = engine.Calculate(lowStrikeOption, market, request);
                var highResult       = engine.Calculate(highStrikeOption, market, request);

                var sign = trade.OptionType == OptionType.Call ? 1.0 : -1.0;
                factor = sign * trade.CashOrNothingAmount / Offset;

                //calc basic stuff
                if (result.IsRequested(PricingRequest.Pv))
                {
                    result.Pv = (lowResult.Pv - highResult.Pv) * factor;
                }
                if (AnalyticalOptionPricerUtil.isBasicPricing(result))
                {
                    result.Delta     = (lowResult.Delta - highResult.Delta) * factor;
                    result.DeltaCash = result.Delta * market.SpotPrices.Value.Values.First();
                    result.Gamma     = (lowResult.Gamma - highResult.Gamma) * factor;
                    result.GammaCash = result.Gamma * market.SpotPrices.Value.Values.First() * market.SpotPrices.Value.Values.First() / 100;
                    result.Vega      = (lowResult.Vega - highResult.Vega) * factor;
                    result.Rho       = (lowResult.Rho - highResult.Rho) * factor;
                    result.Theta     = (lowResult.Theta - highResult.Theta) * factor;
                }
                if (AnalyticalOptionPricerUtil.isHighOrderPricing(result))
                {
                    result.DDeltaDvol = (lowResult.DDeltaDvol - highResult.DDeltaDvol) * factor;
                    result.DVegaDvol  = (lowResult.DVegaDvol - highResult.DVegaDvol) * factor;
                    result.DVegaDt    = (lowResult.DVegaDt - highResult.DVegaDt) * factor;
                    result.DDeltaDt   = (lowResult.DDeltaDt - highResult.DDeltaDt) * factor;
                }
            }
            else if (trade.BinaryOptionPayoffType == BinaryOptionPayoffType.AssetOrNothing)
            {
                var binaryCfOption = new BinaryOption(trade.StartDate, trade.UnderlyingMaturityDate, trade.Exercise, trade.OptionType,
                                                      trade.Strike, trade.UnderlyingProductType, BinaryOptionPayoffType.CashOrNothing, 1.0, trade.Calendar,
                                                      trade.DayCount, trade.PayoffCcy,
                                                      trade.SettlementCcy, trade.ExerciseDates, trade.ObservationDates);
                var binaryResult  = Calculate(binaryCfOption, market, request);
                var vanillaOption = new VanillaOption(trade.StartDate, trade.UnderlyingMaturityDate, trade.Exercise, trade.OptionType,
                                                      trade.Strike, trade.UnderlyingProductType, trade.Calendar, trade.DayCount, trade.PayoffCcy,
                                                      trade.SettlementCcy, trade.ExerciseDates, trade.ObservationDates, trade.Notional);
                var engine        = new AnalyticalVanillaEuropeanOptionEngine();
                var vanillaResult = engine.Calculate(vanillaOption, market, request);
                var sign          = trade.OptionType == OptionType.Call ? 1.0 : -1.0;

                if (result.IsRequested(PricingRequest.Pv))
                {
                    result.Pv = sign * vanillaResult.Pv + trade.Strike * binaryResult.Pv;
                }

                if (AnalyticalOptionPricerUtil.isBasicPricing(result))
                {
                    result.Delta     = sign * vanillaResult.Delta + trade.Strike * binaryResult.Delta;
                    result.DeltaCash = result.Delta * market.SpotPrices.Value.Values.First();
                    result.Gamma     = sign * vanillaResult.Gamma + trade.Strike * binaryResult.Gamma;
                    result.GammaCash = result.Gamma * market.SpotPrices.Value.Values.First() * market.SpotPrices.Value.Values.First() / 100;
                    result.Vega      = sign * vanillaResult.Vega + trade.Strike * binaryResult.Vega;
                    result.Rho       = sign * vanillaResult.Rho + trade.Strike * binaryResult.Rho;
                    result.Theta     = sign * vanillaResult.Theta + trade.Strike * binaryResult.Theta;
                }

                if (AnalyticalOptionPricerUtil.isHighOrderPricing(result))
                {
                    result.DDeltaDvol = sign * vanillaResult.DDeltaDvol + trade.Strike * binaryResult.DDeltaDvol;
                    result.DVegaDvol  = sign * vanillaResult.DVegaDvol + trade.Strike * binaryResult.DVegaDvol;
                    result.DVegaDt    = sign * vanillaResult.DVegaDt + trade.Strike * binaryResult.DVegaDt;
                    result.DDeltaDt   = sign * vanillaResult.DDeltaDt + trade.Strike * binaryResult.DDeltaDt;
                }
            }
            return(result);
        }
Пример #16
0
        public override IPricingResult Calculate(RainbowOption trade, IMarketCondition market, PricingRequest request)
        {
            var result = new PricingResult(market.ValuationDate, request);

            var exerciseDate = trade.ExerciseDates.Last();
            var maturityDate = trade.UnderlyingMaturityDate;

            //TODO:  support timeIncrement
            var exerciseInYears = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, exerciseDate, trade);
            var maturityInYears = AnalyticalOptionPricerUtil.timeToMaturityFraction(market.ValuationDate, maturityDate, trade);

            var riskFreeRate = market.DiscountCurve.Value.ZeroRate(market.ValuationDate, exerciseDate);
            var ticker1      = trade.UnderlyingTickers[0];
            var ticker2      = trade.UnderlyingTickers[1];

            double dividendRate1, dividendRate2;

            if (AnalyticalOptionPricerUtil.isForwardFuturesOption(trade.UnderlyingProductType))
            {
                dividendRate1 = riskFreeRate;
                dividendRate2 = riskFreeRate;
            }
            else
            {
                dividendRate1 = market.DividendCurves.Value[ticker1].ZeroRate(market.ValuationDate, exerciseDate);
                dividendRate2 = market.DividendCurves.Value[ticker2].ZeroRate(market.ValuationDate, exerciseDate);
            }

            var spot1 = market.SpotPrices.Value[ticker1];
            var spot2 = market.SpotPrices.Value[ticker2];

            var sigma1 = market.VolSurfaces.Value[ticker1].GetValue(exerciseDate, trade.Strikes[0], spot1);
            var sigma2 = market.VolSurfaces.Value[ticker2].GetValue(exerciseDate, trade.Strikes[0], spot2);

            var strike1 = trade.Strikes[0];

            var strike2 = 0.0;

            if (trade.Strikes.Length > 1)
            {
                strike2 = trade.Strikes[1];
            }

            //Note: correlation here is a scala number.  can be a grid for multi-asset option
            var rho = market.Correlations.Value[ticker1].GetValue(exerciseDate, strike1);

            var calculator = new RainbowOptionCalculator(trade.OptionType,
                                                         trade.RainbowType,
                                                         strike1, strike2, trade.CashAmount,
                                                         spot1, spot2, rho,
                                                         sigma1, sigma2,
                                                         exerciseInYears,
                                                         riskFreeRate,
                                                         dividendRate1, dividendRate2,
                                                         trade.Notional);

            bool isExpired         = trade.ExerciseDates.Last() < market.ValuationDate;
            bool isExpiredforTheta = trade.ExerciseDates.Last() <= market.ValuationDate;

            if (isExpired)
            {
                result.Pv                 = 0.0;
                result.Theta              = 0.0;
                result.asset1Delta        = 0.0;
                result.asset1DeltaCash    = 0.0;
                result.asset2Delta        = 0.0;
                result.asset2DeltaCash    = 0.0;
                result.asset1PartialDelta = 0.0;
                result.asset2PartialDelta = 0.0;
                result.asset1Gamma        = 0.0;
                result.asset1GammaCash    = 0.0;
                result.asset2Gamma        = 0.0;
                result.asset2GammaCash    = 0.0;
                result.asset1Vega         = 0.0;
                result.asset2Vega         = 0.0;
                result.Rho                = 0.0;
                result.Theta              = 0.0;
                result.asset1DDeltaDt     = 0.0;
                result.asset2DDeltaDt     = 0.0;
                result.asset1DVegaDvol    = 0.0;
                result.asset2DVegaDvol    = 0.0;
                result.asset1DDeltaDvol   = 0.0;
                result.asset2DDeltaDvol   = 0.0;
                result.asset1DVegaDt      = 0.0;
                result.asset2DVegaDt      = 0.0;
                result.crossGamma         = 0.0;
                result.crossVomma         = 0.0;
                result.crossVanna1        = 0.0;
                result.crossVanna2        = 0.0;
                result.correlationVega    = 0.0;
            }

            else
            {
                if (result.IsRequested(PricingRequest.Pv))
                {
                    result.Pv = calculator.Pv;
                }

                if (AnalyticalOptionPricerUtil.isBasicPricing(result))
                {
                    result.asset1Delta        = calculator.asset1Delta;
                    result.asset2Delta        = calculator.asset2Delta;
                    result.asset1DeltaCash    = calculator.asset1Delta * spot1;
                    result.asset2DeltaCash    = calculator.asset2Delta * spot2;
                    result.asset1PartialDelta = calculator.asset1PartialDelta;
                    result.asset2PartialDelta = calculator.asset2PartialDelta;
                    result.asset1Gamma        = calculator.asset1Gamma;
                    result.asset2Gamma        = calculator.asset2Gamma;
                    result.asset1GammaCash    = calculator.asset1Gamma * spot1 * spot1 / 100;
                    result.asset2GammaCash    = calculator.asset2Gamma * spot2 * spot2 / 100;
                    result.asset1Vega         = calculator.asset1Vega;
                    result.asset2Vega         = calculator.asset2Vega;
                    result.Rho = calculator.Rho;

                    result.Theta = (isExpiredforTheta) ? 0.0 : calculator.Theta;
                }

                if (AnalyticalOptionPricerUtil.isHighOrderPricing(result))
                {
                    result.asset1DVegaDvol  = calculator.asset1DVegaDvol;
                    result.asset2DVegaDvol  = calculator.asset2DVegaDvol;
                    result.asset1DDeltaDvol = calculator.asset1DDeltaDvol;
                    result.asset2DDeltaDvol = calculator.asset2DDeltaDvol;
                    result.crossGamma       = calculator.crossGamma;
                    result.crossVomma       = calculator.crossVomma;
                    result.crossVanna1      = calculator.crossVanna1;
                    result.crossVanna2      = calculator.crossVanna2;
                    result.correlationVega  = calculator.correlationVega;
                }


                if (isExpiredforTheta)
                {
                    result.asset1DDeltaDt = result.asset2DDeltaDt = 0.0;
                    result.asset1DVegaDt  = result.asset2DVegaDt = 0.0;
                }
                else
                {
                    result.asset1DDeltaDt = calculator.asset1DDeltaDt;
                    result.asset2DDeltaDt = calculator.asset2DDeltaDt;
                    result.asset1DVegaDt  = calculator.asset1DVegaDt;
                    result.asset2DVegaDt  = calculator.asset2DVegaDt;
                }
            }
            return(result);
        }
Пример #17
0
        /// <summary>
        /// 计算期权
        /// </summary>
        /// <param name="option">期权</param>
        /// <param name="market">市场</param>
        /// <param name="request">计算请求</param>
        /// <returns>计算结果</returns>
        public override IPricingResult Calculate(IOption option, IMarketCondition market, PricingRequest request)
        {
            var  result            = new PricingResult(market.ValuationDate, request);
            bool isExpired         = option.ExerciseDates.Last() < market.ValuationDate;
            bool isExpiredforTheta = option.ExerciseDates.Last() <= market.ValuationDate;
            bool onMaturityDate    = (option.ExerciseDates.Last() == market.ValuationDate);

            if (isExpired)
            {
                result.Pv         = result.Delta = result.DeltaCash = result.Gamma = result.GammaCash = result.Theta = 0.0;
                result.ThetaPnL   = result.CalenderThetaPnL = result.Vega = result.Rho = result.StoppingTime = 0.0;
                result.DVegaDvol  = result.DVegaDt = result.DDeltaDvol = result.DDeltaDt = 0.0;
                result.PricingVol = 0.0;
                return(result);
            }

            else
            {
                var now = DateTime.Now;
                var expiryDayCutoffTime = new DateTime(now.Year, now.Month, now.Day, 15, 0, 0);
                var expiryDayStartTime  = new DateTime(now.Year, now.Month, now.Day, 9, 30, 0);
                var T = (expiryDayCutoffTime - now).TotalSeconds / (expiryDayCutoffTime - expiryDayStartTime).TotalSeconds / 365.0;

                SetPricingVol(result, option, market);

                //Calc delta/pv differently on expiry day
                if (onMaturityDate && T > 0.0)
                {
                    if (result.IsRequested(PricingRequest.Pv) && double.IsNaN(result.Pv))
                    {
                        result.Pv = DoCalcExpiryPv(option, market, T);
                    }

                    if (result.IsRequested(PricingRequest.Delta) && double.IsNaN(result.Delta))
                    {
                        result.Delta     = DoCalcExpiryDelta(option, market, T);
                        result.DeltaCash = result.Delta * market.SpotPrices.Value.Values.First();
                    }
                }
                else if (onMaturityDate && T <= 0.0)
                {
                    if (result.IsRequested(PricingRequest.Pv) && double.IsNaN(result.Pv))
                    {
                        var pv = CalcPvs(option, market.ToArrayT());
                        result.Pv         = pv[0];
                        result.PricingVol = 0.0;
                    }

                    if (result.IsRequested(PricingRequest.Delta) && double.IsNaN(result.Delta))
                    {
                        var pv = CalcPvs(option, new[] { market })[0];
                        if (option.OptionType == OptionType.Call)
                        {
                            result.Delta     = (pv > 0) ? 1 * option.Notional : 0;
                            result.DeltaCash = result.Delta * market.SpotPrices.Value.Values.First();
                        }
                        else
                        {
                            result.Delta     = (pv > 0) ? -1 * option.Notional: 0;
                            result.DeltaCash = result.Delta * market.SpotPrices.Value.Values.First();
                        }
                    }
                }

                //on other days

                if (result.IsRequested(PricingRequest.Pv) && double.IsNaN(result.Pv))
                {
                    var pv = CalcPvs(option, market.ToArrayT());
                    result.Pv = pv[0];
                }

                if (result.IsRequested(PricingRequest.Delta) && double.IsNaN(result.Delta))
                {
                    result.Delta     = CalcDelta(option, market);
                    result.DeltaCash = result.Delta * market.SpotPrices.Value.Values.First();
                }

                if (result.IsRequested(PricingRequest.Gamma) && double.IsNaN(result.Gamma))
                {
                    result.Gamma     = CalcGamma(option, market);
                    result.GammaCash = result.Gamma * market.SpotPrices.Value.Values.First() * market.SpotPrices.Value.Values.First() / 100;
                }

                if (result.IsRequested(PricingRequest.Vega) && double.IsNaN(result.Vega))
                {
                    result.Vega        = CalcVega(option, market);
                    result.FwdDiffVega = CalcFwdDiffVega(option, market);
                }

                if (result.IsRequested(PricingRequest.Rho) && double.IsNaN(result.Rho))
                {
                    var markets = new[]
                    {
                        market,
                        market.UpdateCondition(new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, market.DiscountCurve.Value.Shift(10))),
                    };
                    var pvs = CalcPvs(option, markets);
                    result.Rho = (pvs[1] - pvs[0]) / 10.0;
                }

                if (result.IsRequested(PricingRequest.DVegaDvol) || result.IsRequested(PricingRequest.DVegaDt) ||
                    result.IsRequested(PricingRequest.DDeltaDvol) || result.IsRequested(PricingRequest.DDeltaDt))
                {
                    CalcHighOrder(option, market, result, isExpiredforTheta);
                }

                if (result.IsRequested(PricingRequest.StoppingTime) && double.IsNaN(result.StoppingTime))
                {
                    var stoppingTime = StoppingTime(option, market.ToArrayT());
                    result.StoppingTime = stoppingTime;
                }

                if (result.IsRequested(PricingRequest.Theta))
                {
                    if (isExpiredforTheta)
                    {
                        result.ThetaPnL = result.CalenderThetaPnL = result.Theta = 0.0;
                        return(result);
                    }
                    else
                    {
                        var thetaResults = CalcTheta(option, market);
                        result.Theta            = thetaResults[0]; // this theta is for time pnl
                        result.ThetaPnL         = thetaResults[1];
                        result.CalenderThetaPnL = thetaResults[2]; //in trading day mode, we cannot calc calendar theta
                    }
                }
            }

            if (option.IsMoneynessOption && result.IsRequested(PricingRequest.Pv) && (option.InitialSpotPrice != 0.0))
            {
                result.PctPv = result.Pv / option.InitialSpotPrice;
            }

            return(result);
        }
Пример #18
0
        /// <summary>
        /// 计算一个债券的估值和基本风险指标
        /// </summary>
        /// <param name="bond">债券</param>
        /// <param name="market">市场数据对象</param>
        /// <param name="request">计算请求类型</param>
        /// <returns>计算结果</returns>
        public override IPricingResult Calculate(Bond bond, IMarketCondition market, PricingRequest request)
        {
            var result = new PricingResult(market.ValuationDate, request);

            var cfs   = bond.GetCashflows(market, true);
            var cfAis = bond.GetAiCashflows(market, false);

            //Ai and AiEod are mutually exclusive requests
            var isEod = result.IsRequested(PricingRequest.AiEod);

            if (result.IsRequested(PricingRequest.Ai) || result.IsRequested(PricingRequest.AiEod))
            {
                result.Ai     = bond.GetAccruedInterest(market.ValuationDate, cfAis, isEod);
                result.AiDays = bond.GetAccruedInterestDays(market.ValuationDate, cfAis, isEod);
            }

            if (result.IsRequested(PricingRequest.Ytm) || result.IsRequested(PricingRequest.DirtyPrice) || result.IsRequested(PricingRequest.CleanPrice) ||
                result.IsRequested(PricingRequest.ModifiedDuration) || result.IsRequested(PricingRequest.Convexity) ||
                (result.IsRequested(PricingRequest.DollarDuration)) || result.IsRequested(PricingRequest.DollarConvexity) ||
                result.IsRequested(PricingRequest.MacDuration) || result.IsRequested(PricingRequest.Pv01) ||
                result.IsRequested(PricingRequest.ZeroSpread) || result.IsRequested(PricingRequest.Dv01) ||
                result.IsRequested(PricingRequest.KeyRateDv01))
            {
                double unitDirtyPrice = 0;
                double unitCleanPrice = 0;
                if (double.IsNaN(result.Ai))
                {
                    result.Ai     = bond.GetAccruedInterest(market.ValuationDate, cfAis, isEod);
                    result.AiDays = bond.GetAccruedInterestDays(market.ValuationDate, cfAis, isEod);
                }
                var bondQuote = market.MktQuote.Value[bond.Id];
                if (bondQuote.Item1 == PriceQuoteType.Dirty)
                {
                    result.DirtyPrice = bondQuote.Item2 * bond.Notional / 100.0;
                    result.Ytm        = _bondYieldPricer.YieldFromFullPrice(cfs, bond.PaymentDayCount, bond.PaymentFreq, bond.StartDate, market.ValuationDate, result.DirtyPrice, bond.BondTradeingMarket, bond.IrregularPayment);
                    result.CleanPrice = result.DirtyPrice - result.Ai;
                    unitDirtyPrice    = bondQuote.Item2;
                    unitCleanPrice    = result.CleanPrice / bond.Notional * 100.0;
                }
                else if (bondQuote.Item1 == PriceQuoteType.Clean)
                {
                    result.CleanPrice = bondQuote.Item2 * bond.Notional / 100.0;
                    result.DirtyPrice = result.CleanPrice + result.Ai;

                    unitCleanPrice = bondQuote.Item2;
                    unitDirtyPrice = result.DirtyPrice / bond.Notional * 100;
                    result.Ytm     = _bondYieldPricer.YieldFromFullPrice(cfs, bond.PaymentDayCount, bond.PaymentFreq, bond.StartDate, market.ValuationDate, result.DirtyPrice, bond.BondTradeingMarket, bond.IrregularPayment);
                }
                else
                {
                    result.Ytm        = bondQuote.Item2;
                    result.DirtyPrice = _bondYieldPricer.FullPriceFromYield(cfs, bond.PaymentDayCount, bond.PaymentFreq, bond.StartDate, market.ValuationDate, result.Ytm, bond.BondTradeingMarket, bond.IrregularPayment);
                    result.CleanPrice = result.DirtyPrice - result.Ai;
                    unitCleanPrice    = result.CleanPrice / 100.0;
                    unitDirtyPrice    = result.DirtyPrice / 100.0;
                }

                if (result.IsRequested(PricingRequest.Convexity) || result.IsRequested(PricingRequest.ModifiedDuration) ||
                    result.IsRequested(PricingRequest.DollarConvexity) || result.IsRequested(PricingRequest.DollarDuration) ||
                    result.IsRequested(PricingRequest.MacDuration) || result.IsRequested(PricingRequest.Pv01))
                {
                    result.MacDuration = _bondYieldPricer.GetMacDuration(cfs, bond.PaymentDayCount, bond.PaymentFreq, bond.StartDate, market.ValuationDate, result.Ytm, bond.BondTradeingMarket);

                    //modified duration here = 1% move, price change, per 100 notional dollar bond
                    result.ModifiedDuration = BondPricingFunctions.GetModifiedDuration(cfs, bond.PaymentDayCount, bond.PaymentFreq, bond.StartDate, market.ValuationDate, result.Ytm, bond.BondTradeingMarket, bond.IrregularPayment, _bondYieldPricer);

                    //1% convexity here, modified duration move, further multiplied by 10000
                    result.Convexity = BondPricingFunctions.GetConvexity(cfs, bond.PaymentDayCount, bond.PaymentFreq, bond.StartDate, market.ValuationDate, result.Ytm,
                                                                         bond.BondTradeingMarket, bond.IrregularPayment, _bondYieldPricer);

                    //1% impact, dollar duration is modified duration in dollar term, but scales with notional, for calculating bond book avg portfolio duration, and display purpose
                    result.DollarModifiedDuration = result.ModifiedDuration * unitDirtyPrice * 0.0001 * bond.Notional;

                    //1% impact, dollar convexity is for calculating both pnl and avg book convexity
                    result.DollarConvexity = result.Convexity / 100 * unitDirtyPrice * bond.Notional;

                    //1bp dollar impact, scales with Notional
                    result.Pv01 = (-result.DollarModifiedDuration + 0.5 * result.DollarConvexity * 0.0001 * 0.0001) / 100.0;
                }
            }

            if (result.IsRequested(PricingRequest.Pv))
            {
                result.Pv = cfs.Where(x => x.PaymentDate > market.ValuationDate)
                            .Sum(x => x.PaymentAmount * market.DiscountCurve.Value.GetDf(market.ValuationDate, x.PaymentDate));
            }

            if (result.IsRequested(PricingRequest.ZeroSpread) || result.IsRequested(PricingRequest.Dv01) || result.IsRequested(PricingRequest.KeyRateDv01) || result.IsRequested(PricingRequest.ZeroSpreadDelta))
            {
                result.ZeroSpread      = BondPricingFunctions.ZeroSpread(cfs, market.DiscountCurve.Value, market.ValuationDate, result.DirtyPrice);
                result.ZeroSpreadDelta = BondPricingFunctions.ZeroSpreadRisk(cfs, market.DiscountCurve.Value, market.ValuationDate, result.ZeroSpread);
                if (market.CreditSpread.HasValue)
                {
                    market =
                        market.UpdateCondition(new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve,
                                                                                        market.DiscountCurve.Value.GetSpreadedCurve(market.CreditSpread.Value)));
                }
                else
                {
                    market =
                        market.UpdateCondition(new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve,
                                                                                        market.DiscountCurve.Value.GetSpreadedCurve(new ZeroSpread(result.ZeroSpread))));
                }
            }

            if (result.IsRequested(PricingRequest.Dv01))
            {
                result.Dv01 = base.Calculate(bond, market, PricingRequest.Dv01).Dv01;
            }

            if (result.IsRequested(PricingRequest.KeyRateDv01))
            {
                result.KeyRateDv01 = base.Calculate(bond, market, PricingRequest.KeyRateDv01).KeyRateDv01;
            }

            if (result.IsRequested(PricingRequest.Cashflow))
            {
                result.Cashflows    = bond.GetCashflows(market, false);
                result.CashflowDict = result.Cashflows.ToDictionary(x => x.ToCfKey(), x => x.PaymentAmount);
            }

            //if (bond.Coupon is FloatingCoupon)
            //{
            //	var primeRateDate = market.ValuationDate;
            //	//var primeRateCashflow = cfAis.FirstOrDefault(x => x.AccrualEndDate > market.ValuationDate && x.AccrualStartDate <= market.ValuationDate);
            //	//if (primeRateCashflow != null)
            //	//{
            //	//	primeRateDate = primeRateCashflow.AccrualStartDate;
            //	//}
            //	var fixingCurve = market.FixingCurve ?? market.DiscountCurve ?? market.RiskfreeCurve;
            //	var fixingTuple = bond.Coupon.GetPrimeCoupon(market.HistoricalIndexRates, fixingCurve.Value, primeRateDate);
            //	if (fixingTuple != null && fixingTuple.Item1 != null)
            //		result.ProductSpecific = new Dictionary<string, Dictionary<string, RateRecord>>
            //		{
            //			{
            //				"currentPrimeRate",
            //				new Dictionary<string, RateRecord>
            //				{
            //					{
            //						bond.Id,
            //						new RateRecord
            //						{
            //							Rate = fixingTuple.Item2,
            //							Date = fixingTuple.Item1.ToString()
            //						}
            //					}
            //				}
            //			}
            //		};
            //}

            return(result);
        }
Пример #19
0
        /// <summary>
        /// 计算一个金融衍生品交易的定价和风险指标
        /// </summary>
        /// <param name="trade">交易</param>
        /// <param name="market">市场数据对象</param>
        /// <param name="request">计算请求类型</param>
        /// <returns>计算结果</returns>
        public override IPricingResult Calculate(TTrade trade, IMarketCondition market, PricingRequest request)
        {
            var result = new PricingResult(market.ValuationDate, request);

            if (result.IsRequested(PricingRequest.Pv))
            {
                result.Pv = CalcPv(trade, market);
            }

            if (result.IsRequested(PricingRequest.Carry))
            {
                result.Carry = CalcCarry(trade, market);
            }

            if (result.IsRequested(PricingRequest.Dv01))
            {
                if (double.IsNaN(result.Pv))
                {
                    result.Pv = CalcPv(trade, market);
                }
                var mktDown = market.FixingCurve.HasValue
                                        ? market.UpdateCondition(
                    new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, market.DiscountCurve.Value.Shift(1)),
                    new UpdateMktConditionPack <IYieldCurve>(x => x.FixingCurve, market.FixingCurve.Value.Shift(1)))
                                        : market.UpdateCondition(
                    new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, market.DiscountCurve.Value.Shift(1)));
                result.Dv01 = CalcPv(trade, mktDown) - result.Pv;
            }

            if (result.IsRequested(PricingRequest.Cashflow))
            {
                result.Cashflows = trade.GetCashflows(market, false);
            }

            //Ai and AiEod are mutually exclusive requests
            var isEod = result.IsRequested(PricingRequest.AiEod);

            if (result.IsRequested(PricingRequest.Ai) || result.IsRequested(PricingRequest.AiEod))
            {
                if (result.Cashflows == null || result.Cashflows.Length == 0)
                {
                    result.Cashflows = trade.GetCashflows(market, false);
                }

                result.Ai = trade.GetAccruedInterest(market.ValuationDate, market, isEod);
            }

            if (result.IsRequested(PricingRequest.KeyRateDv01))
            {
                if (double.IsNaN(result.Pv))
                {
                    result.Pv = CalcPv(trade, market);
                }
                var dc = new Dictionary <string, CurveRisk[]>();
                var fc = new Dictionary <string, CurveRisk[]>();

                Parallel.Invoke(
                    () => CalcDiscountDv01(trade, market, result.Pv, ref dc),
                    () => CalcResetDv01(trade, market, result.Pv, ref fc)
                    );


                result.KeyRateDv01 = PricingResultExtension.Aggregate(dc, fc);
            }

            if (result.IsRequested(PricingRequest.FairQuote))
            {
                result.FairQuote = GetFairQuote(trade, market);
            }

            if (result.IsRequested(PricingRequest.MacDuration))
            {
                if (result.Cashflows == null || result.Cashflows.Length == 0)
                {
                    result.Cashflows = trade.GetCashflows(market, false);
                }
                var weightedCf = 0.0;
                var totalCf    = 0.0;
                foreach (var cashflow in result.Cashflows)
                {
                    if (cashflow.PaymentDate > market.ValuationDate)
                    {
                        var t  = market.DiscountCurve.Value.DayCount.CalcDayCountFraction(market.ValuationDate, cashflow.PaymentDate);
                        var df = market.DiscountCurve.Value.GetDf(market.ValuationDate, cashflow.PaymentDate);

                        weightedCf += cashflow.PaymentAmount * df * t;
                        totalCf    += cashflow.PaymentAmount * df;
                    }
                }
                result.MacDuration = weightedCf / totalCf;
            }

            if (result.IsRequested(PricingRequest.Pv01))
            {
                result.Pv01 = CalcPv01(trade, market, result.Pv);
            }

            Date valueDate = result.ValuationDate;

            if (result.IsRequested(PricingRequest.ProductSpecific))
            {
                var yieldCurve = market.DiscountCurve.Value;

                #region

                var psDict = new Dictionary <string, Dictionary <string, RateRecord> >();
                var dayGap = new DayGap("+0BD");
                var T      = (trade is InterestRateSwap) ? (trade as InterestRateSwap).FloatingLeg : trade as SwapLeg;

                //forward rate points
                var tenors           = new[] { "1D", "7D", "3M", "1Y" };
                var fwdStartInTenors = new List <string> {
                    "1D", "1W", "2W", "1M", "2M", "3M", "4M", "5M", "6M", "7M", "8M", "9M", "10M", "11M", "1Y"
                };
                var totalMonths = Convert.ToInt16((yieldCurve.KeyPoints.Last().Item1 - yieldCurve.KeyPoints.First().Item1) / 30.0) + 1;
                for (var i = 15; i <= totalMonths; i += 3)
                {
                    fwdStartInTenors.Add(i + "M");
                }
                foreach (var tenor in tenors)
                {
                    var fwdRates = new Dictionary <string, RateRecord>();
                    var fwdTerm  = new Term(tenor);
                    foreach (var fwdStartInTenor in fwdStartInTenors)
                    {
                        var fwdStartDate = dayGap.Get(T.Calendar, new Term(fwdStartInTenor).Next(valueDate));
                        var fwdEndDate   = dayGap.Get(T.Calendar, fwdTerm.Next(fwdStartDate));
                        if (fwdEndDate < yieldCurve.KeyPoints.Last().Item1)
                        {
                            fwdRates[fwdStartInTenor] = new RateRecord()
                            {
                                Date = fwdStartDate.ToString(),
                                Rate = yieldCurve.GetForwardRate(fwdStartDate, fwdTerm)
                            };
                        }
                    }

                    psDict["forwardrates" + tenor] = fwdRates;
                }

                //spot rate
                var spotRates    = new Dictionary <string, RateRecord>();
                var spotInTenors = fwdStartInTenors;

                foreach (var spotInTenor in spotInTenors)
                {
                    var spotDate = dayGap.Get(T.Calendar, new Term(spotInTenor).Next(valueDate));
                    if (spotDate <= yieldCurve.KeyPoints.Last().Item1)
                    {
                        spotRates[spotInTenor] = new RateRecord
                        {
                            Date = spotDate.ToString(),
                            Rate = yieldCurve.ZeroRate(valueDate, spotDate, Compound.Simple)
                        };
                    }
                }
                psDict["spotRates"] = spotRates;

                //key rates
                var rates          = new Dictionary <string, RateRecord>();
                var ccTenors       = yieldCurve.GetKeyTenors().ToArray();
                var mktInstruments = yieldCurve.MarketInstruments;
                if (mktInstruments != null)
                {
                    if (mktInstruments.Length != ccTenors.Length)
                    {
                        throw new PricingBaseException("Number of calibration instruments mismatches number of calibrated points!");
                    }
                }
                for (var i = 0; i < ccTenors.Count(); ++i)
                {
                    //var spotDate = mktInstruments != null ? mktInstruments[i].Instrument.GetClibrationDate() : dayGap.Get(T.Calendar, new Term(ccTenors[i]).Next(valueDate));
                    var spotDate = dayGap.Get(T.Calendar, new Term(ccTenors[i]).Next(valueDate));
                    rates[ccTenors[i]] = new RateRecord()
                    {
                        ContinuousRate                           = yieldCurve.ZeroRate(valueDate, spotDate),
                        Date                                     = spotDate.ToString(),
                        DiscountFactor                           = yieldCurve.GetDf(valueDate, spotDate),
                        Rate                                     = mktInstruments == null?yieldCurve.GetSpotRate(spotDate) : mktInstruments[i].TargetValue,
                                                     ProductType = mktInstruments == null ? "None" : (mktInstruments[i].Instrument is Deposit) ? "Index" : "Swap",
                                                     ZeroRate    = yieldCurve.ZeroRate(valueDate, spotDate, Compound.Simple),
                                                     Term        = ccTenors[i]
                    };
                }
                psDict["rates"] = rates;

                //discount at cash flow dates
                var dfs   = new Dictionary <string, RateRecord>();
                var dates = result.Cashflows.Select(x => x.PaymentDate);
                foreach (var date in dates)
                {
                    dfs[date.ToString()] = new RateRecord
                    {
                        DiscountFactor = yieldCurve.GetDf(date)
                    };
                }

                psDict["discountfactor"] = dfs;
                //qb rate return
                result.ProductSpecific = psDict;

                #endregion
            }

            return(result);
        }