Beispiel #1
0
        /// <summary>
        /// 获取行权收益
        /// </summary>
        /// <param name="price">标的资产价格</param>
        /// <returns>行权收益</returns>
        public override Cashflow[] GetPayoff(double[] price)
        {
            var payoff          = 0.0;
            var effectiveStrike = IsMoneynessOption? Strike * InitialSpotPrice : Strike;

            switch (OptionType)
            {
            case OptionType.Call:
                payoff = Math.Max(0.0, price[0] - effectiveStrike);
                break;

            case OptionType.Put:
                payoff = Math.Max(0.0, effectiveStrike - price[0]);
                break;

            default:
                throw new PricingBaseException("Unknow/illegal option type!");
            }

            var actualPaymentDate = SettlmentGap.Get(Calendar, UnderlyingMaturityDate);

            return(new[]
            {
                new Cashflow(StartDate, UnderlyingMaturityDate, actualPaymentDate, payoff * Notional, PayoffCcy, CashflowType.Net, false, double.NaN, null),
                //new Cashflow(StartDate, UnderlyingMaturityDate, OptionPremiumPaymentDate ?? actualPaymentDate, OptionPremium, PayoffCcy, CashflowType.Net, true, double.NaN, null)
            });
        }
Beispiel #2
0
        protected OptionBase(Date startDate,
                             Date maturityDate,
                             OptionExercise exercise,
                             OptionType optionType,
                             double[] strike,
                             InstrumentType underlyingInstrumentType,
                             ICalendar calendar,
                             IDayCount dayCount,
                             CurrencyCode payoffCcy,
                             CurrencyCode settlementCcy,
                             Date[] exerciseDates,
                             Date[] observationDates,
                             double notional                      = 1.0,
                             DayGap settlementGap                 = null,
                             Date optionPremiumPaymentDate        = null,
                             double optionPremium                 = 0.0,
                             string[] underlyingTickers           = null,
                             bool isMoneynessOption               = false,
                             double initialSpotPrice              = 0.0,
                             Dictionary <Date, double> dividends  = null,
                             bool hasNightMarket                  = false,
                             bool commodityFuturesPreciseTimeMode = false)
        {
            StartDate = startDate;

            Exercise              = exercise;
            OptionType            = optionType;
            Strike                = strike[0];
            Strikes               = strike;
            UnderlyingProductType = underlyingInstrumentType;

            Calendar               = calendar;
            DayCount               = dayCount;
            SettlmentGap           = settlementGap ?? new DayGap("+0BD");
            UnderlyingMaturityDate = SettlmentGap.Get(Calendar, maturityDate);

            ExerciseDates    = exerciseDates;
            ObservationDates = observationDates;

            UnderlyingTickers = underlyingTickers;

            Notional      = notional;
            PayoffCcy     = payoffCcy;
            SettlementCcy = settlementCcy;

            OptionPremiumPaymentDate = optionPremiumPaymentDate;
            OptionPremium            = optionPremium;

            IsMoneynessOption = isMoneynessOption;
            InitialSpotPrice  = initialSpotPrice;
            Dividends         = dividends;

            HasNightMarket = hasNightMarket;
            CommodityFuturesPreciseTimeMode = commodityFuturesPreciseTimeMode;
        }
