Files
zszq-trs/YLErpDAL/Modules/TradeModule/KnockOutModule/SnowBallTradeKnockOutService.cs
T
2024-05-09 14:06:26 +08:00

142 lines
6.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using CsvHelper;
using Qdp.Foundation.Implementations;
using Qdp.Pricing.Library.Options.Products.Autocall.Snowball;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YLErp.Abstract;
using YLErp.BLL;
using YLErp.DBModels;
using YLErp.DBModels.Helpers;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.TradeModule.ExoticOptionModule;
using YLErp.Modules.TradeModule.KnockOutModule.Dto;
namespace YLErp.Modules.TradeModule.KnockOutModule
{
/// <summary>
/// 雪球期权敲出计算服务
/// </summary>
public class SnowBallTradeKnockOutService : ITradeKnockOutService
{
public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate, ITradeExtendDataProvider _tradeExtendDataProvider)
{
var snowBallOption = _tradeExtendDataProvider.GetTrade_Snowball_Option(td.id);
if (snowBallOption == null)
{
return new GetKnockOutPayoffResult { IsKnockOut = false };
}
td.trade_snowball = snowBallOption;
return GetKnockOutPayoff(td, underlyingPrice, _valueDate);
}
public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate)
{
GetKnockOutPayoffResult result = new GetKnockOutPayoffResult { IsKnockOut = false };
var snowBallOption = td.trade_snowball;
if (snowBallOption == null)
{
return result;
}
if (snowBallOption.PrepaymentUsed)
{
var specialSnowBallResult = new SpecialSnowballObservationHelper(td, snowBallOption).GetObservationResultForTraderSide(_valueDate, underlyingPrice, td.Notional);
if (specialSnowBallResult != null && specialSnowBallResult.ResultType == SnowballObservationResultType.KoPayoff)
{
result.IsKnockOut = true;
result.Payoff = specialSnowBallResult.PaymentAmount;
}
return result;
}
var request = new OptionTradeParamRequest(valuedateBLL.SysRiskFreeRate())
{
ParamOverride = p => p.notional = td.Notional
};
var optionTrade = QdpTradeBuilder.GetSnowballOptionTrade(td, snowBallOption, request);
var snowball = (SimpleSnowball)optionTrade.Instrument;
var isCall = ConsGlobal.CallPut.IsCall(td.CallPut);
if (snowball.KOObsDates.Select(x => x.DateTime).Contains(_valueDate))
{
(var koSettleDate, var koBarrier) = GetSnowBallKoSettleInfo(_valueDate, td, snowBallOption, snowball);
// 发生敲出事件(看涨 - 向上敲出支付票息,看跌 - 向下敲出支付票息)
if (isCall ? underlyingPrice >= koBarrier : underlyingPrice <= koBarrier)
{
result.IsKnockOut = true;
if (snowball.UseOptionPayoffAtKO)
{
double paymentAmount = 0;
var koOptionCashflows = snowball.GetKOPayoff(new Date(_valueDate), underlyingPrice);
paymentAmount = TradeHelper.GetAmountByPaymentAmount(koOptionCashflows[0].PaymentAmount, td.PrincipalSum(), td.BuySell);
result.Payoff = paymentAmount;
}
else
{
var CouponPayment = snowball.CouponPayment(_valueDate, includeStartDate: snowBallOption.CouponIncludeStartDate == true && snowBallOption.CouponDayCount != "Monthly");
var couponPayment = TradeHelper.GetAmountByPaymentAmount(CouponPayment, td.PrincipalSum(), td.BuySell);
if (snowBallOption.AnnualizedPremiumRate.HasValue && snowBallOption.AnnualizedPremiumRate != 0)
{
var tradePrice = (td.StockEqvNotional * td.ParticipationRate * snowBallOption.AnnualizedPremiumRate * snowball.CouponDayCount.CalcDayCountFraction(snowball.StartDate, new Date(_valueDate))) ?? 0;
if (tradePrice != 0)
{
couponPayment += (td.BuySell == "买入" ? -1 : 1) * tradePrice;
}
}
result.Payoff = couponPayment;
}
}
}
return result;
}
//获取雪球期权敲出时要准备的信息
public (DateTime koSettleDate, double koBarrier) GetSnowBallKoSettleInfo(DateTime valueDate, OtcTradeBase otcTrade, trade_snowball tradeSnowball, SimpleSnowball snowball)
{
double koBarrier;
var koSettleDate = valueDate;
var datesStr = tradeSnowball.KOObservationSettleDates;
var KOObsSettleDates = string.IsNullOrWhiteSpace(datesStr) ? null : datesStr.Split(new char[] { ',', ';', '', '' }, StringSplitOptions.RemoveEmptyEntries).Select(x => DateTime.Parse(x)).ToArray();
if (snowball.CustomizedKOBarriers != null && snowball.CustomizedKOBarriers.Length > 0)
{
var index = snowball.KOObsDates.Select(x => x.DateTime).ToList().IndexOf(valueDate);
koBarrier = snowball.CustomizedKOBarriers[index];
if (KOObsSettleDates != null && KOObsSettleDates.Length > index)
{
koSettleDate = KOObsSettleDates[index];
}
}
else
{
koBarrier = tradeSnowball.KOBarrier;
if (KOObsSettleDates != null && KOObsSettleDates.Any())
{
koSettleDate = KOObsSettleDates[0];
}
}
if (tradeSnowball.KORebateType == RebateTypeEnum.AtEnd)
{
koSettleDate = otcTrade.ExerciseDate.Value;
}
else if (koSettleDate < valueDate)
{
koSettleDate = valueDate;
}
if (otcTrade.IsMoneynessOptionData)
{
koBarrier *= otcTrade.SpotPrice ?? 1.0;
}
return (koSettleDate, koBarrier);
}
}
}