using Qdp.Foundation.Implementations;
using Qdp.Pricing.Base.Implementations;
using Qdp.Pricing.Library.Options.Products.Autocall.Phoenix;
using Qdp.Pricing.Library.Options.Products.Autocall.Snowball;
using YLErp.BLL;
using YLErp.BLL.Calculation.V2;
using YLErp.BLL.EodSettlement;
using YLErp.DBModels;
using YLErp.DBModels.Helpers;
using YLErp.Models;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.TradeModule;
using YLErp.Modules.TradeModule.DealModule;
using YLErp.Modules.TradeModule.ExoticOptionModule;
using YLErp.QdpModule;
namespace YLErp.Modules.RiskModule
{
///
/// 资金流动性预测
///
public class FlowRiskService : YLBaseService
{
public FlowRiskService(OptUserInfo userInfo) : base(userInfo)
{
}
public FlowRiskService(YLBaseService baseService) : base(baseService)
{
}
///
/// 价格
///
private Dictionary _prices = new Dictionary();
///
/// 障碍期权
///
private BarrierOptionKnockioService barrierService = null;
///
/// 二元期权
///
private BinaryOptionDealService binaryService = null;
///
/// 双鲨期权
///
private DoubleSharkOptionKnockoutService doubleSharkService = null;
///
/// 区间累积期权
///
private TradeRangeAccrualService rangeAccrualService = null;
///
/// 凤凰期权
///
private TradeAutocallBLL autocallService = null;
///
/// 雪球期权
///
private TradeSnowballBLL snowballService = null;
public List QueryFlowRiskList(DateTime startDate, DateTime endDate)
{
if (endDate < startDate)
{
return new List();
}
var flowRiskList = new List();
var dates = QdpCalendarHelper.AllBizDays(startDate, endDate);
var list =
(from t in DbContext.trade
where
ConsTrade.PositionTradeStatusList.Contains(t.TradeStatus) &&
t.ExerciseDate >= startDate && t.ValidState != "InValid"
select t).ToArray();
#if DEBUG
//string temp = "";
//list = DbContext.trade.Where(O => O.TradeNumber == temp).ToArray();
#endif
tradeBLL.SetFieldsByTradeType(list);
var subTradeDict = list.Where(O => O.ParentTradeId > 0).GroupBy(O => O.ParentTradeId).ToDictionary(K => K.Key, V => V.ToList());
list = list.Where(O => O.ParentTradeId == 0).ToArray();
foreach (var item in list)
{
if (subTradeDict.ContainsKey(item.id))
{
item.SubTrades = subTradeDict[item.id];
}
if (item.UnderlyingCode == null)
{
item.UnderlyingCode = "";
}
if (!_prices.ContainsKey(item.UnderlyingCode))
{
_prices[item.UnderlyingCode] = DataCacheProvider.GetUnderlyingDataSource().GetPrice(item.UnderlyingCode);
}
if (item.SubTrades != null && item.SubTrades.Any())
{
var endAll = true;
DateTime? settledate = null;
var trades = item.SubTrades.Where(O => O.TradeType != "现金流交易");
foreach (var sItem in trades)
{
if (!_prices.ContainsKey(sItem.UnderlyingCode))
{
_prices[sItem.UnderlyingCode] = DataCacheProvider.GetUnderlyingDataSource().GetPrice(sItem.UnderlyingCode);
}
var obj = CheckTradeStatus(sItem, startDate, endDate);
flowRiskList.Add(obj);
settledate = obj?.ValueDate ?? sItem.ExerciseDate ?? endDate;
if (!ConsTrade.TradeCompleteStatus.Contains(sItem.TradeStatus))
{
endAll = false;
}
}
if (endAll)
{
//结构化交易中所有非现金流交易全部了结时,现金流交易也应该了结;
trades = item.SubTrades.Where(O => O.TradeType == "现金流交易");
foreach (var sItem in trades)
{
var obj = new FlowRiskModel();
var udm = new underlying_manager();
udm.QuotationDate = sItem.ExerciseDate;
var ttm = TradeCalcHelper.CalculateTTMDays(sItem.ExerciseDate.Value, sItem.ExerciseDate.Value, udm.UnderlyingTypeId, false);
var OptionValue = ValueCalculator.GetOptionValueResultV2(
UserInfo.UserId.ToString(),
udm,
sItem,
new double[] { 0.0 },
new double[] { 0.0 },
null,
timeToMaturityDays: ttm,
request: QdpPricingRequest.BASIC_PRICING);
obj.Execute -= OptionValue.Pv;
obj.ValueDate = settledate ?? startDate;
obj.TradeType = "现金流交易";
obj.TradeNumber = sItem.TradeNumber;
obj.EncryptId = sItem.EncryptId;
flowRiskList.Add(obj);
}
}
}
else
{
var obj = CheckTradeStatus(item, startDate, endDate);
flowRiskList.Add(obj);
}
}
var dict = flowRiskList.Where(O => O != null && O.TotleCash != 0).GroupBy(O => O.ValueDate).ToDictionary(K => K.Key, V => V.ToList()).OrderBy(O => O.Key);
var result = new List();
var total = new FlowRiskModel() { ParentLevel = 2 };
foreach (var item in dict)
{
var parent = new FlowRiskModel() { ParentLevel = 1, ValueDate = item.Key, KO = item.Value.Sum(O => O.KO), Execute = item.Value.Sum(O => O.Execute) };
total.KO += parent.KO;
total.Execute += parent.Execute;
result.Add(parent);
result.AddRange(item.Value);
}
result.Add(total);
return result;
}
private FlowRiskModel CheckTradeStatus(trade td, DateTime startDate, DateTime endDate)
{
var result = new FlowRiskModel();
result.TradeNumber = td.TradeNumber;
result.TradeType = td.TradeType;
result.EncryptId = td.EncryptId;
switch (td.TradeType)
{
case "香草期权":
case "亚式期权":
case "合成价差期权":
case "收益增强结构":
case "自定义交易":
if (td.ExerciseDate > endDate)
{
result = null;
break;
}
trade_cash r = new trade_cash();
SettlementCalcCommons.SetPossibleExec(r, td, _prices[td.UnderlyingCode]);
td.TradeStatus = "已到期";
result.Execute = -r.Amount;
result.ValueDate = td.ExerciseDate.Value;
break;
case "收益互换":
if (td.ExerciseDate > endDate)
{
result = null;
break;
}
var tradeCashList = DbContext.trade_cash.Where(y => y.TradeId == td.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= td.ExerciseDate);
var tradeCashIds = tradeCashList.Select(x => x.id);
var tradeCash = tradeCashList.OrderByDescending(y => y.id).FirstOrDefault();
var cashSwaps = DbContext.trade_cash_swap.Where(x => x.TradeId == td.id && tradeCashIds.Contains(x.TradeCashId)).ToArray();
var tradeCashSwap = tradeCash != null ? cashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id) : null;
//取最后一次手动收益;
var lastManualCashSwap = cashSwaps.OrderByDescending(o => o.StartDate).FirstOrDefault(x => !x.IsAuto);
var lastManualCash = lastManualCashSwap != null ? tradeCashList.FirstOrDefault(x => x.id == lastManualCashSwap.TradeCashId) : null;
DateTime endDateSwap;
var preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, td.ExerciseDate.Value, tradeCash, lastManualCash, td.trade_swap.IsGetFloatingProfit, out endDateSwap);
var initialAmountPay = PayoffSwapCalcService.GetInitialAmountSwapPay(td, td.trade_swap, tradeCashSwap?.PayFinalPrice ?? td.trade_swap.PaySpotPrice ?? 0
, _prices[td.UnderlyingCode], td.StockEqvNotional, td.ExerciseDate.Value, tradeCash?.ValueDate);
var extraAmountGet = PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.GetSwapTimeAndRate, preSwapDate, endDateSwap, td.trade_swap.AnnualDays ?? 0, td.StockEqvNotional);
preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, td.ExerciseDate.Value, tradeCash, lastManualCash, td.trade_swap.IsPayFloatingProfit, out endDateSwap);
var initialAmountGet = PayoffSwapCalcService.GetInitialAmountSwapGet(td, td.trade_swap, tradeCashSwap?.GetFinalPrice ?? td.trade_swap.GetSpotPrice ?? 0
, _prices[td.UnderlyingCode], td.StockEqvNotional, td.ExerciseDate.Value, tradeCash?.ValueDate);
var extraAmountPay = PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.PaySwapTimeAndRate, preSwapDate, endDateSwap, td.trade_swap.AnnualDays ?? 0, td.StockEqvNotional);
td.TradeStatus = "已到期";
result.Execute = -((initialAmountGet + extraAmountGet) - (initialAmountPay + extraAmountPay));
result.ValueDate = td.ExerciseDate.Value;
break;
case "现金流交易":
if (td.ExerciseDate > endDate)
{
result = null;
break;
}
var udm = new underlying_manager();
udm.QuotationDate = td.ExerciseDate;
var ttm = TradeCalcHelper.CalculateTTMDays(td.ExerciseDate.Value, td.ExerciseDate.Value, udm.UnderlyingTypeId, false);
var OptionValue = ValueCalculator.GetOptionValueResultV2(
UserInfo.UserId.ToString(),
udm,
td,
new double[] { 0.0 },
new double[] { 0.0 },
null,
timeToMaturityDays: ttm,
request: QdpPricingRequest.BASIC_PRICING);
result.Execute -= OptionValue.Pv;
result.ValueDate = td.ExerciseDate.Value;
if ((td.SettlementDate ?? td.ExerciseDate.GetValueOrDefault()) > endDate)
{
result = null;
}
break;
case "凤凰期权":
{
autocallService = autocallService ?? new TradeAutocallBLL(UserInfo);
var observDates = CalendarImpl.Get("chn").BizDaysBetweenDatesInclEndDay(
new Date(td.TradeDate), new Date(td.ExerciseDate.Value)).Where(O => O.DateTime != td.TradeDate).ToArray();
//敲入转期权和到期支付票息同时存在时,若设置观察价格页面设置了结算金额,作为票息处理,敲入了结金额维持系统计算逻辑不变
bool hasUseSettlementAmount = false;
var tradeCashs = DbContext.trade_cash.Where(x => x.ValidState != ConsGlobal.InValid && !x.IsDeleted && x.TradeId == td.id && x.Action == "系统操作-平仓费" && (x.ValueDate > startDate && (x.ConfirmDate > startDate || x.ConfirmDate == DateTime.MinValue)) && x.UnwindNotional < x.Notional).ToList();
var notional = (ConsTrade.TradeCompleteStatus.Contains(td.TradeStatus) && td.UnWindDate <= startDate ? 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;
var happenedObservations = new List();
foreach (var date in observDates)
{
if (date.DateTime < startDate || date.DateTime > endDate)
{
continue;
}
var isKnockedOut = false;
//只在敲出观察日检查敲出和票息情况
//如果交易已经是敲出状态了,不用再做票息和敲出检查
if (autocall.KOObsDates.Select(x => x.DateTime).Contains(date.DateTime)
&& 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(date.DateTime);
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;
isKnockedOut = true;// _prices[td.UnderlyingCode] >= koBarrier;
//有票息
//if (_prices[td.UnderlyingCode] >= couponBarrier)
{
//利息计算时,当autocall的Notional包含了符号,则GetEffectiveObservation考虑了买卖方向了
var observation = autocall.GetEffectiveObservation(date);
if (observation != null)
{
td.trade_autocall = td.trade_autocall;
//观察日页面设置的结算金额
if (td.SettlementAmount != null)
{
td.SettlementAmount = td.SettlementAmount;
hasUseSettlementAmount = true;
//到期敲入且未敲出情况
if (date.DateTime == autocall.ExerciseDates.Last().DateTime && !isKnockedOut)
{
//当前满足敲入或者已经敲入了
if (autocall.KIObsDates.Select(x => x.DateTime).Contains(date.DateTime) && _prices[td.UnderlyingCode] <= kiBarrier || td.trade_autocall.KnockInOutStatus == ConsTrade.KnockState.KnockedIn)
{
var optionPayoffPayment = autocall.GetPayoff(new double[] { _prices[td.UnderlyingCode] });
var paymentAmount = TradeHelper.GetAmountByPaymentAmount(optionPayoffPayment[0].PaymentAmount, td.PrincipalSum(), td.BuySell);
td.SettlementAmount -= paymentAmount;
}
}
}
happenedObservations.Add(autocallService.SaveCouponObservation(td, td.trade_autocall, observation, date.DateTime, _prices[td.UnderlyingCode], isKnockedOut, td.SettlementAmount, false));
}
}
#endregion
#region 敲出检查
// 发生敲出事件
if (isKnockedOut)
{
// 更新观察状态
td.trade_autocall.KnockInOutStatus = ConsTrade.KnockState.KnockedOut;
td.trade_autocall.KnockInOutDate = date.DateTime;
// 更新交易状态
td.TradeStatus = ConsTrade.已平仓;
td.UnWindDate = date.DateTime;
happenedObservations.ForEach(O =>
{
result.KO -= O.PaymentAmount;
});
result.ValueDate = date;
if (td.trade_autocall.CouponPayType != CouponPayTypeEnum.AtMaturity)
{
break;
}
}
#endregion
}
#region 敲入检查
//在当前结算日之前未敲出且未敲入:
if (autocall.KIObsDates.Select(x => x.DateTime).Contains(date.DateTime) && !isKnockedOut)
{
//看涨 - 向下敲入,看跌 - 向上敲入
var knockedin = ConsGlobal.CallPut.IsCall(td.CallPut) ? _prices[td.UnderlyingCode] <= kiBarrier : _prices[td.UnderlyingCode] >= kiBarrier;
// 发生敲入事件
if (knockedin)
{
// 更新观察状态
td.trade_autocall.KnockInOutStatus = ConsTrade.KnockState.KnockedIn;
td.trade_autocall.KnockInOutDate = date.DateTime;
}
}
#endregion
#region 到期检查
if (date.DateTime == autocall.ExerciseDates.Last().DateTime)
{
td.UnWindDate = date.DateTime;
if (td.trade_autocall.KnockInOutStatus == ConsTrade.KnockState.KnockedIn)
{
td.TradeStatus = ConsTrade.已执行;
if (!autocall.IncludeCouponAfterKI)
{
// 敲入不支付票息,则要将之前累积的票息删除掉
happenedObservations.Clear();
hasUseSettlementAmount = false;
}
double paymentAmount = 0;
if (td.SettlementAmount != null && !hasUseSettlementAmount)
{
paymentAmount = td.SettlementAmount ?? 0;
}
else
{
//已敲入,到期时计算期权收益
var optionPayoffPayment = autocall.GetPayoff(new double[] { _prices[td.UnderlyingCode] });
//optionPayoffPayment[0].PaymentAmount包含了买卖方向的处理了
paymentAmount = TradeHelper.GetAmountByPaymentAmount(optionPayoffPayment[0].PaymentAmount, td.PrincipalSum(), td.BuySell);
}
if (td.trade_autocall.CouponPayAtMaturity && td.trade_autocall.IncludeCouponAfterKI)
{
happenedObservations.AddRange(DbContext.autocall_observation.Where(o => o.TradeId == td.id).ToList());
}
}
else if (td.trade_autocall.KnockInOutStatus != ConsTrade.KnockState.KnockedOut)
{
// 更新交易状态
td.TradeStatus = ConsTrade.已到期;
if (td.trade_autocall.CouponPayAtMaturity)
{
happenedObservations.AddRange(DbContext.autocall_observation.Where(o => o.TradeId == td.id).ToList());
}
if ((td.SettlementDate ?? td.ExerciseDate.GetValueOrDefault()) > endDate)
{
result = null;
}
}
else if (td.trade_autocall.KnockInOutStatus == ConsTrade.KnockState.KnockedOut)
{
if (td.trade_autocall.CouponPayAtMaturity)
{
happenedObservations.AddRange(DbContext.autocall_observation.Where(o => o.TradeId == td.id).ToList());
}
}
if (result != null)
{
happenedObservations.ForEach(O =>
{
result.Execute -= O.PaymentAmount;
});
result.ValueDate = date;
}
break;
}
#endregion
}
}
break;
case "雪球期权":
{
snowballService = snowballService ?? new TradeSnowballBLL(UserInfo);
var observDates = CalendarImpl.Get("chn").BizDaysBetweenDatesInclEndDay(
new Date(td.TradeDate), new Date(td.ExerciseDate.Value)).Where(O => O.DateTime != td.TradeDate).ToArray();
var tradeCashs = DbContext.trade_cash.Where(x => x.ValidState != ConsGlobal.InValid && !x.IsDeleted && x.TradeId == td.id && x.Action == "系统操作-平仓费" && (x.ValueDate > startDate && (x.ConfirmDate > startDate || 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 <= startDate ? 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;
var happenedObservations = new List();
foreach (var date in observDates)
{
if (date.DateTime < startDate || date.DateTime > endDate)
{
continue;
}
//只在敲出观察日检查敲出和票息情况
//如果交易已经是敲出状态了,不用再做票息和敲出检查
if (snowball.KOObsDates.Select(x => x.DateTime).Contains(date.DateTime)
&& td.trade_snowball.KnockInOutStatus != ConsTrade.KnockState.KnockedOut)
{
#region 敲出检查
double koBarrier;
var koSettleDate = date.DateTime;
if (snowball.CustomizedKOBarriers != null && snowball.CustomizedKOBarriers.Length > 0)
{
var index = snowball.KOObsDates.Select(x => x.DateTime).ToList().IndexOf(date.DateTime);
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 < date.DateTime)
{
koSettleDate = date.DateTime;
}
if (koSettleDate > endDate)
{
result = null;
break;
}
if (td.IsMoneynessOptionData)
{
koBarrier *= td.SpotPrice ?? 1.0;
}
// 发生敲出事件
//if (_prices[td.UnderlyingCode] >= koBarrier)
{
// 更新观察状态
td.trade_snowball.KnockInOutStatus = ConsTrade.KnockState.KnockedOut;
td.trade_snowball.KnockInOutDate = date.DateTime;
// 更新交易状态
td.TradeStatus = ConsTrade.已平仓;
td.UnWindDate = date.DateTime;
if (snowball.UseOptionPayoffAtKO)
{
double paymentAmount = 0;
var koOptionCashflows = snowball.GetKOPayoff(date, _prices[td.UnderlyingCode]);
if (td.SettlementAmount != null)
{
paymentAmount = td.SettlementAmount ?? 0;
}
else
{
paymentAmount = TradeHelper.GetAmountByPaymentAmount(koOptionCashflows[0].PaymentAmount, td.PrincipalSum(), td.BuySell);
}
result.KO -= paymentAmount;
result.ValueDate = koSettleDate;
break;
//koOptionCashflows[0].PaymentAmount包含了买卖方向的处理了
}
else
{
if (td.SettlementAmount != null)
{
double tradePrice = 0;
var settlementAmount = td.SettlementAmount ?? 0;
//观察日价格页面的结算金额包含了年化期权费,该处逻辑需要先按照扣除年化期权费来算,后面逻辑会补上年化期权费,否则会重复运算
if (td.trade_snowball.AnnualizedPremiumRate.HasValue && td.trade_snowball.AnnualizedPremiumRate != 0)
{
tradePrice = td.StockEqvNotional * td.ParticipationRate * td.trade_snowball.AnnualizedPremiumRate * snowball.CouponDayCount.CalcDayCountFraction(snowball.StartDate, date) ?? 0;
if (tradePrice != 0)
{
settlementAmount -= (td.BuySell == "买入" ? -1 : 1) * tradePrice;
}
}
result.KO -= settlementAmount;
result.ValueDate = date;
break;
}
else
{
var couponPayment = TradeHelper.GetAmountByPaymentAmount(snowball.CouponPayment(date), td.PrincipalSum(), td.BuySell);
result.KO -= couponPayment;
result.ValueDate = date;
break;
}
}
}
#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 < date.DateTime)
&& snowball.KIObsDates.Select(x => x.DateTime).Contains(date.DateTime)
&& td.trade_snowball.KIPayoffType != KIPayoffTypeEnum.None)
{
var kiBarrier =
td.IsMoneynessOptionData ?
td.trade_snowball.KIBarrier * td.SpotPrice :
td.trade_snowball.KIBarrier;
// 发生敲入事件
if (_prices[td.UnderlyingCode] <= kiBarrier)
{
// 更新观察状态
td.trade_snowball.KnockInOutStatus = ConsTrade.KnockState.KnockedIn;
td.trade_snowball.KnockInOutDate = date.DateTime;
}
}
#endregion
#region 到期检查
if (date.DateTime == snowball.ExerciseDates.Last().DateTime)
{
if (snowball.UseOptionPayoffAtMaturity &&
(td.trade_snowball.KnockInOutStatus == ConsTrade.KnockState.KnockedIn || td.trade_snowball.KIBarrier <= 0))
{
td.TradeStatus = ConsTrade.已执行;
td.UnWindDate = date.DateTime;
double paymentAmount = 0;
//已敲入,到期时计算期权收益
var optionPayoffPayment = snowball.GetPayoff(new double[] { _prices[td.UnderlyingCode] });
if (td.SettlementAmount != null)
{
paymentAmount = td.SettlementAmount ?? 0;
}
else
{
paymentAmount = TradeHelper.GetAmountByPaymentAmount(optionPayoffPayment[0].PaymentAmount, td.PrincipalSum(), td.BuySell);
}
//optionPayoffPayment[0].PaymentAmount包含了买卖方向的处理了
result.Execute -= paymentAmount;
result.ValueDate = date;
break;
}
else if (td.trade_snowball.KnockInOutStatus != ConsTrade.KnockState.KnockedOut)
{
td.TradeStatus = ConsTrade.已到期;
td.UnWindDate = date.DateTime;
var maturityCouponRate = snowball.Coupon * snowball.InitialSpotPrice;
var maturityCouponPayment =
snowball.FixedCoupon ?
maturityCouponRate * snowball.Notional :
maturityCouponRate * snowball.Notional * snowball.CouponDayCount.CalcDayCountFraction(snowball.StartDate, snowball.ExerciseDates.Last());
maturityCouponPayment = TradeHelper.GetAmountByPaymentAmount(maturityCouponPayment, td.PrincipalSum(), td.BuySell);
double tradePrice = 0;
if (td.trade_snowball.AnnualizedPremiumRate.HasValue && td.trade_snowball.AnnualizedPremiumRate != 0)
{
tradePrice = td.StockEqvNotional * td.ParticipationRate * td.trade_snowball.AnnualizedPremiumRate * snowball.CouponDayCount.CalcDayCountFraction(snowball.StartDate, date) ?? 0;
}
tradeCash = new trade_cash();
if (td.SettlementAmount != null)
{
//观察日价格页面的结算金额包含了年化期权费,该处逻辑需要先按照扣除年化期权费来算,后面逻辑会补上年化期权费,否则会重复运算
var settlementAmount = td.SettlementAmount ?? 0;
if (tradePrice != 0)
{
settlementAmount -= (td.BuySell == "买入" ? -1 : 1) * tradePrice;
}
result.Execute -= settlementAmount;
result.ValueDate = date;
}
else
{
result.Execute -= maturityCouponPayment;
result.ValueDate = date;
}
if ((td.SettlementDate ?? td.ExerciseDate.GetValueOrDefault()) > endDate)
{
result = null;
}
}
}
#endregion
}
}
break;
//case "气囊结构":
// //气囊结构没有计算赔付;
// airbagService = airbagService ?? new TradeAirbagService(UserInfo);
// airbagService.CheckAirbagKnockInStatus(td, td.trade_airbag, startDate, _prices[td.UnderlyingCode]);
// break;
case "区间累积期权":
{
if (td.ExerciseDate > endDate)
{
result = null;
break;
}
rangeAccrualService = rangeAccrualService ?? new TradeRangeAccrualService(UserInfo);
var observDates = QdpHelper.ParseObservationDate(td.trade_rangeaccrual.ObservationDates)?.ToArray();
if (observDates == null)
{
observDates = CalendarImpl.Get("chn").BizDaysBetweenDatesInclEndDay(
new Date(td.TradeDate.Value), new Date(td.ExerciseDate.Value)).Where(O => O.DateTime != td.TradeDate).ToArray();
}
observDates = observDates.Where(O => O.DateTime >= startDate).ToArray();
var happenedObservations = new List();
if (observDates != null)
{
foreach (var date in observDates)
{
var upperRange = td.IsMoneynessOptionData ? td.trade_rangeaccrual.UpperRange * td.SpotPrice.Value : td.trade_rangeaccrual.UpperRange;
var lowerRange = td.IsMoneynessOptionData ? td.trade_rangeaccrual.LowerRange * td.SpotPrice.Value : td.trade_rangeaccrual.LowerRange;
//有区间收益
if (_prices[td.UnderlyingCode] < upperRange && _prices[td.UnderlyingCode] > lowerRange)
{
var couponCash = td.trade_rangeaccrual.BonusRate * td.Notional * (td.SpotPrice ?? 0) / observDates.Length * (td.BuySell == "卖出" ? -1 : 1);
happenedObservations.Add(rangeAccrualService.SaveObservation(td, td.trade_rangeaccrual, date, couponCash, td.Notional, false));
}
}
}
//到期日生成票息资金记录
td.TradeStatus = ConsTrade.已到期;
happenedObservations.AddRange(DbContext.autocall_observation.Where(o => o.TradeId == td.id).ToList());
//happenedObservations?.ForEach(o =>
//{
// var paymentAmount = TradeHelper.GetAmountByPaymentAmount(o.PaymentAmount, td.PrincipalSum(), td.BuySell);
// result.Execute -= paymentAmount;
//});
result.Execute -= happenedObservations.Sum(n => n.PaymentAmount) + td.PrincipalSum();
result.ValueDate = td.ExerciseDate.Value;
if ((td.SettlementDate ?? td.ExerciseDate.GetValueOrDefault()) > endDate)
{
result = null;
}
}
break;
case "双鲨期权":
{
var observDates = QdpHelper.ParseObservationDate(td.trade_double_sharkfin_option.ObservationDates)?.ToArray();
if (observDates == null)
{
observDates = CalendarImpl.Get("chn").BizDaysBetweenDatesInclEndDay(
new Date(td.TradeDate), new Date(td.ExerciseDate.Value)).Where(O => O.DateTime != td.TradeDate).ToArray();
}
var lastDate = observDates.Where(O => O >= new Date(startDate) && O <= new Date(endDate)).OrderBy(O => (O)).FirstOrDefault();
if (lastDate != default)
{
doubleSharkService = doubleSharkService ?? new DoubleSharkOptionKnockoutService(UserInfo);
var barrierHigh = td.IsMoneynessOptionData ? td.trade_double_sharkfin_option.BarrierHigh * td.SpotPrice : td.trade_double_sharkfin_option.BarrierHigh;
var barrierLow = td.IsMoneynessOptionData ? td.trade_double_sharkfin_option.BarrierLow * td.SpotPrice : td.trade_double_sharkfin_option.BarrierLow;
var useRebate = _prices[td.UnderlyingCode] <= barrierLow;
var price = _prices[td.UnderlyingCode];
td.trade_double_sharkfin_option.KnockInOutStatus = ConsTrade.KnockState.KnockedOut;
td.trade_double_sharkfin_option.KnockInOutDate = startDate;
td.TradeStatus = ConsTrade.已平仓;
td.UnWindDate = startDate;
r = doubleSharkService.SaveDoubleSharkFinRebateCash(td, td.trade_double_sharkfin_option, price, startDate, useRebate, false);
result.KO = -r?.Amount;
if (td.trade_double_sharkfin_option.RebateType == "AtHit")
{
result.ValueDate = lastDate;
}
else if (td.trade_double_sharkfin_option.RebateType == "AtEnd" && td.ExerciseDate <= endDate)
{
result.ValueDate = td.ExerciseDate.Value;
}
else
{
result = null;
}
}
else if (td.ExerciseDate <= endDate)
{
td.TradeStatus = ConsTrade.已到期;
td.UnWindDate = td.ExerciseDate;
r = new trade_cash();
SettlementCalcCommons.SetPossibleExec(r, td, _prices[td.UnderlyingCode]);
result.Execute = -r?.Amount;
result.ValueDate = td.ExerciseDate.Value;
if ((td.SettlementDate ?? td.ExerciseDate.GetValueOrDefault()) > endDate)
{
result = null;
}
}
else
{
result = null;
}
}
break;
case "二元期权":
{
if (td.ExerciseMode == "American")
{
r = null;
binaryService = binaryService ?? new BinaryOptionDealService(UserInfo);
var isObservationDate = true;
double upPrice = _prices[td.UnderlyingCode], lowPrice = _prices[td.UnderlyingCode];
var strike = td.IsMoneynessOptionData ? td.Strike * td.SpotPrice : td.Strike;
var UpperBarrier = new Lazy(() =>
td.IsMoneynessOptionData ? td.trade_binary_option.UpperBarrier * td.SpotPrice : td.trade_binary_option.UpperBarrier);
if (isObservationDate)
{
switch (td.trade_binary_option.PayoffType)
{
case "UpOneTouch":
//触碰,买方获得盈利,交易结束
var cash = BinaryOptionDealService.GetCashOrNothingAmount(td, td.trade_binary_option, startDate, useHighAmount: false);
r = binaryService.SaveBinarySettleCash(td, td.trade_binary_option, startDate, cash, true, upPrice, false);
td.TradeStatus = ConsTrade.已执行;
td.UnWindDate = startDate;
break;
case "DownOneTouch":
//触碰,买方获得盈利,交易结束
cash = BinaryOptionDealService.GetCashOrNothingAmount(td, td.trade_binary_option, startDate, useHighAmount: false);
r = binaryService.SaveBinarySettleCash(td, td.trade_binary_option, startDate, cash, true, lowPrice, false);
td.TradeStatus = ConsTrade.已执行;
td.UnWindDate = startDate;
break;
case "UpNoTouch":
//触碰,买方无盈利,交易结束
r = binaryService.SaveBinarySettleCash(td, td.trade_binary_option, startDate, 0, false, upPrice, false);
td.TradeStatus = ConsTrade.已到期;
td.UnWindDate = startDate;
break;
case "DownNoTouch":
//触碰,买方无盈利,交易结束
r = binaryService.SaveBinarySettleCash(td, td.trade_binary_option, startDate, 0, false, lowPrice, false);
td.TradeStatus = ConsTrade.已到期;
td.UnWindDate = startDate;
break;
case "DoubleOneTouch":
var breachHighBarrier = upPrice >= UpperBarrier.Value;
var price = breachHighBarrier ? upPrice : lowPrice;
cash = BinaryOptionDealService.GetCashOrNothingAmount(td, td.trade_binary_option, startDate, useHighAmount: breachHighBarrier);
//触碰上限或下限,买方获得盈利,交易结束
r = binaryService.SaveBinarySettleCash(td, td.trade_binary_option, startDate, cash, true, price, false);
td.TradeStatus = ConsTrade.已执行;
td.UnWindDate = startDate;
break;
case "DoubleNoTouch":
price = upPrice >= td.trade_binary_option.UpperBarrier ? upPrice : lowPrice;
//触碰上限或下限,买方无盈利,交易结束
r = binaryService.SaveBinarySettleCash(td, td.trade_binary_option, startDate, 0, false, price, false);
td.TradeStatus = ConsTrade.已到期;
td.UnWindDate = startDate;
break;
}
if (td.trade_binary_option.RebateType == "AtHit")
{
result.ValueDate = startDate;
}
else if (td.trade_binary_option.RebateType == "AtEnd" && td.ExerciseDate <= endDate)
{
result.ValueDate = td.ExerciseDate.Value;
}
else
{
result = null;
}
}
//OneTouch类型,到期仍未触碰,则交易结束
if (td.trade_binary_option.PayoffType.Contains("OneTouch") && td.ExerciseDate <= startDate)
{
binaryService.SaveBinarySettleCash(td, td.trade_binary_option, startDate, 0, false, _prices[td.UnderlyingCode], false);
td.TradeStatus = ConsTrade.已到期;
td.UnWindDate = startDate;
}
//NoTouch类型,到期仍未触碰,买方获得盈利,交易结束
if (td.trade_binary_option.PayoffType.Contains("NoTouch") && td.ExerciseDate <= endDate)
{
var cash = BinaryOptionDealService.GetCashOrNothingAmount(td, td.trade_binary_option, startDate, useHighAmount: false);
r = binaryService.SaveBinarySettleCash(td, td.trade_binary_option, startDate, cash, false, _prices[td.UnderlyingCode], false);
td.TradeStatus = ConsTrade.已执行;
td.UnWindDate = endDate;
}
result.KO = -r?.Amount;
}
else if (td.ExerciseDate <= endDate)
{
r = new trade_cash();
SettlementCalcCommons.SetPossibleExec(r, td, _prices[td.UnderlyingCode]);
result.Execute = -r.Amount;
result.ValueDate = td.ExerciseDate.Value;
if ((td.SettlementDate ?? td.ExerciseDate.GetValueOrDefault()) > endDate)
{
result = null;
}
}
else
{
result = null;
}
}
break;
case "障碍期权":
{
r = null;
barrierService = barrierService ?? new BarrierOptionKnockioService(UserInfo);
var observDates = QdpHelper.ParseObservationDate(td.trade_barrier_option.ObservationDates)?.ToArray();
if (observDates == null)
{
observDates = CalendarImpl.Get("chn").BizDaysBetweenDatesInclEndDay(
new Date(td.TradeDate), new Date(td.ExerciseDate.Value)).Where(O => O.DateTime != td.TradeDate).ToArray();
}
var lastDate = observDates.Where(O => O >= new Date(startDate) && O <= new Date(endDate)).OrderBy(O => (O)).FirstOrDefault();
if (lastDate != default)
{
switch (td.trade_barrier_option.Discrete)
{
case "离散":
switch (td.trade_barrier_option.BarrierType)
{
case "上升敲出":
td.trade_barrier_option.KnockInOutStatus = ConsTrade.KnockState.KnockedOut;
td.trade_barrier_option.KnockInOutDate = lastDate;
td.trade_barrier_option.KnockInOutNotional = td.Notional;
td.TradeStatus = ConsTrade.已平仓;
td.UnWindDate = lastDate;
r = barrierService.SetTradeCash(td, td.trade_barrier_option, lastDate, _prices[td.UnderlyingCode], td.trade_barrier_option.BarrierPrice, false);
break;
case "下降敲出":
td.trade_barrier_option.KnockInOutStatus = ConsTrade.KnockState.KnockedOut;
td.trade_barrier_option.KnockInOutDate = lastDate;
td.trade_barrier_option.KnockInOutNotional = td.Notional;
td.TradeStatus = ConsTrade.已平仓;
td.UnWindDate = lastDate;
r = barrierService.SetTradeCash(td, td.trade_barrier_option, lastDate, _prices[td.UnderlyingCode], td.trade_barrier_option.BarrierPrice, false);
break;
case "双障碍敲出":
td.trade_barrier_option.KnockInOutStatus = ConsTrade.KnockState.KnockedOut;
td.trade_barrier_option.KnockInOutDate = lastDate;
td.trade_barrier_option.KnockInOutNotional = td.Notional;
td.TradeStatus = ConsTrade.已平仓;
td.UnWindDate = lastDate;
r = barrierService.SetTradeCash(td, td.trade_barrier_option, lastDate, _prices[td.UnderlyingCode], td.trade_barrier_option.UpperBarrierPrice, false);
break;
}
break;
case "连续":
switch (td.trade_barrier_option.BarrierType)
{
case "上升敲出":
td.trade_barrier_option.KnockInOutStatus = ConsTrade.KnockState.KnockedOut;
td.trade_barrier_option.KnockInOutDate = lastDate;
td.trade_barrier_option.KnockInOutNotional = td.Notional;
td.TradeStatus = ConsTrade.已平仓;
td.UnWindDate = lastDate;
r = barrierService.SetTradeCash(td, td.trade_barrier_option, lastDate, _prices[td.UnderlyingCode], td.trade_barrier_option.BarrierPrice, false);
break;
case "下降敲出":
td.trade_barrier_option.KnockInOutStatus = ConsTrade.KnockState.KnockedOut;
td.trade_barrier_option.KnockInOutDate = lastDate;
td.trade_barrier_option.KnockInOutNotional = td.Notional;
td.TradeStatus = ConsTrade.已平仓;
td.UnWindDate = lastDate;
r = barrierService.SetTradeCash(td, td.trade_barrier_option, lastDate, _prices[td.UnderlyingCode], td.trade_barrier_option.BarrierPrice, false);
break;
case "双障碍敲出":
td.trade_barrier_option.KnockInOutStatus = ConsTrade.KnockState.KnockedOut;
td.trade_barrier_option.KnockInOutDate = lastDate;
td.trade_barrier_option.KnockInOutNotional = td.Notional;
td.TradeStatus = ConsTrade.已平仓;
td.UnWindDate = lastDate;
r = barrierService.SetTradeCash(td, td.trade_barrier_option, lastDate, _prices[td.UnderlyingCode], td.trade_barrier_option.UpperBarrierPrice, false);
break;
}
break;
}
result.KO = -r?.Amount;
if (td.trade_barrier_option.RebateType == "AtHit")
{
result.ValueDate = lastDate;
}
else if (td.trade_barrier_option.RebateType == "AtEnd" && td.ExerciseDate <= endDate)
{
result.ValueDate = td.ExerciseDate.Value;
}
else
{
result = null;
}
}
else if (td.ExerciseDate <= endDate)
{
td.TradeStatus = ConsTrade.已到期;
td.UnWindDate = td.ExerciseDate;
r = new trade_cash();
SettlementCalcCommons.SetPossibleExec(r, td, _prices[td.UnderlyingCode]);
result.Execute = -r.Amount;
result.ValueDate = td.ExerciseDate.Value;
if ((td.SettlementDate ?? td.ExerciseDate.GetValueOrDefault()) > endDate)
{
result = null;
}
}
else
{
result = null;
}
}
break;
case "远期":
case "掉期":
{
if (td.ExerciseDate > endDate)
{
result = null;
break;
}
var variety = DataCacheProvider.GetVariety(td.UnderlyingCode);
result.Execute = ((td.Strike - _prices[td.UnderlyingCode]) * td.Notional * variety.CountRatio) ?? 0;
if ((td.BuySell == "卖出" && td.OptionType == "看涨")
|| (td.BuySell == "买入" && td.OptionType == "看跌"))
{
result.Execute *= -1;
}
result.ValueDate = td.ExerciseDate.Value;
result.TradeType = "远期";
if ((td.SettlementDate ?? td.ExerciseDate.GetValueOrDefault()) > endDate)
{
result = null;
}
}
break;
case "累计期权":
{
var payment = 0d;
var cashAtEnd = td.trade_accumulator_option.SettlementMode == "现金期末";
_prices.TryGetValue(td.UnderlyingCode, out var price);
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
var notional = td.trade_accumulator_option.AccumuTradeAmount * underlying.CountRatio;
if (cashAtEnd || td.trade_accumulator_option.SettlementMode == "实物交割")
{
td.trade_accumulator_option.SettlementMode = "现金当日";
}
result.ValueDate = startDate;
for (var dt = startDate; dt <= endDate; dt = dt.AddDays(1))
{
var checkResult = TradeModule.AccumulatorOptionModule.TradeAccumulatorService.CheckAccumulatorPayoff(td, td.trade_accumulator_option, dt, price, notional);
if (checkResult == null) continue;
if (checkResult.SettlementMode == "票息" || checkResult.SettlementMode == "现金当日")
{
payment += checkResult.PaymentAmount;
}
else if (checkResult.SettlementMode == "敲出")
{
if (td.trade_accumulator_option.EarlyTerminate)
{
result.ValueDate = dt;
result.KO = cashAtEnd || payment >= 0 ? 0 : -payment;
break;
}
}
if (dt >= td.ExerciseDate.Value)
{
result.ValueDate = dt;
result.Execute = payment >= 0 ? 0 : -payment;
break;
}
}
}
break;
default:
result = null;
break;
}
if (result != null && result.TotleCash != 0)
{
if (td.PremiumPayDate.GetValueOrDefault() > td.TradeDate && td.PremiumPayDate.GetValueOrDefault() >= startDate && td.PremiumPayDate.GetValueOrDefault() <= endDate)
{
var tradeprice = td.TradePrice * (td.BuySell == "卖出" ? -1 : 1);
if (result.KO != 0)
{
result.KO += tradeprice;
}
if (result.Execute != 0)
{
result.Execute += tradeprice;
}
}
}
if (result == null)
{
//避免结构化交易装填判断错误;
td.TradeStatus = "确认成交";
}
return result;
}
}
///
/// 流动性风险
///
public class FlowRiskModel
{
public int ParentLevel { get; set; }
public string EncryptId { get; set; }
public string TradeType { get; set; }
///
/// 日期
///
public DateTime? ValueDate { get; set; }
///
/// 准备金
///
public double TotleCash { get { return (KO ?? 0) + (Execute ?? 0); } }
///
/// 交易编号
///
public string TradeNumber { get; set; }
///
/// 敲出
///
public double? KO { get; set; }
///
/// 到期
///
public double? Execute { get; set; }
public FlowRiskModel()
{
this.KO = 0;
this.Execute = 0;
}
}
}