95 lines
4.2 KiB
C#
95 lines
4.2 KiB
C#
using Qdp.Pricing.Library.Options.Products.Autocall.Phoenix;
|
|
using YLErp.Abstract;
|
|
using YLErp.BLL;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.TradeModule.KnockOutModule.Dto;
|
|
|
|
namespace YLErp.Modules.TradeModule.KnockOutModule
|
|
{
|
|
/// <summary>
|
|
/// 凤凰期权敲出计算服务
|
|
/// </summary>
|
|
public class AutocallTradeKnockOutService : ITradeKnockOutService
|
|
{
|
|
public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate, ITradeExtendDataProvider _tradeExtendDataProvider)
|
|
{
|
|
|
|
var autocallOption = _tradeExtendDataProvider.GetTrade_Autocall_Option(td.id);
|
|
if (autocallOption == null)
|
|
{
|
|
return new GetKnockOutPayoffResult { IsKnockOut = false };
|
|
}
|
|
td.trade_autocall = autocallOption;
|
|
return GetKnockOutPayoff(td, underlyingPrice, _valueDate);
|
|
}
|
|
|
|
public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate)
|
|
{
|
|
var result = new GetKnockOutPayoffResult { IsKnockOut = false };
|
|
var autocallOption = td.trade_autocall;
|
|
if (autocallOption == null)
|
|
{
|
|
return result;
|
|
}
|
|
//1、获取敲出观察日期
|
|
var optionTrade = QdpTradeBuilder.GetAutocallOptionTrade(td, autocallOption,
|
|
new OptionTradeParamRequest(valuedateBLL.SysRiskFreeRate()) { ParamOverride = x => { x.notional = td.Notional; } });
|
|
var autocall = (AutoCall)optionTrade.Instrument;
|
|
var kiBarrier = td.IsMoneynessOptionData ? autocallOption.KIBarrier * td.SpotPrice : autocallOption.KIBarrier;
|
|
var isCall = ConsGlobal.CallPut.IsCall(td.CallPut);
|
|
if (autocall.KOObsDates.Select(x => x.DateTime).Contains(_valueDate)) //当前日为观察日
|
|
{
|
|
|
|
//2、敲出判断
|
|
double koBarrier;
|
|
if (autocall.CustomizedKOBarriers != null && autocall.CustomizedKOBarriers.Length > 0)
|
|
{
|
|
var index = autocall.KOObsDates.Select(x => x.DateTime).ToList().IndexOf(_valueDate);
|
|
koBarrier = autocall.CustomizedKOBarriers[index];
|
|
}
|
|
else
|
|
{
|
|
koBarrier = autocallOption.KOBarrier;
|
|
}
|
|
|
|
if (td.IsMoneynessOptionData)
|
|
{
|
|
koBarrier *= td.SpotPrice ?? 1.0;
|
|
}
|
|
|
|
//看涨 - 向上敲出,看跌 - 向下敲出
|
|
var isKnockedOut = isCall ? underlyingPrice >= koBarrier : underlyingPrice <= koBarrier;
|
|
|
|
if (isKnockedOut)
|
|
{
|
|
result.IsKnockOut = true;
|
|
var couponBarrier = td.IsMoneynessOptionData ? autocallOption.CouponBarrier * td.SpotPrice : autocallOption.CouponBarrier;
|
|
if (isCall ? underlyingPrice >= couponBarrier : underlyingPrice <= couponBarrier) // 与派息障碍价格比较
|
|
{
|
|
var observation = autocall.GetEffectiveObservation(_valueDate, includeTradeStartDate: autocallOption.CouponIncludeStartDate == true && autocallOption.CouponDayCount != "Monthly");
|
|
if (observation != null)
|
|
{
|
|
result.Payoff = observation.PaymentAmount;
|
|
}
|
|
}
|
|
if (autocallOption.CouponPayType == CouponPayTypeEnum.AtCreated) //如果是产生时支付,持仓payoff为当日票息
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//如果到期支付 或者 敲出支付 持仓payoff加上之前的票息
|
|
using (var db = DbContextFactory.GetYLDbContext())
|
|
{
|
|
var obsAmount = db.autocall_observation.Where(o => o.TradeId == td.id && o.EndDate != _valueDate).Sum(p => p.PaymentAmount);
|
|
result.Payoff += obsAmount;
|
|
}
|
|
return result;
|
|
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|