using YLErp.DBModels.Consts; using YLErp.Modules.VolatilityModule; using YLErp.QdpModule; namespace YLErp.Modules.EodModule.SettlementModule { /// /// 结算波动率接口(暂未考虑多标的处理) /// public interface IEodVolProvider { double? GetVol(OtcTradeBase td, double spotPrice); } #region----持仓波动率---- /// /// TradeVol模式持仓波动率提供 /// class EodPositionVolProvider_Trade : TradeVolitalityProvider, IEodVolProvider { Dictionary _overridVolDic; public EodPositionVolProvider_Trade(DateTime valueDate) : base(valueDate) { } public double? GetVol(OtcTradeBase td, double spotPrice) { if (td is null) { throw new ArgumentNullException(nameof(td)); } if (td.id < 1) { return null; } if (_overridVolDic == null) { using (var db = DbContextFactory.GetYLDbContext()) { _overridVolDic = db.eod_trade_vol_override.Where(x => x.valuedate == _valueDate) .Select(n => new { n.tradeid, n.vol }).ToDictionary(n => n.tradeid, m => m.vol); } } if (_overridVolDic.TryGetValue(td.id, out var vol)) { return vol; } if (TryGetVol(td.id, td.ExerciseDate.Value, out vol)) { return vol; } return VolatilityHelper.GetTradeVol(_valueDate, td.TradeDate.Value, td.ExerciseDate.Value, td.TradeOpenVolatility ?? 0, td.TradeCloseVolatility ?? 0, td.NumOfSmoothingDays ?? 0); } } #endregion #region----曲面波动率---- /// /// 曲面波动率模式持仓波动率提供 /// class EodUnderlyingVolProvider : UnderlyingVolitalityProvider { protected EodUnderlyingVolProvider(DateTime valueDate, IEnumerable volTypes) : base(valueDate, volTypes) { } protected double? InnerGetVol(OtcTradeBase td, string volType, double spotPrice) { if (td is null) { throw new ArgumentNullException(nameof(td)); } var userGroup = string.Empty; if (ConsUserGroup.HasGroup) { userGroup = DataCacheProvider.GetAssetUnitDataSource().GetData(td.AssetId)?.UserGroup; if (string.IsNullOrEmpty(userGroup)) { throw new Exception($"[结算交易'{td.TradeNumber}'][取{volType}波动率]未能获取用户组!"); } } var unVol = GetVol(volType, userGroup, td.UnderlyingCode); if (unVol == null) { return null; } var constVol = VolatilityHelper.GetInterpolatedVol( volConstructionType: PS.Config.ErpElement.SkewMapVolConstruction ? VolConstructionType.SkewMap : VolConstructionType.Normal, volSurface: unVol, valueDate: _valueDate, underlyingCode: td.UnderlyingCode, exerciseDate: td.ExerciseDate.Value, strike: td.Strike ?? 0, isBuy: td.BuySell == "买入", isCall: td.CallPut == "Call", spotPrice: spotPrice, isMoneynessOption: td.IsMoneynessOption == "是", isEodCalc: true); return constVol; } } /// /// 单个曲面波动率类型 /// class EodUnderlyingSingleVolProvider : EodUnderlyingVolProvider, IEodVolProvider { readonly string _volType; public EodUnderlyingSingleVolProvider(DateTime valueDate, string volType) : base(valueDate, new[] { volType }) { _volType = volType ?? throw new ArgumentNullException(nameof(volType)); } public double? GetVol(OtcTradeBase td, double spotPrice) { return InnerGetVol(td, _volType, spotPrice); } } /// /// 曲面波动率模式持仓波动率提供 /// class EodPositionVolProvider_Underlying : EodUnderlyingVolProvider, IEodVolProvider { readonly string _volType; Dictionary _overridVolDic; public EodPositionVolProvider_Underlying(DateTime valueDate, string volType) : base(valueDate, new[] { volType }) { _volType = volType ?? throw new ArgumentNullException(nameof(volType)); } public double? GetVol(OtcTradeBase td, double spotPrice) { if (_overridVolDic == null) { using (var db = DbContextFactory.GetYLDbContext()) { _overridVolDic = db.eod_trade_vol_override.Where(x => x.valuedate == _valueDate) .Select(n => new { n.tradeid, n.vol }).ToDictionary(n => n.tradeid, m => m.vol); } } if (_overridVolDic.TryGetValue(td.id, out var vol)) { return vol; } return InnerGetVol(td, _volType, spotPrice); } } #endregion #region----对冲波动率---- /// /// 对冲波动率提供 /// class EodHedgeVolProvider : TradeHedgeVolProvider, IEodVolProvider { public EodHedgeVolProvider(DateTime valueDate) : base(valueDate) { } public double? GetVol(OtcTradeBase td, double spotPrice) { if (td is null) { throw new ArgumentNullException(nameof(td)); } if (TryGetVol(td.id, out var vol)) { return vol; } return td.TradeSavedVol ?? 0; } } /// /// 开仓波动率提供(开仓波动率只在TradeVol模式下结算) /// class EodOpenVolProvider : TradeHedgeVolProvider, IEodVolProvider { public EodOpenVolProvider(DateTime valueDate) : base(valueDate) { } public double? GetVol(OtcTradeBase td, double spotPrice) { return td?.TradeOpenVolatility; } } #endregion #region----扩展波动率---- /// /// 扩展波动率(光证)提供 /// class EodExtendVolProvider_GZ : VarietyVolProvider, IEodVolProvider { public EodExtendVolProvider_GZ(DateTime valueDate) : base(valueDate) { } public double? GetVol(OtcTradeBase td, double spotPrice) { if (td is null) { throw new ArgumentNullException(nameof(td)); } if (TryGetVol(td.UnderlyingCode, out var vol)) { return vol; } return null; } } /// /// 扩展波动率(BidAskVol)提供 /// class EodExtendVolProvider_BidAskVol : EodUnderlyingVolProvider, IEodVolProvider { public EodExtendVolProvider_BidAskVol(DateTime valueDate) : base(valueDate, new[] { "报价Ask", "报价Bid" }) { } public double? GetVol(OtcTradeBase td, double spotPrice) { if (td is null) { throw new ArgumentNullException(nameof(td)); } return InnerGetVol(td, td.BuySell == "买入" ? "报价Ask" : "报价Bid", spotPrice); } } #endregion /// /// 波动率提供者工厂 /// public class EodVolProviderFactory { public static IEodVolProvider GetEodVolProvider(DateTime valueDate, string volType) { switch (volType) { case "持仓": if (PS.Config.IsTradeVol) { return new EodPositionVolProvider_Trade(valueDate); } volType = BLL.valuedateBLL.SystemDate.EodSettleVolMode.TrimToNull() ?? "财务"; return new EodPositionVolProvider_Underlying(valueDate, volType); case "开仓": return new EodOpenVolProvider(valueDate); case "对冲": return new EodHedgeVolProvider(valueDate); case "BidAskVol": return new EodExtendVolProvider_BidAskVol(valueDate); case "光证": return new EodExtendVolProvider_GZ(valueDate); default: return new EodUnderlyingSingleVolProvider(valueDate, volType); } } } }