Files
zszq-trs/YLErpDAL/BLL/EodSettlement/SettlementCalcCommons.cs
T
2024-05-09 14:06:26 +08:00

275 lines
13 KiB
C#

using Qdp.ComputeServiceV2.Data.CommonModels.TradeInfos;
using Qdp.Pricing.Base.Implementations;
using Qdp.Pricing.Library.Common.Interfaces;
using Qdp.Pricing.Library.Options.Products.Asian;
using Qdp.Pricing.Library.Options.Products.Barrier;
using Qdp.Pricing.Library.Options.Products.Binary;
using YLErp.Commons;
using YLErp.DBModels.Helpers;
using YLErp.Modules;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.TradeModule.ExoticOptionModule;
namespace YLErp.BLL.EodSettlement
{
/// <summary>
/// 结算通用类
/// </summary>
public class SettlementCalcCommons
{
/// <summary>
/// 计算行权收益
/// </summary>
public static void SetPossibleExec(trade_cash tc, trade trade, double price, bool isRefreshFinalPrice = false
, DateTime? finalPriceSettleDate = null, double? strike = null)
{
string fixings = null;
tradeBLL.SetFieldsByTradeType(trade);
//var isBinaryOption = trade.TradeType == "二元期权";
var isAsianOption = trade.TradeType == "亚式期权";
if (isAsianOption && trade.trade_asian_option == null)
{
throw new ServiceException("缺少亚式期权交易信息");
}
//亚式期权浮动行权价有行权价传入的情况处理
if (isAsianOption)
{
var startDate = trade.trade_asian_option.AveragingPeriodStartDate ?? trade.TradeDate.Value;
var settleDate = finalPriceSettleDate ?? valuedateBLL.ValueDate;
//亚式浮动行权价并且行权价有输入值的情况下
if (strike.HasValue && trade.trade_asian_option.StrikeType == "Floating")
{
//均价起算日大于结算日的情况下取计值日
if (startDate > settleDate)
{
startDate = settleDate;
}
fixings = $"{startDate:yyyy-MM-dd},{strike}";
}
else
{
//均价起算日大于结算日的情况下取不到fixing则直接赋值
if (startDate > settleDate)
{
fixings = $"{settleDate:yyyy-MM-dd},{price}";
}
else
{
fixings = AsianOptionFixingService.GetFixingString(settleDate, trade);
if (string.IsNullOrEmpty(fixings))
{
//取不到fixing则直接赋值
fixings = $"{settleDate:yyyy-MM-dd},{price}";
}
}
}
}
if (trade.TradeType == "Risky期权")
{
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode);
if (underlying == null)
{
throw new Exception($"找不到标的资产{trade.UnderlyingCode}的信息");
}
var QdpTrades = GetToQdpOptionRisk(trade, underlying, finalPriceSettleDate, fixings);
tc.IsPossibleExec = true;
tc.UnwindPrice = tc.UnwindPrice ?? 0;
foreach (var item in QdpTrades)
{
if (item != null && item.Instrument != null && item.Instrument is IOption optitem)
{
Cashflow[] cashFlows;
cashFlows = optitem.GetPayoff(new double[] { price });
if (!(cashFlows != null && (cashFlows[0].PaymentAmount == 0 || double.IsNaN(cashFlows[0].PaymentAmount))))
{
//cashFlows[0].PaymentAmount包含了买卖方向的处理了
tc.UnwindPrice += cashFlows[0].PaymentAmount / trade.Notional;
tc.Amount += OtcFormatHelper.FormatValue(cashFlows[0].PaymentAmount, 2);
tc.InitialAmount += OtcFormatHelper.FormatValue(cashFlows[0].PaymentAmount, 2);
}
}
}
//risky保底是一个总的值
var amount = TradeHelper.GetAmountByPaymentAmount(0, trade.PrincipalSum(), trade.BuySell);
tc.Amount += OtcFormatHelper.FormatValue(amount, 2);
tc.InitialAmount += OtcFormatHelper.FormatValue(amount, 2);
}
else if (trade.TradeType == "雪球期权" && trade.trade_snowball.PrepaymentUsed)
{
var obResult = new SpecialSnowballObservationHelper(trade, trade.trade_snowball)
.GetObservationResultForTraderSide(finalPriceSettleDate ?? valuedateBLL.ValueDate, price, trade.Notional);
var amount = TradeHelper.GetAmountByPaymentAmount(obResult.PaymentAmount, trade.PrincipalSum(), trade.BuySell);
tc.IsPossibleExec = true;
tc.UnwindPrice = obResult.PaymentAmount / trade.Notional;
tc.Amount = OtcFormatHelper.FormatValue(amount, 2);
tc.InitialAmount = OtcFormatHelper.FormatValue(amount, 2);
}
else
{
var QdpTrade = TradeCalcHelper.GetQdpTrade(trade, finalPriceSettleDate, fixings);
if (QdpTrade != null && QdpTrade.Instrument != null && QdpTrade.Instrument is IOption opt)
{
if (isAsianOption)
{
var asianOpt = opt as AsianOption;
tc.StrikeType = trade.trade_asian_option.StrikeType;
if (trade.trade_asian_option.StrikeType == "Floating")
{
tc.Strike = asianOpt.ActualStrike;
}
else
{
tc.FinalPrice = asianOpt.FinalPrice();
//isRefreshFinalPrice为false代表非默认标的价格,则根据行权页面的标的价格计算行权收益
if (isRefreshFinalPrice)
{
//分段式亚式期权,行权时的默认标的价格需要通过QDP计算得出,而不是标的现价
//再根据该价格算出行权收益
price = asianOpt.FinalPrice();
if (finalPriceSettleDate != null)
{
price = asianOpt.FinalPrice(finalPriceSettleDate);
}
price = Convert.ToDouble(price.OtcFormatUmPrice());
}
}
}
Cashflow[] cashFlows;
if (QdpTrade.Instrument is BinaryOption)
{
var option = QdpTrade.Instrument as BinaryOption;
var valueDate = finalPriceSettleDate ?? valuedateBLL.ValueDate;
cashFlows = option.GetPayoff(new double[] { price }, valueDate);
}
else if (QdpTrade.Instrument is BarrierOption)
{
var option = QdpTrade.Instrument as BarrierOption;
var valueDate = finalPriceSettleDate ?? valuedateBLL.ValueDate;
cashFlows = option.GetPayoff(new double[] { price }, valueDate);
}
else
{
cashFlows = opt.GetPayoff(new double[] { price });
}
if (cashFlows != null && (cashFlows[0].PaymentAmount == 0 || double.IsNaN(cashFlows[0].PaymentAmount)))
{
var amount = TradeHelper.GetAmountByPaymentAmount(0, trade.PrincipalSum(), trade.BuySell);
tc.IsPossibleExec = true;
tc.UnwindPrice = 0;
tc.Amount = OtcFormatHelper.FormatValue(amount, 2);
tc.InitialAmount = OtcFormatHelper.FormatValue(amount, 2);
}
else
{
//cashFlows[0].PaymentAmount包含了买卖方向的处理了
var paymentAmount = trade.TradeType == "累计期权" ? cashFlows[0].PaymentAmount * trade.Notional / (trade.CountRatio ?? 1) : cashFlows[0].PaymentAmount;
var amount = TradeHelper.GetAmountByPaymentAmount(paymentAmount, trade.PrincipalSum(), trade.BuySell);
tc.IsPossibleExec = true;
tc.UnwindPrice = paymentAmount / trade.Notional;
tc.Amount = OtcFormatHelper.FormatValue(amount, 2);
tc.InitialAmount = OtcFormatHelper.FormatValue(amount, 2);
}
}
}
}
public static List<TradeBase> GetToQdpOptionRisk(trade trade, underlying_manager underlying, DateTime? finalPriceSettleDate, string fixings)
{
var tradeclone = trade.Clone();
tradeclone.TradeAmount = tradeclone.TradeAmount = TradeCalcHelper.GetTradeAmountV(trade, trade.TradeAmount, 1);
tradeclone.Notional = tradeclone.Notional = TradeCalcHelper.GetTradeAmountV(trade, trade.Notional, underlying.CountRatio);
var options = new List<TradeBase>();
var td1 = tradeclone.Clone();
td1.Strike = trade.trade_risky_option.Strike1;
td1.ParticipationRate = trade.trade_risky_option.ParticipationRate1;
td1.TradeAmount = TradeCalcHelper.GetTradeAmount(td1, td1.TradeAmount, 1);
td1.Notional = TradeCalcHelper.GetTradeAmount(td1, td1.Notional, underlying.CountRatio);
td1.OptionType = "看跌";
td1.BuySell = trade.BuySell == "买入" ? "卖出" : "买入";
var option1 = TradeCalcHelper.GetQdpTrade(td1, finalPriceSettleDate, fixings);
if (option1 != null)
{
options.Add(option1);
}
var td2 = tradeclone.Clone();
td2.Strike = trade.trade_risky_option.Strike2;
td2.ParticipationRate = trade.trade_risky_option.ParticipationRate2;
td2.TradeAmount = TradeCalcHelper.GetTradeAmount(td2, td2.TradeAmount, 1);
td2.Notional = TradeCalcHelper.GetTradeAmount(td2, td2.Notional, underlying.CountRatio);
var option2 = TradeCalcHelper.GetQdpTrade(td2, finalPriceSettleDate, fixings);
if (option2 != null)
{
options.Add(option2);
}
var td3 = tradeclone.Clone();
td3.Strike = trade.trade_risky_option.Strike3;
//decimal 为了解决精度问题: 0.2-0.3=0.0999999999
var participationRate3 = (decimal)trade.trade_risky_option.ParticipationRate2 - (decimal)trade.trade_risky_option.ParticipationRate3;
td3.ParticipationRate = (double?)Math.Abs(participationRate3);
td3.TradeAmount = TradeCalcHelper.GetTradeAmount(td3, td3.TradeAmount, 1);
td3.Notional = TradeCalcHelper.GetTradeAmount(td3, td3.Notional, underlying.CountRatio);
if (participationRate3 < 0)
{
td3.BuySell = trade.BuySell == "买入" ? "卖出" : "买入";
}
var option3 = TradeCalcHelper.GetQdpTrade(td3, finalPriceSettleDate, fixings);
if (option3 != null)
{
options.Add(option3);
}
return options;
}
/// <summary>
/// 获取根据当前价格行权的行权价
/// </summary>
public static double GetOTCTradeExerciseProfit(trade trade, double price)
{
//实值pv计算
var ActualPv = 0.0;
tradeBLL.SetFieldsByTradeType(trade);
var QdpTrade = TradeCalcHelper.GetQdpTrade(trade);
if (QdpTrade != null && QdpTrade.Instrument != null)
{
var opt = QdpTrade.Instrument as IOption;
if (opt != null)
{
try
{
var cashFlows = opt.GetPayoff(new double[] { price });
if (cashFlows != null && cashFlows[0].PaymentAmount == 0)
{
return ActualPv;
}
else
{
ActualPv = OtcFormatHelper.FormatValue(cashFlows[0].PaymentAmount, 2);
}
}
catch (Exception)
{
}
}
}
return ActualPv;
}
}
}