Beispiel #3
0
        /// <summary>
        /// 获取行权收益
        /// </summary>
        /// <param name="pricePath">价格路径</param>
        /// <returns>行权收益</returns>
        public override Cashflow[] GetPayoff(Dictionary <Date, double> pricePath)
        {
            var prices = new SortedDictionary <Date, double>(pricePath);

            //merges fixings and monte carlo path
            foreach (var key in Fixings.Keys)
            {
                prices[key] = Fixings[key];
            }

            var simulatedValuesToCheck = ObservationDates.Select(x => prices[x]).ToArray();
            var actualPaymentDate      = SettlmentGap.Get(Calendar, UnderlyingMaturityDate);
            var voidCf = new[]
            {
                new Cashflow(StartDate, UnderlyingMaturityDate, actualPaymentDate, Rebate * Notional, PayoffCcy, CashflowType.Net, false, double.NaN, null),
                new Cashflow(StartDate, UnderlyingMaturityDate, OptionPremiumPaymentDate ?? actualPaymentDate, OptionPremium, PayoffCcy, CashflowType.Net, true, double.NaN, null)
            };

            switch (BarrierType)
            {
            case BarrierType.UpAndOut:
                return(simulatedValuesToCheck.Any(val => val > Barrier)
                                                ? voidCf
                                                : GetPayoff(new[] { prices.Last().Value }));

            case BarrierType.UpAndIn:
                return(simulatedValuesToCheck.Any(val => val > Barrier)
                                                ? GetPayoff(new[] { prices.Last().Value })
                                                : voidCf);

            case BarrierType.DownAndOut:
                return(simulatedValuesToCheck.Any(val => val < Barrier)
                                                ? voidCf
                                                : GetPayoff(new[] { prices.Last().Value }));

            case BarrierType.DownAndIn:
                return(simulatedValuesToCheck.Any(val => val < Barrier)
                                                ? GetPayoff(new[] { prices.Last().Value })
                                                : voidCf);

            case BarrierType.DoubleTouchOut:
                return(simulatedValuesToCheck.Any(val => (val > UpperBarrier || val < Barrier))
                                                ? voidCf
                                                : GetPayoff(new[] { prices.Last().Value }));

            case BarrierType.DoubleTouchIn:
                return(simulatedValuesToCheck.Any(val => (val > UpperBarrier || val < Barrier))
                                                ? GetPayoff(new[] { prices.Last().Value })
                                                : voidCf);

            default:
                return(voidCf);
            }
        }
Beispiel #4
0
        public override Cashflow[] GetPayoff(Dictionary <Date, double> pricePath)
        {
            var prices = new Dictionary <Date, double>(pricePath);

            //merges fixings and monte carlo path

            foreach (var key in Fixings.Keys)
            {
                prices[key] = Fixings[key];
            }

            var amount = Ranges.Select(
                x => 1.0 * x.ObservationDates.Count(date => prices[date] > x.LowerRange && prices[date] < x.UpperRange) * x.BonusRate / x.ObservationDates.Length
                ).Sum();

            var settlementDate = SettlmentGap.Get(Calendar, UnderlyingMaturityDate);

            return(new[]
            {
                new Cashflow(StartDate, UnderlyingMaturityDate, settlementDate, amount * Notional, SettlementCcy, CashflowType.Net, false, double.NaN, null),
                new Cashflow(StartDate, UnderlyingMaturityDate, OptionPremiumPaymentDate ?? settlementDate, OptionPremium, SettlementCcy, CashflowType.Net, false, double.NaN, null)
            });
        }
Beispiel #5
0
        //Todo Fixing payoff
        public override Cashflow[] GetPayoff(double[] price)
        {
            //price:{ minPrice, maxPrice, pricePath[ExerciseDates[0]] }
            //used in approximation
            var amount          = 0.0;
            var effectiveStrike = IsMoneynessOption ? Strike * InitialSpotPrice : Strike;

            if (OptionType == OptionType.Call)
            {
                amount = StrikeStyle == StrikeStyle.Fixed ? Math.Max(0.0, price[1] - effectiveStrike) : Math.Max(0.0, price[2] - price[0]);
            }
            else if (OptionType == OptionType.Put)
            {
                amount = StrikeStyle == StrikeStyle.Fixed ? Math.Max(0.0, effectiveStrike - price[0]) : Math.Max(0.0, price[1] - price[2]);
            }

            var settlementDate = SettlmentGap.Get(Calendar, UnderlyingMaturityDate);

            return(new[]
            {
                new Cashflow(StartDate, UnderlyingMaturityDate, settlementDate, amount * Notional, SettlementCcy, CashflowType.Net, false, double.NaN, null),
                //new Cashflow(StartDate, UnderlyingMaturityDate, OptionPremiumPaymentDate ?? settlementDate, OptionPremium, SettlementCcy, CashflowType.Net, false, double.NaN, null)
            });
        }
