Files
zszq-trs/YLErpDAL/Modules/CalculationModule/OptionValueCalcContext.cs
T
2024-05-09 14:06:26 +08:00

455 lines
17 KiB
C#

using Qdp.Pricing.Base.Implementations;
using Qdp.Pricing.Library.Equity.Engines.Analytical;
using YLErp.Abstract;
using YLErp.Commons;
using YLErp.Enums;
using YLErp.Modules.CalculationModule.Abstract;
using YLErp.Modules.VolatilityModule;
using YLErp.QdpModule;
namespace YLErp.Modules.CalculationModule
{
/// <summary>
/// 期权估值计算上下文
/// </summary>
public class OptionValueCalcContext : IOtcTradeValueCalcContext
{
/// <summary>
///
/// </summary>
protected OptionValueCalcContext(DateTime valueDate, IOtcTradeValueCalcContext baseContext)
{
if (baseContext == null)
{
throw new ArgumentNullException(nameof(baseContext));
}
ValueDate = valueDate;
VolType = baseContext.VolType;
IsEodCalc = baseContext.IsEodCalc;
DataProvider = baseContext.DataProvider;
AddingVolRate = baseContext.AddingVolRate;
ErrorHandler = baseContext.ErrorHandler;
SysRiskFreeRate = baseContext.SysRiskFreeRate;
CalcScenario = baseContext.CalcScenario;
UserGroup = baseContext.UserGroup;
CalcDeltaT1 = baseContext.CalcDeltaT1;
MarketProxy = new MarketProxy(valueDate, SysRiskFreeRate)
{
Trace = baseContext.Trace
};
}
/// <summary>
///
/// </summary>
public OptionValueCalcContext(string volType, bool isEodCalc, DateTime valueDate, double sysRiskFreeRate, IOptionCalcDataProvider dataProvider)
{
DataProvider = CalcCheckHelper.CheckOptionCalcDataProvider(dataProvider);
VolType = volType;
IsEodCalc = isEodCalc;
ValueDate = valueDate;
SysRiskFreeRate = sysRiskFreeRate;
MarketProxy = new MarketProxy(valueDate, sysRiskFreeRate);
}
#region----属性定义----
/// <summary>
/// 计算场景枚举
/// </summary>
public CalcScenarioEnum CalcScenario { get; set; }
/// <summary>
/// 波动率类型(默认:'对冲')
/// </summary>
public string VolType { get; } = "对冲";
public bool IsEodCalc { get; }
/// <summary>
/// 波动率用户组
/// </summary>
public string UserGroup { get; set; }
/// <summary>
/// 是否精确时间模式
/// </summary>
public virtual bool IsPreciseTimeMode => CalcScenario != CalcScenarioEnum.EodSettlement;
/// <summary>
/// 波动率加点值
/// </summary>
public double AddingVolRate { get; set; }
/// <summary>
/// 是否计算T+1日Delta
/// </summary>
public bool CalcDeltaT1 { get; set; }
//--------------------------------
/// <summary>
/// 估值日
/// </summary>
public DateTime ValueDate { get; }
/// <summary>
///
/// </summary>
public MarketProxy MarketProxy { get; }
/// <summary>
/// 期权计算数据提供接口
/// </summary>
public IOptionCalcDataProvider DataProvider { get; protected set; }
/// <summary>
/// 错误处理接口
/// </summary>
public IErrorHandler ErrorHandler { get; set; }
/// <summary>
/// 系统全局无风险利率
/// </summary>
public double SysRiskFreeRate { get; }
/// <summary>
/// 用于计算跟踪
/// </summary>
public TraceWrap Trace { get => MarketProxy.Trace; set => MarketProxy.Trace = value; }
public string SkipTradeTypes { get; set; }
#endregion
#region----方法定义----
/// <summary>
/// 获取期权计算模式
/// </summary>
public virtual PricingRequest GetPricingRequest(OtcTradeBase trade)
{
if (trade is null)
{
throw new ArgumentNullException(nameof(trade));
}
if (!string.IsNullOrEmpty(SkipTradeTypes) && SkipTradeTypes.Contains(trade.TradeType))
{
return PricingRequest.None;
}
if (CalcScenario == CalcScenarioEnum.RealtimeRisk
&& !PS.Config.ErpElement.CalcAutocallGreeksInRisk
&& (trade.TradeType == "凤凰期权" || trade.TradeType == "雪球期权"))
{
return QdpPricingRequest.BASIC_PRICING;
}
var pr = QdpPricingRequest.BASIC_GREEKS | PricingRequest.TimeValue;
if (trade.TradeType == "亚式期权")
{
pr |= PricingRequest.SA_Delta;
}
//20220118:上期做了定制处理,可以返回DDeltaDt指标值
return PS.Config.Company != Configuration.CompanyEnum.上期资本 ? pr : pr | PricingRequest.DDeltaDt;
}
/// <summary>
///
/// </summary>
public double GetCorrelation(int underlyingId1, int underlyingId2)
{
var correlation = DataProvider.UnderlyingDataProvider.GetCorrelation(underlyingId1, underlyingId2);
return correlation == null || correlation.Correlation == null ? 0.0 : correlation.Correlation.Value;
}
/// <summary>
/// 根据交易品种ID获取此交易品种是否存在夜盘
/// </summary>
public bool HasNightMarket(int varietyId)
{
var variety = DataProvider.UnderlyingDataProvider.GetVariety(varietyId);
if (variety != null)
{
return variety.HasNightMarket;
}
return false;
}
#region----波动率----
//TODO:PrepareVolatility欠缺多标的交易的波动率处理
/// <summary>
/// 准备波动率(仅适用于场外期权和场内期权交易)
/// </summary>
public bool PrepareVolatility(string qdpTradeId, OtcTradeBase tradeObj, double spotPrice, out string[] volsurfaceNames)
{
volsurfaceNames = new[] { qdpTradeId };
if (tradeObj.TradeType == "场内期权")
{
bool prepareExOptionSavedVol()
{
var vol = DataProvider.VolatilityDataProvider.GetExOptionSavedVol(tradeObj.ExchangeOptionCode, ValueDate);
if (vol != null)
{
var volitality = QdpVolHelper.GenerateFlatSurface(vol.Value);
MarketProxy.SetVolSurface(qdpTradeId, volitality, AddingVolRate);
return true;
}
return false;
}
if (PS.Config.Company == Configuration.CompanyEnum.光大光子)
{
return prepareExOptionSavedVol();
}
if (VolType != "交易曲面") //交易曲面时获取交易Mid波动率
{
if (prepareExOptionSavedVol())
{
return true;
}
if (PS.Config.ErpElement.ExchangeOptionVolType == Configuration.Enums.ExchangeOptionVolType.ImpliedVol)
{
double volValue = tradeObj.Vol ?? 0;
if (!tradeObj.Vol.IsNormalize())
{
if (!tradeObj.TradeSinglePrice.HasValue)
{
throw new ServiceException($"计算场内期权隐含波动率失败,期权代码:{tradeObj.ExchangeOptionCode},错误信息:期权价格未获取到");
}
try
{
volValue = VolatilityHelper.GetImpliedVol(ValueDate, tradeObj, null, spotPrice, IsEodCalc);
}
catch (Exception ex)
{
throw new ServiceException($"计算场内期权隐含波动率失败,期权代码:{tradeObj.ExchangeOptionCode},期权价格:{tradeObj.TradeSinglePrice:0.####},错误信息:{ex.Message}");
}
}
MarketProxy.SetVolSurface(qdpTradeId, volValue);
return true;
}
}
}
else //场外期权
{
if (VolType == "对冲")
{
var vol = DataProvider.VolatilityDataProvider.GetOtcHedgingVol(tradeObj.id, ValueDate) ?? tradeObj.TradeSavedVol;
if (vol != null)
{
var volitality = QdpVolHelper.GenerateFlatSurface(vol.Value);
if (volitality == null)
{
return false;
}
MarketProxy.SetVolSurface(qdpTradeId, volitality, AddingVolRate);
return true;
}
}
//只有在tradeVol模式下才应从开平仓波动率中插值,否则应去曲面上插值
if (VolType == "持仓" && PS.Config.IsTradeVol)
{
//场外期权交易使用tradingVol
var volitality = GetTradingVolatility(tradeObj, false);
if (volitality == null)
{
return false;
}
MarketProxy.SetVolSurface(qdpTradeId, volitality, AddingVolRate);
return true;
}
}
//设置标的波动率
var volitalityU = GetUnderlyingVolatility(tradeObj, VolType, tradeObj.UnderlyingCode, spotPrice);
if (volitalityU == null)
{
return false;
}
MarketProxy.SetVolSurface(qdpTradeId, volitalityU, AddingVolRate);
return true;
}
//获取交易波动率(如果是结算,先查找结算波动率)
private IVolatility GetTradingVolatility(OtcTradeBase tradeObj, bool isEod)
{
double? vol = null;
if (isEod)
{
vol = DataProvider.VolatilityDataProvider.GetOtcEodOverrideVol(tradeObj.id, ValueDate);
}
if (vol == null)
{
var tradeVol = DataProvider.VolatilityDataProvider.GetOtcPositionVol(tradeObj.id, ValueDate);
var daycountMode = PS.Config.ErpElement.SmoothingDaycountMode == Configuration.Enums.SmoothingDaycountMode.CalendarDay
? Qdp.Pricing.Base.Enums.DayCountMode.CalendarDay
: Qdp.Pricing.Base.Enums.DayCountMode.TradingDay;
if (tradeVol == null)
{
vol = AnalyticalOptionTradeVolInterp.tradeVolLinearInterp(
new Qdp.Foundation.Implementations.Date(ValueDate),
tradeObj.TradeOpenVolatility ?? 0,
tradeObj.TradeCloseVolatility ?? 0,
new Qdp.Foundation.Implementations.Date(tradeObj.StartDate.Value),
new Qdp.Foundation.Implementations.Date(tradeObj.ExerciseDate.Value),
tradeObj.NumOfSmoothingDays ?? 0,
daycountMode,
CalendarImpl.Get("chn"));
}
else
{
//新增交易当天的持仓波动率需要划掉一天,修改后的持仓波动率不需要再划一天
vol = AnalyticalOptionTradeVolInterp.tradeVolLinearInterp(
new Qdp.Foundation.Implementations.Date(ValueDate),
tradeVol.OpenVol,
tradeVol.CloseVol,
new Qdp.Foundation.Implementations.Date(tradeVol.ValueDate),
new Qdp.Foundation.Implementations.Date(tradeObj.ExerciseDate.Value),
tradeVol.SmoothingDays,
daycountMode,
CalendarImpl.Get("chn"), tradeVol.IsFirst);
}
}
return QdpVolHelper.GenerateFlatSurface(OtcFormatHelper.FormatValue(vol.Value, PS.Config.ErpElement.VolMoreAccurate ? 6 : 4));
}
/// <summary>
/// 获取vol 没有则按照默认值新增
/// </summary>
private IVolatility GetUnderlyingVolatility(OtcTradeBase tradeObj, string voltype, string underlyingCode, double spotPrice, string volmode = "MoneynessVol")
{
voltype = VolatilityHelper.GetUnderlyingVolType(voltype);
var vol = DataProvider.VolatilityDataProvider.GetUnderlyingVol(PS.Config.Is润和 && !IsEodCalc ? DateTime.Today : ValueDate, voltype, underlyingCode, UserGroup);
if (vol != null)
{
var constVol = VolatilityHelper.GetInterpolatedVol(
volConstructionType: PS.Config.ErpElement.SkewMapVolConstruction ? VolConstructionType.SkewMap : VolConstructionType.Normal,
volSurface: vol,
valueDate: PS.Config.Is润和 && !IsEodCalc ? DateTime.Today : ValueDate,
underlyingCode: underlyingCode,
exerciseDate: tradeObj.ExerciseDate.Value,
strike: tradeObj.Strike ?? 0,
isBuy: tradeObj.BuySell == "买入",
isCall: ConsGlobal.CallPut.IsCall(tradeObj.CallPut),
spotPrice: spotPrice,
isMoneynessOption: tradeObj.IsMoneynessOption == "是",
isEodCalc: IsEodCalc);
return QdpVolHelper.GenerateFlatSurface(constVol);
}
var defVol = VolatilityHelper.GetDefaultVol(new SingleVolatilityRequest
{
QuotationDate = ValueDate,
UnderlyingCode = underlyingCode,
VolType = voltype,
TradeVolWithBidAsk = false,
UserGroup = UserGroup
});
defVol.VolSurfaceMode = volmode;
return defVol;
}
/// <summary>
/// 获取交易的无风险利率
/// </summary>
public virtual double GetRiskFreeRate(OtcTradeBase trade)
{
return trade.NoRiskRate ?? SysRiskFreeRate;
}
/// <summary>
/// 获取交易的分红率
/// </summary>
public virtual double GetDividendRate(OtcTradeBase trade)
{
if (trade.TradeType == "场内期权" && !string.IsNullOrWhiteSpace(trade.ExchangeOptionCode))
{
var exOption = DataProvider.UnderlyingDataProvider.GetExchange_List_Option(trade.ExchangeOptionCode);
var underlying = DataProvider.UnderlyingDataProvider.GetUnderlying(exOption?.UnderlyingCode);
return underlying?.DividendRate ?? SysRiskFreeRate;
}
return trade.DividendRate ?? GetRiskFreeRate(trade);
}
#endregion
#endregion
bool _disposed;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
MarketProxy.Dispose();
}
_disposed = true;
}
public virtual string GetFixingString(OtcTradeBase trade, trade_asian_option asianOption, double spotPrice)
{
var fixing = AsianOptionFixingService.GetFixingString(ValueDate, trade, asianOption);
if (CalcScenario == CalcScenarioEnum.RealtimeRisk && IsPreciseTimeMode)
{
//修复实时计算中fixing最后一天的价格不是实时价格
fixing = FixingService.AddOrReplaceLastDateSpotPrice(fixing, ValueDate, spotPrice);
}
if (PS.Config.Is润和 && DateTime.Now.Hour < 15)
{
var index = fixing.IndexOf(ValueDate.ToString("yyyy-MM-dd"));
if (index >= 0)
{
fixing = fixing.Remove(index).TrimEnd(';');
}
}
return fixing;
}
public override string ToString()
{
return $"{ValueDate:yyyy-MM-dd}--{VolType}";
}
}
}