Files
zszq-trs/YLErpDAL/Modules/EodModule/SettlementModule/V2/EodPositionSettleServiceTemp.cs
T
2024-05-09 14:06:26 +08:00

108 lines
4.0 KiB
C#

using YLErp.DBModels.Consts;
using YLErp.Modules.CalculationModule;
using YLErp.QdpModule;
namespace YLErp.Modules.EodModule.SettlementModule.V2
{
/// <summary>
/// 临时存放
/// </summary>
class EodPositionSettleServiceTemp<TRisk, TPosition, TPnl> : EodSettleServiceBaseV2
where TPnl : EodPnl, new()
where TRisk : EodTradeRisk, new()
where TPosition : EodTradePosition, new()
{
public EodPositionSettleServiceTemp(EodSettlementContextV2 context) : base(context)
{
}
#region----盈亏分解V1----
//判断是否可以进行盈亏分解计算
private bool CanCalcPnlExplain(OtcTradeBase td)
{
switch (td.TradeType)
{
case "远期":
case "收益互换":
case "自定义交易":
return false;
default:
return true;
}
}
private void CalcPnlExplainV1(trade td, TPnl pnl1, TRisk risk1, double spotPrice1, double riskFreeRate1)
{
if (!CanCalcPnlExplain(td))
{
return;
}
var preRisk = DbContext.Set<TRisk>().Where(n => n.ValueDate < _context.SettleDate && n.TradeId == td.id)
.OrderByDescending(n => n.ValueDate).Select(n => new { n.ValueDate, n.Vol, n.Pv }).FirstOrDefault();
if (preRisk == null)
{
return;
}
DateTime date0;
double spotPrice0, vol0, riskFreeRate0, PV0, vol1 = risk1.Vol;
var hisData = DbContext.TradeHisData.Where(n => n.TradeId == td.id && n.ValueDate < _context.SettleDate && n.ValueType == ConsTradeField.NoRiskRate)
.OrderByDescending(n => n.ValueDate).Select(n => new { n.Value }).FirstOrDefault();
spotPrice0 = _context.GetPreEodPriceProvider().GetPrice(td.UnderlyingCode, td.SettlementType);
PV0 = preRisk.Pv;
vol0 = preRisk.Vol;
date0 = preRisk.ValueDate;
riskFreeRate0 = hisData?.Value ?? td.NoRiskRate ?? riskFreeRate1;
var sdiff = spotPrice1 - spotPrice0;
pnl1.PnLDelta = risk1.Delta * sdiff;
pnl1.PnLGamma = risk1.Gamma * sdiff * sdiff / 2;
pnl1.PnLVega = risk1.Vega * (risk1.Vol - vol0) * 100;
pnl1.PnLTheta = risk1.Theta * (_context.SettleDate - _context.PreSettleDate).TotalDays;
pnl1.PnLRho = risk1.Rho * (riskFreeRate1 - riskFreeRate0);
//交易在上一交易日使用当前交易日的标的价格计算出的Pv
var PV0s1 = CalcPnlExplainV1(td, date0, spotPrice1, vol0, riskFreeRate0);
//交易在上一交易日使用当前交易日的波动率计算出的Pv
var PV0v1 = CalcPnlExplainV1(td, date0, spotPrice0, vol1, riskFreeRate0);
//交易在上一交易日使用当前交易日的标的价格和波动率计算出的Pv
var PV0s1v1 = CalcPnlExplainV1(td, date0, spotPrice1, vol1, riskFreeRate0);
pnl1.PnLPrice = PV0s1 - PV0;
pnl1.PnLVol = PV0v1 - PV0;
pnl1.PnLPriceVolCross = PV0s1v1 - PV0 - pnl1.PnLPrice - pnl1.PnLVol;
}
private static double CalcPnlExplainV1(trade td, DateTime valueDate, double spotPrice, double vol, double riskFreeRate)
{
var req = new OptionValueCalcRequest(riskFreeRate)
{
correlations = null,//不计算彩虹等多标的期权暂时不需要
engineName = null,
preciseTimeMode = false, //日终一定是false
isEodCalc = true,
pricingRequest = QdpPricingRequest.PV_ONLY,
spotPrices = new[] { spotPrice },
vols = new[] { vol }
};
var result = OptionCalculatorV2.GetOptionValueResult(valueDate, td, req, out _);
return NumberHelper.Normalize(result.Pv);
}
#endregion
}
}