Beispiel #6
0
        private Cashflow[] GetBondCashflows(IMarketCondition market, bool netted = true, bool calcAi = false)
        {
            var accruals             = Accruals.ToArray();
            var schedulePaymentDates = calcAi ? Accruals.Skip(1).ToArray() : PaymentSchedule.ToArray();

            if (schedulePaymentDates.Length == 0)
            {
                throw  new PricingLibraryException("Number of payments is 0");
            }

            List <CfCalculationDetail[]> cfCalcDetails;

            var cashflows  = new List <Cashflow>();
            var prevCfDate = accruals[0];

            var coupons = Coupon.GetCoupon(
                Accruals,
                market.FixingCurve.HasValue ? market.FixingCurve.Value : null,
                market.HistoricalIndexRates.HasValue ? market.HistoricalIndexRates.Value : null,
                out cfCalcDetails,
                IssueRate,
                _compensationRate);
            var refStartDates = new List <Date>();
            var refEndDates   = new List <Date>();

            for (var i = 0; i < coupons.Length; ++i)
            {
                var refStartDate = accruals[i];
                var refEndDate   = accruals[i + 1];
                if (i == 0 && !_isRegualDate[i])
                {
                    if (PaymentFreq != Frequency.None)
                    {
                        if (Stub == Stub.LongStart || Stub == Stub.ShortStart)
                        {
                            refStartDate = PaymentFreq.GetTerm().Prev(refEndDate);
                        }
                        else
                        {
                            refEndDate = PaymentFreq.GetTerm().Next(refStartDate);
                        }
                    }
                }
                refStartDates.Add(refStartDate);
                refEndDates.Add(refEndDate);
            }

            IAmortization amortization;

            if (AmortizationType == AmortizationType.EqualPrincipal || AmortizationType == AmortizationType.EqualPrincipalAndInterest)
            {
                //for these two types, amortization is calculated in cash flow calculation
                var      tArr = coupons.Select((x, i) => AccrualDayCount.CalcDayCountFraction(accruals[i], accruals[i + 1], refStartDates[i], refEndDates[i])).ToArray();
                double[] begPrincipal;
                double[] interest;
                double[] principalPay;
                double[] prepayment;
                double[] defaultPrincipal;
                _mortgageCalculator.GetPaymentDetails(tArr, Notional, coupons, PaymentFreq, AmortizationType, out begPrincipal, out interest, out principalPay, out prepayment, out defaultPrincipal, 0);
                amortization = new Amortization(ToAmortizationSchedule(schedulePaymentDates, principalPay.Select((x, i) => Tuple.Create(i + 1, x)).ToDictionary(x => x.Item1, x => x.Item2)), false);
            }
            else
            {
                amortization = Amoritzation.Adjust(new Schedule(schedulePaymentDates), Calendar, calcAi ? AccrualBizDayRule : PaymentBizDayRule, PaymentFreq);
                amortization = amortization.ResetAmortization(market.ValuationDate);
            }

            for (var i = 0; i < coupons.Length; ++i)
            {
                var amortizationRedemption = 0.0;
                var remainPrincipal        = 100.0;
                var couponPay = 0.0;
                var prevDate  = prevCfDate;
                if (amortization.AmortizationSchedule != null && amortization.AmortizationSchedule.Any(x => x.Key > prevCfDate && x.Key < schedulePaymentDates[i]))
                {
                    var intermediatePrePayDate = amortization.AmortizationSchedule.Where(x => x.Key > prevCfDate && x.Key < schedulePaymentDates[i]).Select(x => x.Key).OrderBy(x => x).ToArray();
                    CfCalculationDetail[] tmpCfCalculationDetails;
                    foreach (var date in intermediatePrePayDate)
                    {
                        amortizationRedemption = amortization.GetRemainingPrincipal(prevDate);
                        remainPrincipal        = Notional * amortizationRedemption;
                        var periodCoupon = Coupon.GetCoupon(prevDate, date, market.FixingCurve.Value, market.HistoricalIndexRates, out tmpCfCalculationDetails, _compensationRate[i]);
                        couponPay = remainPrincipal * periodCoupon * AccrualDayCount.CalcDayCountFraction(prevDate, date, refStartDates[i], refEndDates[i]);
                        cashflows.Add(new Cashflow(prevDate, date, date, couponPay, Currency, CashflowType.Coupon, tmpCfCalculationDetails.Aggregate(true, (current, v) => current & v.IsFixed), market.GetDf(date), cfCalcDetails[i], refStartDates[i], refEndDates[i], remainPrincipal, periodCoupon));
                        prevDate = date;
                    }
                    coupons[i]       = Coupon.GetCoupon(prevDate, accruals[i + 1], market.FixingCurve.Value, market.HistoricalIndexRates, out tmpCfCalculationDetails, _compensationRate[i]);
                    cfCalcDetails[i] = tmpCfCalculationDetails;
                }

                amortizationRedemption = amortization.GetRemainingPrincipal(prevDate);
                remainPrincipal        = Notional * amortizationRedemption;
                couponPay = remainPrincipal * coupons[i] * AccrualDayCount.CalcDayCountFraction(prevDate, accruals[i + 1], refStartDates[i], refEndDates[i]);

                if (i == coupons.Length - 1)
                {
                    amortizationRedemption = amortization.GetRemainingPrincipal(prevCfDate);
                    remainPrincipal        = Notional * amortizationRedemption;

                    //final settlement might be adjusted, coupon [MaturityDate, settlementDate) is added
                    if (SettlmentGap != null)
                    {
                        var settlementDate = SettlmentGap.Get(Calendar, UnderlyingMaturityDate);
                        if (settlementDate > accruals[i + 1])
                        {
                            var tmpCoupon        = double.IsNaN(_settlementCoupon) ? coupons[i] : _settlementCoupon;
                            var additionalCoupon = remainPrincipal * tmpCoupon * AccrualDayCount.CalcDayCountFraction(UnderlyingMaturityDate, settlementDate, refStartDates[i], refEndDates[i]);
                            couponPay += additionalCoupon;
                        }
                    }

                    couponPay = Redemption.GetRedemptionPayment(couponPay, remainPrincipal) - remainPrincipal;
                }

                cashflows.Add(new Cashflow(prevDate, accruals[i + 1], schedulePaymentDates[i], couponPay, Currency, CashflowType.Coupon, cfCalcDetails[i] == null ? true : cfCalcDetails[i].Aggregate(true, (current, v) => current & v.IsFixed), market.GetDf(schedulePaymentDates[i]), cfCalcDetails[i], refStartDates[i], refEndDates[i], remainPrincipal, coupons[i]));
                prevCfDate = accruals[i + 1];
            }

            cashflows.AddRange(amortization.AmortizationSchedule.Keys.Select(key => new Cashflow(key, key, key, amortization.AmortizationSchedule[key] * Notional, Currency, CashflowType.Principal, true, market.GetDf(key), null)));

            if (netted)
            {
                return(cashflows
                       .GroupBy(cf => cf.PaymentDate)
                       .Select(item => new Cashflow(item.Min(x => x.AccrualStartDate), item.Max(x => x.AccrualEndDate), item.Key, item.Sum(entry => entry.PaymentAmount), Currency, CashflowType.Coupon, item.Aggregate(true, (current, v) => current && v.IsFixed), market.GetDf(item.Key), item.Min(x => x.CalculationDetails), item.Min(x => x.RefStartDate), item.Max(x => x.RefEndDate), item.Max(entry => entry.StartPrincipal), item.Sum(entry => entry.CouponRate)))
                       .OrderBy(cf => cf.PaymentDate)
                       .ToArray());
            }
            else
            {
                return(cashflows.ToArray());
            }
        }
