using Qdp.Foundation.Implementations;
using Qdp.Pricing.Library.Options.Products.Autocall.Phoenix;
using Qdp.Pricing.Library.Options.Products.Autocall.Snowball;
using YLErp.BLL;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.TradeModule;
namespace YLErp.Modules.EodModule
{
///
/// 检查交易观察日状态和票息是否产生
///
public class CheckTradeObservateStatusService : YLBaseService
{
public CheckTradeObservateStatusService(YLBaseService baseService) : base(baseService)
{
}
public CheckTradeObservateStatusService(OptUserInfo userInfo) : base(userInfo)
{
}
public KeyValuePair CheckTradeObservateStatus(trade td, DateTime valuedate, double[] price, double? SettlementAmount)
{
new TradeExtendService(OptUser, DbContext).SetTradeExtend(new[] { td }, tracking: true);
switch (td.TradeType)
{
case "障碍期权":
if (!string.IsNullOrEmpty(td.trade_barrier_option.KnockInOutStatus))
{
return new KeyValuePair();
}
if (td.TradeStatus != ConsTrade.确认成交)
{
return new KeyValuePair();
}
return checkBarrierObservateStatus(td, valuedate, price);
case "双鲨期权":
if (!string.IsNullOrEmpty(td.trade_double_sharkfin_option.KnockInOutStatus))
{
return new KeyValuePair();
}
if (td.TradeStatus != ConsTrade.确认成交)
{
return new KeyValuePair();
}
return checkDoubleSharkObservateStatus(td, valuedate, price);
case "区间累积期权":
return checkRangeAccrualObservateStatus(td, valuedate, price);
case "凤凰期权":
return checkAutocallObservateStatus(td, valuedate, price, SettlementAmount);
case "雪球期权":
return checkSnowballObservateStatus(td, valuedate, price, SettlementAmount);
case "气囊结构":
return checkAirbagObservateStatus(td, valuedate, price);
default:
return new KeyValuePair();
}
}
public KeyValuePair checkBarrierObservateStatus(trade td, DateTime valuedate, double[] price)
{
var tradeBarrier = td.trade_barrier_option;
var BarrierPrice = td.IsMoneynessOptionData ? tradeBarrier.BarrierPrice * td.SpotPrice : tradeBarrier.BarrierPrice;
var UpperBarrierPrice = td.IsMoneynessOptionData ? tradeBarrier.UpperBarrierPrice * td.SpotPrice : tradeBarrier.UpperBarrierPrice;
var highPrice = tradeBarrier.Discrete == "离散" ? price[0] : price[1];
var lowPrice = tradeBarrier.Discrete == "离散" ? price[0] : price[2];
switch (tradeBarrier.BarrierType)
{
case "上升敲入":
if (highPrice >= BarrierPrice)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedIn, false);
}
break;
case "上升敲出":
if (highPrice >= BarrierPrice)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedOut, true);
}
break;
case "下降敲入":
if (lowPrice <= BarrierPrice)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedIn, false);
}
break;
case "下降敲出":
if (lowPrice <= BarrierPrice)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedOut, true);
}
break;
case "双障碍敲出":
if (highPrice >= UpperBarrierPrice || lowPrice <= BarrierPrice)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedOut, true);
}
break;
case "双障碍敲入":
if (highPrice >= UpperBarrierPrice || lowPrice <= BarrierPrice)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedIn, false);
}
break;
}
return new KeyValuePair();
}
public KeyValuePair checkDoubleSharkObservateStatus(trade td, DateTime valuedate, double[] price)
{
var tradeDbShark = td.trade_double_sharkfin_option;
var barrierHigh = td.IsMoneynessOptionData ? tradeDbShark.BarrierHigh * td.SpotPrice : tradeDbShark.BarrierHigh;
var barrierLow = td.IsMoneynessOptionData ? tradeDbShark.BarrierLow * td.SpotPrice : tradeDbShark.BarrierLow;
var highPrice = price[1];
var lowPrice = price[2];
if (highPrice >= barrierHigh || lowPrice <= barrierLow)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedOut, true);
}
return new KeyValuePair();
}
public KeyValuePair checkRangeAccrualObservateStatus(trade td, DateTime valuedate, double[] price)
{
var tradeRange = td.trade_rangeaccrual;
var upperRange = td.IsMoneynessOptionData ? tradeRange.UpperRange * td.SpotPrice.Value : tradeRange.UpperRange;
var lowerRange = td.IsMoneynessOptionData ? tradeRange.LowerRange * td.SpotPrice.Value : tradeRange.LowerRange;
//有区间收益
if (price[0] < upperRange && price[0] > lowerRange)
{
return new KeyValuePair("", true);
}
return new KeyValuePair("", false);
}
public KeyValuePair checkAutocallObservateStatus(trade td, DateTime valuedate, double[] price, double? SettlementAmount)
{
var tradeCashs = DbContext.trade_cash.Where(x => x.ValidState != ConsGlobal.InValid && !x.IsDeleted && x.TradeId == td.id && x.Action == "系统操作-平仓费" && (x.ValueDate > valuedate && (x.ConfirmDate > valuedate || x.ConfirmDate == DateTime.MinValue)) && x.UnwindNotional < x.Notional).ToList();
var notional = (ConsTrade.TradeCompleteStatus.Contains(td.TradeStatus) && td.UnWindDate <= valuedate ? 0 : td.Notional) + tradeCashs.Sum(x => x.UnwindNotional).Value;
var optionTrade = QdpTradeBuilder.GetAutocallOptionTrade(td, td.trade_autocall,
new OptionTradeParamRequest(valuedateBLL.SysRiskFreeRate()) { ParamOverride = x => { x.notional = notional; } });
var autocall = (AutoCall)optionTrade.Instrument;
var kiBarrier = td.IsMoneynessOptionData ? td.trade_autocall.KIBarrier * td.SpotPrice : td.trade_autocall.KIBarrier;
if (autocall.KOObsDates.Select(x => x.DateTime).Contains(valuedate)
&& td.trade_autocall.KnockInOutStatus != ConsTrade.KnockState.KnockedOut)
{
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 = td.trade_autocall.KOBarrier;
}
if (td.IsMoneynessOptionData)
{
koBarrier *= td.SpotPrice ?? 1.0;
}
#region 票息检查
var couponBarrier =
td.IsMoneynessOptionData ?
td.trade_autocall.CouponBarrier * td.SpotPrice :
td.trade_autocall.CouponBarrier;
var isKnockedOut = price[0] >= koBarrier;
//有票息
if (price[0] >= couponBarrier)
{
//利息计算时,当autocall的Notional包含了符号,则GetEffectiveObservation考虑了买卖方向了
var observation = autocall.GetEffectiveObservation(new Date(valuedate));
if (observation != null)
{
//观察日页面设置的结算金额
if (SettlementAmount != null)
{
//到期敲入且未敲出情况
if (valuedate == autocall.ExerciseDates.Last().DateTime && !isKnockedOut)
{
//当前满足敲入或者已经敲入了
if (autocall.KIObsDates.Select(x => x.DateTime).Contains(valuedate) && price[0] <= kiBarrier || td.trade_autocall.KnockInOutStatus == ConsTrade.KnockState.KnockedIn)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedIn, true);
}
}
}
//SaveCouponObservation(trade.trade, observation, valuedate, closePrice, isKnockedOut);
}
return new KeyValuePair(ConsTrade.KnockState.Monitoring, true);
}
#endregion
#region 敲出检查
// 发生敲出事件
if (isKnockedOut)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedOut, false);
}
#endregion
}
#region 敲入检查
//在当前结算日之前未敲出且未敲入:
if (!((td.trade_autocall.KnockInOutStatus == ConsTrade.KnockState.KnockedOut
|| td.trade_autocall.KnockInOutStatus == ConsTrade.KnockState.KnockedIn)
&& td.trade_autocall.KnockInOutDate < valuedate)
&& autocall.KIObsDates.Select(x => x.DateTime).Contains(valuedate))
{
// 发生敲入事件
if (price[0] <= kiBarrier)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedIn, false);
}
}
#endregion
#region 到期检查
if (valuedate == autocall.ExerciseDates.Last().DateTime)
{
td.UnWindDate = valuedate;
if (td.trade_autocall.KnockInOutStatus == ConsTrade.KnockState.KnockedIn)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedIn, false);
}
else if (td.trade_autocall.KnockInOutStatus != ConsTrade.KnockState.KnockedOut)
{
return new KeyValuePair(ConsTrade.KnockState.Monitoring, false);
}
else if (td.trade_autocall.KnockInOutStatus == ConsTrade.KnockState.KnockedOut)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedOut, false);
}
}
#endregion
return new KeyValuePair();
}
public KeyValuePair checkSnowballObservateStatus(trade td, DateTime valueDate, double[] price, double? SettlementAmount)
{
var tradeCashs = DbContext.trade_cash.Where(x => x.ValidState != ConsGlobal.InValid && !x.IsDeleted && x.TradeId == td.id && x.Action == "系统操作-平仓费" && (x.ValueDate > valueDate && (x.ConfirmDate > valueDate || x.ConfirmDate == DateTime.MinValue)) && x.UnwindNotional < x.Notional).ToList();
var request = new OptionTradeParamRequest(valuedateBLL.SysRiskFreeRate())
{
ParamOverride = p => p.notional = (ConsTrade.TradeCompleteStatus.Contains(td.TradeStatus) && td.UnWindDate <= valueDate ? 0 : td.Notional) + tradeCashs.Sum(x => x.UnwindNotional).Value
};
var optionTrade = QdpTradeBuilder.GetSnowballOptionTrade(td, td.trade_snowball, request);
var datesStr = td.trade_snowball.KOObservationSettleDates;
var KOObsSettleDates = string.IsNullOrWhiteSpace(datesStr) ? null : datesStr.Split(new char[] { ',', ';', ',', ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => DateTime.Parse(x)).ToArray();
var snowball = (SimpleSnowball)optionTrade.Instrument;
//只在敲出观察日检查敲出和票息情况
//如果交易已经是敲出状态了,不用再做票息和敲出检查
if (snowball.KOObsDates.Select(x => x.DateTime).Contains(valueDate)
&& td.trade_snowball.KnockInOutStatus != ConsTrade.KnockState.KnockedOut)
{
#region 敲出检查
double koBarrier;
var koSettleDate = valueDate;
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 = td.trade_snowball.KOBarrier;
if (KOObsSettleDates != null && KOObsSettleDates.Any())
{
koSettleDate = KOObsSettleDates[0];
}
}
if (td.trade_snowball.KORebateType == RebateTypeEnum.AtEnd)
{
koSettleDate = td.ExerciseDate.Value;
}
else if (koSettleDate < valueDate)
{
koSettleDate = valueDate;
}
if (td.IsMoneynessOptionData)
{
koBarrier *= td.SpotPrice ?? 1.0;
}
// 发生敲出事件
if (price[0] >= koBarrier)
{
if (snowball.UseOptionPayoffAtKO)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedOut, false);
}
else
{
if (SettlementAmount != null)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedOut, false);
}
else
{
return new KeyValuePair(ConsTrade.KnockState.KnockedOut, true);
}
}
}
return new KeyValuePair(td.trade_snowball.KnockInOutStatus, true);
#endregion
}
#region 敲入检查
//在当前结算日之前未敲出且未敲入:
// !((KO || KI) && KOKIDate < valueDate)
if (!((td.trade_snowball.KnockInOutStatus == ConsTrade.KnockState.KnockedOut
|| td.trade_snowball.KnockInOutStatus == ConsTrade.KnockState.KnockedIn)
&& td.trade_snowball.KnockInOutDate < valueDate)
&& snowball.KIObsDates.Select(x => x.DateTime).Contains(valueDate)
&& td.trade_snowball.KIPayoffType != KIPayoffTypeEnum.None)
{
var kiBarrier =
td.IsMoneynessOptionData ?
td.trade_snowball.KIBarrier * td.SpotPrice :
td.trade_snowball.KIBarrier;
// 发生敲入事件
if (price[0] <= kiBarrier)
{
return new KeyValuePair(ConsTrade.KnockState.KnockedIn, false);
}
}
#endregion
#region 到期检查
if (valueDate == snowball.ExerciseDates.Last().DateTime)
{
if (snowball.UseOptionPayoffAtMaturity &&
(td.trade_snowball.KnockInOutStatus == ConsTrade.KnockState.KnockedIn || td.trade_snowball.KIBarrier <= 0))
{
return new KeyValuePair(ConsTrade.KnockState.KnockedIn, false);
}
else if (td.trade_snowball.KnockInOutStatus != ConsTrade.KnockState.KnockedOut)
{
return new KeyValuePair(ConsTrade.KnockState.Monitoring, false);
}
}
#endregion
return new KeyValuePair();
}
public KeyValuePair checkAirbagObservateStatus(trade td, DateTime valuedate, double[] price)
{
//气囊结构暂时都是每日连续观察,不用考虑观察周期问题
//气囊结构暂时都是向下敲入
var tradeAirbag = td.trade_airbag;
if (valuedate == td.ExerciseDate)
{
if (price[0] >= td.SpotPrice)
{
return new KeyValuePair(tradeAirbag.KnockInOutStatus, true);
}
else if (tradeAirbag.KnockInOutStatus == ConsTrade.KnockState.KnockedIn)
{
return new KeyValuePair(tradeAirbag.KnockInOutStatus, true);
}
else
{
return new KeyValuePair(tradeAirbag.KnockInOutStatus, false);
}
}
return new KeyValuePair(tradeAirbag.KnockInOutStatus, false);
}
}
}