예제 #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);
        }
예제 #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);
        }
예제 #3
0
파일: Index.cs 프로젝트: stepinto163/Qdp
        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);
            }
        }