Beispiel #7
0
        /// <summary>
        /// 获取行权收益
        /// </summary>
        /// <param name="price">标的资产价格</param>
        /// <returns>行权收益</returns>
        public override Cashflow[] GetPayoff(double[] price)
        {
            //used in approximation
            var amount          = 0.0;
            var effectiveStrike = IsMoneynessOption ? Strike * InitialSpotPrice : Strike;

            if (OptionType == OptionType.Call)
            {
                if (StrikeStyle == StrikeStyle.Fixed)
                {
                    if (this.AsianType == AsianType.GeometricAverage)
                    {
                        var n          = this.Fixings.Count;
                        var finalPrice = Math.Pow(this.Fixings.Select(x => x.Value).Aggregate(func: (result, item) => result * item), 1.0 / n);
                        amount = Math.Max(finalPrice - effectiveStrike, 0);
                    }
                    else if (AsianType == AsianType.ArithmeticAverage || AsianType == AsianType.DiscreteArithmeticAverage)
                    {
                        var finalPrice = this.Fixings.Select(x => x.Value).Average();
                        amount = Math.Max(finalPrice - effectiveStrike, 0);
                    }
                }
                else
                {
                    if (this.AsianType == AsianType.GeometricAverage)
                    {
                        var strike = this.Fixings.Select(x => x.Value).Aggregate(func: (result, item) => result * item);
                        amount = Math.Max(price[0] - strike, 0);
                    }
                    else if (AsianType == AsianType.ArithmeticAverage || AsianType == AsianType.DiscreteArithmeticAverage)
                    {
                        var strike = this.Fixings.Select(x => x.Value).Average();
                        amount = Math.Max(price[0] - strike, 0);
                    }
                }
            }
            else // Put
            {
                if (StrikeStyle == StrikeStyle.Fixed)
                {
                    if (this.AsianType == AsianType.GeometricAverage)
                    {
                        var n          = this.Fixings.Count;
                        var finalPrice = Math.Pow(this.Fixings.Select(x => x.Value).Aggregate(func: (result, item) => result * item), 1.0 / n);
                        amount = Math.Max(effectiveStrike - finalPrice, 0);
                    }
                    else if (AsianType == AsianType.ArithmeticAverage || AsianType == AsianType.DiscreteArithmeticAverage)
                    {
                        var finalPrice = this.Fixings.Select(x => x.Value).Average();
                        amount = Math.Max(effectiveStrike - finalPrice, 0);
                    }
                }
                else
                {
                    if (this.AsianType == AsianType.GeometricAverage)
                    {
                        var strike = this.Fixings.Select(x => x.Value).Aggregate(func: (result, item) => result * item);
                        amount = Math.Max(strike - price[0], 0);
                    }
                    else if (AsianType == AsianType.ArithmeticAverage || AsianType == AsianType.DiscreteArithmeticAverage)
                    {
                        var strike = this.Fixings.Select(x => x.Value).Average();
                        amount = Math.Max(strike - price[0], 0);
                    }
                }
            }

            var settlementDate = SettlmentGap.Get(Calendar, UnderlyingMaturityDate);

            return(new[]
            {
                new Cashflow(StartDate, UnderlyingMaturityDate, settlementDate, amount * Notional, SettlementCcy, CashflowType.Net, false, double.NaN, null),
                //new Cashflow(StartDate, UnderlyingMaturityDate, OptionPremiumPaymentDate ?? settlementDate, OptionPremium, SettlementCcy, CashflowType.Net, false, double.NaN, null)
            });
        }
