Example #1
0
        public static Date GetFxSpotDate(Date startDate,
                                         DayGap settlement,
                                         CurrencyCode fgnCcy,
                                         CurrencyCode domCcy,
                                         ICalendar fgnCalendar,
                                         ICalendar domCalendar)
        {
            //中国外汇交易中心产品指引(外汇市场)V1.8 58页
            var foreignSpotDate  = settlement.Get(fgnCalendar, startDate);
            var domesticSpotDate = settlement.Get(domCalendar, startDate);

            var usdCalendar = CalendarImpl.Get(Calendar.Usd);

            if (fgnCcy == CurrencyCode.USD)
            {
                if (!usdCalendar.IsHoliday(domesticSpotDate))
                {
                    return(domesticSpotDate);
                }
            }

            if (domCcy == CurrencyCode.USD)
            {
                if (!usdCalendar.IsHoliday(foreignSpotDate))
                {
                    return(foreignSpotDate);
                }
            }

            var guessSettlementDate = foreignSpotDate > domesticSpotDate ? foreignSpotDate : domesticSpotDate;

            if (usdCalendar.IsHoliday(guessSettlementDate) || fgnCalendar.IsHoliday(guessSettlementDate) || domCalendar.IsHoliday(guessSettlementDate))
            {
                //find next biz day for foreign currency and domestic currency
                while (fgnCalendar.IsHoliday(guessSettlementDate) || domCalendar.IsHoliday(guessSettlementDate))
                {
                    guessSettlementDate = new Term("1D").Next(guessSettlementDate);
                }
                return(guessSettlementDate);
            }

            return(guessSettlementDate);
        }
Example #2
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);
        }
Example #3
0
        public double GetFixingRate(IYieldCurve fixingCurve,
                                    ICalendar resetCalendar,
                                    IDayCount dayCount,
                                    Date accStartDate,
                                    Date accEndDate,
                                    ITerm resetTerm,
                                    ITerm fixingTenor,
                                    DayGap fixingToResetGap,
                                    Stub resetStub,
                                    BusinessDayConvention resetBda,
                                    double couponSpread,
                                    double capRate,
                                    double floorRate,
                                    out CfCalculationDetail[] resetDetails,
                                    IDictionary <Date, double> historicalRate = null,
                                    FloatingCouponCalcType frnCalc            = FloatingCouponCalcType.SimpleFrn,
                                    double stepWiseCompensationCoupon         = 0.0,
                                    double multiplier = 1.0)
        {
            var details     = new List <CfCalculationDetail>();
            var resetPriods = resetTerm == null
                                ? new List <Date> {
                accStartDate, accEndDate
            }
                                : new Schedule(accStartDate, accEndDate, resetTerm, resetStub, resetCalendar, resetBda).ToList();


            for (var i = 0; i < resetPriods.Count - 1; ++i)
            {
                var resetStartDate = resetPriods[i];
                var resetEndDate   = resetPriods[i + 1];
                if (resetEndDate > accEndDate)
                {
                    resetEndDate = accEndDate;
                }
                var fixingStartDate = fixingToResetGap.Get(resetCalendar, resetStartDate);

                var forwardCompound = frnCalc == FloatingCouponCalcType.ZzFrn ? Compound.Continuous : IndexType.ForwardCompound();
                details.Add(new CfCalculationDetail(
                                resetStartDate,
                                resetEndDate,
                                fixingStartDate,
                                multiplier * GetResetRate(fixingCurve, fixingStartDate, resetCalendar, fixingTenor, AverageDays, historicalRate, forwardCompound, IndexType.DayCount()) + stepWiseCompensationCoupon,
                                dayCount.CalcDayCountFraction(resetStartDate, resetEndDate, accStartDate, accEndDate),
                                resetStartDate < (fixingCurve == null ? fixingStartDate : fixingCurve.ReferenceDate)));
            }

            resetDetails = details.ToArray();
            var    totalDcf = resetDetails.Sum(x => x.FixingDcf);
            double couponRate;

            switch (CouponCompound)
            {
            case CouponCompound.Compounded:
                couponRate =
                    (resetDetails.Select(x =>
                {
                    var coupon = FilterRate(x.FixingRate + couponSpread, capRate, floorRate);
                    return(1.0 + coupon * x.FixingDcf);
                })
                     .Aggregate(1.0, (current, v) => current * v) - 1.0) / totalDcf;
                return(couponRate);

            case CouponCompound.Simple:
                couponRate =
                    resetDetails.Select(x =>
                {
                    var coupon = FilterRate(x.FixingRate + couponSpread, capRate, floorRate);
                    return(coupon * x.FixingDcf);
                }).Sum() / totalDcf;
                return(couponRate);

            default:
                throw new PricingLibraryException("Unknow type of coupon compund type" + CouponCompound);
            }
        }