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

165 lines
7.0 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.DBModels;
using YLErp.Modules.TradeModule.KnockOutModule.Dto;
using YLErp.QdpModule;
namespace YLErp.Modules.TradeModule.KnockOutModule
{
/// <summary>
/// 美式二元期权敲出服务
/// </summary>
public class AmericanBinaryOptionTradeKnockOutService : ITradeKnockOutService
{
public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate, ITradeExtendDataProvider _tradeExtendDataProvider)
{
var binaryOption = _tradeExtendDataProvider.GetTrade_Binary_Option(td.id);
if (binaryOption == null)
{
return new GetKnockOutPayoffResult { IsKnockOut = false };
}
td.trade_binary_option = binaryOption;
return GetKnockOutPayoff(td, underlyingPrice, _valueDate);
}
/// <summary>
/// 获取敲出赔付
/// </summary>
/// <param name="td"></param>
/// <param name="underlyingPrice"></param>
/// <param name="_valueDate"></param>
/// <param name="binaryOption"></param>
/// <returns></returns>
public GetKnockOutPayoffResult GetKnockOutPayoff(trade td, double underlyingPrice, DateTime _valueDate)
{
var binaryOption = td.trade_binary_option;
GetKnockOutPayoffResult result = new GetKnockOutPayoffResult { IsKnockOut = false };
if (binaryOption == null)
{
return result;
}
if (binaryOption.IsDiscreteMonitored)
{
var observationDates = QdpHelper.GetObservationDatesFromString(binaryOption.ObservationDates);
if (observationDates != null && observationDates.Length > 0 && !observationDates.Contains(_valueDate))
{
return result; //非观察日 不做敲出计算
}
}
var strike = td.IsMoneynessOptionData ? td.Strike * td.SpotPrice : td.Strike;
var UpperBarrier = new Lazy<double?>(() =>
td.IsMoneynessOptionData ? binaryOption.UpperBarrier * td.SpotPrice : binaryOption.UpperBarrier);
switch (binaryOption.PayoffType)
{
case "UpOneTouch":
if (underlyingPrice >= strike)
{
//触碰,买方获得盈利,交易结束
result.IsKnockOut = true;
result.Payoff = CalcAmericanBinaryOptionTradeKnockOutPayoff(td, binaryOption, useHighAmount: false, _valueDate);
}
else if (td.ExerciseDate <= _valueDate)
{
result.IsKnockOut = true;
result.Payoff = 0;
}
break;
case "DownOneTouch":
if (underlyingPrice <= strike)
{
//触碰,买方获得盈利,交易结束
result.IsKnockOut = true;
result.Payoff = CalcAmericanBinaryOptionTradeKnockOutPayoff(td, binaryOption, useHighAmount: false, _valueDate);
}
else if (td.ExerciseDate <= _valueDate)
{
result.IsKnockOut = true;
result.Payoff = 0;
}
break;
case "UpNoTouch":
if (underlyingPrice >= strike)
{
//触碰,买方无盈利,交易结束
result.IsKnockOut = true;
result.Payoff = 0;
}
break;
case "DownNoTouch":
if (underlyingPrice <= strike)
{
//触碰,买方无盈利,交易结束
result.IsKnockOut = true;
result.Payoff = 0;
}
break;
case "DoubleOneTouch":
if (underlyingPrice >= UpperBarrier.Value || underlyingPrice <= strike)
{
var breachHighBarrier = underlyingPrice >= UpperBarrier.Value;
result.IsKnockOut = true;
result.Payoff = CalcAmericanBinaryOptionTradeKnockOutPayoff(td, binaryOption, useHighAmount: breachHighBarrier, _valueDate);
}
else if (td.ExerciseDate <= _valueDate)
{
result.IsKnockOut = true;
result.Payoff = 0;
}
break;
case "DoubleNoTouch":
if (underlyingPrice >= UpperBarrier.Value || underlyingPrice <= strike)
{
//触碰上限或下限,买方无盈利,交易结束
result.IsKnockOut = true;
result.Payoff = 0;
}
break;
}
return result;
}
/// <summary>
/// 计算美式二元敲出 收益
/// </summary>
/// <param name="td"></param>
/// <param name="binaryOption"></param>
/// <param name="useHighAmount"></param>
/// <returns></returns>
private double CalcAmericanBinaryOptionTradeKnockOutPayoff(trade td, trade_binary_option binaryOption, bool useHighAmount,DateTime _valueDate)
{
var result = (td.Notional / td.OriginalNotional * (td.OriginalPrincipalSum ?? 0)) ?? 0;
double refund;
if (td.IsUsePremiumRate == true)
{
var rate = useHighAmount ? binaryOption.CashOrNothingAmountHighRate : binaryOption.CashOrNothingAmountRate;
refund = Math.Abs((rate ?? 0) * (td.SpotPrice ?? 0) * td.Notional);
}
else
{
var amount = useHighAmount ? binaryOption.CashOrNothingAmountHigh : binaryOption.CashOrNothingAmount;
refund = Math.Abs((amount ?? 0) * td.Notional);
}
if (binaryOption.RebateAnnualizedAtKO)
{
var rebateDayCountImpl = string.IsNullOrWhiteSpace(binaryOption.RebateDayCount) ? new Act365() : binaryOption.RebateDayCount.ToDayCountImpl();
var fraction = rebateDayCountImpl.CalcDayCountFraction(new Date(td.StartDate.Value), new Date(_valueDate));
refund *= fraction;
refund += Math.Abs((td.TradePrice - td.TradePrice * fraction) ?? 0);
}
return (result + refund) * EodOperationBase.GetSign(td.BuySell);
}
}
}