Beispiel #8
0
        /// <summary>
        /// 获取行权收益
        /// </summary>
        /// <param name="price">标的资产价格</param>
        /// <returns>行权收益</returns>
        public override Cashflow[] GetPayoff(double[] price)
        {
            var    actualPaymentDate = SettlmentGap.Get(Calendar, UnderlyingMaturityDate);
            double payoff;

            double vanillaPayoff;
            var    effectiveStrike = IsMoneynessOption ? Strike * InitialSpotPrice : Strike;

            switch (OptionType)
            {
            case OptionType.Call:
                vanillaPayoff = Math.Max(price[0] - effectiveStrike, 0.0) * ParticipationRate + Coupon;
                break;

            case OptionType.Put:
                vanillaPayoff = Math.Max(effectiveStrike - price[0], 0.0) * ParticipationRate + Coupon;
                break;

            default:
                throw new PricingBaseException("Unknow/illegal option type!");
            }

            if (BarrierStatus == BarrierStatus.Monitoring)
            {
                switch (BarrierType)
                {
                case BarrierType.UpAndIn:
                case BarrierType.DownAndIn:
                    payoff = Rebate;
                    break;

                default:
                    payoff = vanillaPayoff;
                    break;
                }
            }
            else if (BarrierStatus == BarrierStatus.KnockedOut)
            {
                switch (BarrierType)
                {
                case BarrierType.UpAndOut:
                case BarrierType.DownAndOut:
                    payoff = Rebate;
                    break;

                default:
                    payoff = 0.0;
                    break;
                }
            }
            else
            {
                payoff = vanillaPayoff;
                //if knocked in, barrier reduce to vanilla
            }

            return(new[]
            {
                new Cashflow(StartDate, UnderlyingMaturityDate, actualPaymentDate, payoff * Notional, PayoffCcy, CashflowType.Net, false, double.NaN, null),
                //new Cashflow(StartDate, UnderlyingMaturityDate, OptionPremiumPaymentDate ?? actualPaymentDate, OptionPremium, PayoffCcy, CashflowType.Net, true, double.NaN,null)
            });
        }