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

148 lines
6.2 KiB
C#

using Qdp.Foundation.Implementations;
using Qdp.Pricing.Base.Implementations;
using Qdp.Pricing.Base.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YLErp.Abstract;
using YLErp.BLL.Eod;
using YLErp.BLL;
using YLErp.DBModels;
using YLErp.Modules.TradeModule.KnockOutModule.Dto;
using YLErp.QdpModule;
namespace YLErp.Modules.TradeModule.KnockOutModule
{
/// <summary>
/// 障碍期权敲出服务
/// </summary>
public class BarrierOptionTradeKnockOutService : ITradeKnockOutService
{
public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate, ITradeExtendDataProvider _tradeExtendDataProvider)
{
GetKnockOutPayoffResult result = new GetKnockOutPayoffResult { IsKnockOut = false };
var barrierOption = _tradeExtendDataProvider.GetTrade_Barrier_Option(td.id);
if (barrierOption == null)
{
return new GetKnockOutPayoffResult { IsKnockOut = false };
}
td.trade_barrier_option = barrierOption;
return GetKnockOutPayoff(td, underlyingPrice, _valueDate);
}
public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate)
{
GetKnockOutPayoffResult result = new GetKnockOutPayoffResult { IsKnockOut = false };
var barrierOption = td.trade_barrier_option;
if (barrierOption == null)
{
return result;
}
//连续每天观察 离散根据观察日判断 如果非观察日 不检测敲入敲出
if ("离散".Equals(barrierOption.Discrete))
{
var observationDates = QdpHelper.GetObservationDatesFromString(barrierOption.ObservationDates);
//每日观察或者当前结算日是观察日的时候,才检查是否会敲入敲出
if (observationDates != null && observationDates.Length > 0 && !observationDates.Contains(_valueDate))
{
return result;
}
}
var BarrierPrice = td.IsMoneynessOptionData ? barrierOption.BarrierPrice * td.SpotPrice : barrierOption.BarrierPrice;
var UpperBarrierPrice = td.IsMoneynessOptionData ? barrierOption.UpperBarrierPrice * td.SpotPrice : barrierOption.UpperBarrierPrice;
switch (barrierOption.BarrierType)
{
case "上升敲出":
if (underlyingPrice >= BarrierPrice)
{
result.IsKnockOut = true;
result.Payoff = CalcBarrierOptionTradeKnockOutPayoff(td, barrierOption, underlyingPrice, _valueDate);
}
break;
case "下降敲出":
if (underlyingPrice <= BarrierPrice)
{
result.IsKnockOut = true;
result.Payoff = CalcBarrierOptionTradeKnockOutPayoff(td, barrierOption, underlyingPrice, _valueDate);
}
break;
case "双障碍敲出":
if (underlyingPrice >= UpperBarrierPrice || underlyingPrice <= BarrierPrice)
{
result.IsKnockOut = true;
var upDown = underlyingPrice >= UpperBarrierPrice ? true : false;
result.Payoff = CalcBarrierOptionTradeKnockOutPayoff(td, barrierOption, underlyingPrice, _valueDate, upDown);
}
break;
}
return result;
}
/// <summary>
/// 计算具体收益
/// </summary>
/// <param name="td"></param>
/// <param name="barrierOption"></param>
/// <param name="underlyingPrice"></param>
/// <param name="upDown">双障碍敲出 才有用</param>
/// <returns></returns>
private double CalcBarrierOptionTradeKnockOutPayoff(trade td, trade_barrier_option barrierOption, double underlyingPrice,DateTime _valueDate, bool upDown = false)
{
var spotPrice = td.SpotPrice ?? 0;
double rebate, rebateRate; //计算补偿金额
if (upDown)
{
if (td.IsUsePremiumRate == true)
{
rebateRate = barrierOption.RebateHighRate ?? 0;
rebate = rebateRate * spotPrice;
}
else
{
rebate = barrierOption.RebateHigh ?? 0;
rebateRate = spotPrice > 0 ? rebate / spotPrice : 0;
}
}
else
{
if (td.IsUsePremiumRate == true)
{
rebateRate = barrierOption.RebateRate ?? 0;
rebate = rebateRate * spotPrice;
}
else
{
rebate = barrierOption.Rebate ?? 0; //补偿金额
rebateRate = spotPrice > 0 ? rebate / spotPrice : 0;
}
}
if (barrierOption.RebateAnnualizedAtKO) //补偿按敲出日年化
{
var rebateDayCountImpl = string.IsNullOrWhiteSpace(barrierOption.RebateDayCount) ? new Act365() : barrierOption.RebateDayCount.ToDayCountImpl();
var fraction = rebateDayCountImpl.CalcDayCountFraction(new Date(td.StartDate.Value), new Date(_valueDate));
rebate *= fraction;
rebate += Math.Abs((td.TradeSinglePrice - td.TradeSinglePrice * fraction) ?? 0);
}
var payoff = td.Notional * rebate + ((td.Notional / td.OriginalNotional * td.OriginalPrincipalSum) ?? 0); // 补偿金额 * 持仓份额 + 保底收益总额*尺长比例
//交易员视角
if (valuedateBLL.SystemDate.UnwindAmountAngle == 1)
{
payoff = payoff * (td.BuySell == "卖出" ? -1 : 1);
}
else
{
payoff = payoff * EodOperationBase.GetSign(td.BuySell);
}
return payoff;
}
}
}