165 lines
7.0 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|