using YLErp.Abstract.DataProviders; using YLErp.BLL; using YLErp.Modules.VolatilityModule; namespace YLErp.Modules.ExchangeOptionTradeModule { /// /// 场内期权波动率查询 /// public class ExchangeOptionVolQueryService : YLBaseService { public ExchangeOptionVolQueryService(OptUserInfo userInfo) : base(userInfo) { } /// /// 获取场内期权保存的波动率 /// /// public double? GetSavedVol(string optionCode, DateTime valueDate) { var (volValue, useFlag) = InnerGetSavedVol(optionCode, valueDate); return useFlag == ExchangeOptionVolUseFlag.FixedValue ? volValue : null; } private (double? volValue, ExchangeOptionVolUseFlag useFlag) InnerGetSavedVol(string optionCode, DateTime valueDate) { valueDate = valueDate.Date; var data = DbContext.exchange_option_vol .Where(v => v.OptionCode == optionCode && v.ValueDate <= valueDate) .OrderByDescending(v => v.ValueDate) .Select(n => new { n.Volatility, n.UseFlag }) .FirstOrDefault(); return data != null ? (data.Volatility, data.UseFlag) : (null, ExchangeOptionVolUseFlag.SystemOrImpliedVol); } /// /// 获取场内期权波动率 /// /// nullable时使用当前交易日期 /// /// /// /// public (double? volValue, ExchangeOptionVolResultType volType) GetVolValue(ExchangeOptionVolRequest request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (string.IsNullOrWhiteSpace(request.OptionCode)) { throw new ServiceException("场内期权代码 不能为空"); } var valueDate = request.ValueDate ?? valuedateBLL.ValueDate; //从数据库中获取保存的场内期权波动率值 var (volValue, useFlag) = InnerGetSavedVol(request.OptionCode, valueDate); if (useFlag == ExchangeOptionVolUseFlag.FixedValue) { return (volValue, ExchangeOptionVolResultType.SavedFixVol); } //特殊:光子只需要保存的波动率,故而返回null if (PS.Config.Is光大光子) { return (null, ExchangeOptionVolResultType.SavedFixVol); } //根据配置获取系统或隐含波动率 return GetSystemOrImpliedVol(request); } /// /// 根据配置获取系统或隐含波动率 /// private (double? volValue, ExchangeOptionVolResultType volType) GetSystemOrImpliedVol(ExchangeOptionVolRequest request) { var valueDate = request.ValueDate ?? valuedateBLL.ValueDate; var isImpliedVol = PS.Config.ErpElement.ExchangeOptionVolType == Configuration.Enums.ExchangeOptionVolType.ImpliedVol; var volResultType = isImpliedVol ? ExchangeOptionVolResultType.ImpliedVol : ExchangeOptionVolResultType.UnderlyingVol; //取场内期权合约信息 var exchangeOption = DataCacheProvider.GetExchangeListOptionDataSource().GetData(request.OptionCode); if (exchangeOption == null) { return (null, volResultType); } //取场内期权标的信息 var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(exchangeOption.UnderlyingCode); if (underlying == null) { return (null, volResultType); } //取场内期权标的价格 double underlyingPrice; if (request.UnderlyingPrice == null) { if (request.UnderlyingPriceProvider?.Value == null) { throw new ServiceException("缺少标的价格提供接口"); } underlyingPrice = request.UnderlyingPriceProvider.Value.GetPrice(underlying.UnderlyingCode); } else { underlyingPrice = request.UnderlyingPrice.Value; } if (isImpliedVol) { if (request.ExchangeOptionPriceProvider?.Value == null) { throw new ServiceException("缺少场内期权价格提供接口"); } var exOptionPrice = request.ExchangeOptionPriceProvider.Value.GetPrice(exchangeOption.ContractCode); var tempTrade = new trade { BuySell = "买入", TradeType = "场内期权", UnderlyingCode = underlying.UnderlyingCode, UnderlyingId = underlying.id, TradeDate = valueDate, StartDate = valueDate, ExerciseDate = exchangeOption.MaturityDate, MaturityDate = underlying.MaturityDate, TradePrice = exOptionPrice, TradeStatus = "确认成交", ExerciseMode = exchangeOption.ExerciseMode, OptionType = exchangeOption.OptionType, Strike = exchangeOption.Strike, Notional = 1, UnderlyingInstrumentType = underlying.UnderlyingInstrumentType, ExchangeOptionCode = exchangeOption.ContractCode, AssetId = 0, id = -1, UnderlyingAssetClass = underlying.UnderlyingType, //用于反算隐含波动率 StructureType = "场内期权", TradeSinglePrice = exOptionPrice }; var volValue = VolatilityHelper.GetImpliedVol(valueDate, tempTrade, null, underlyingPrice, false); return (volValue, ExchangeOptionVolResultType.ImpliedVol); } else { var req = new SingleVolReq { VolType = VolatilityHelper.GetUnderlyingVolType(request.VolType), Strike = exchangeOption.Strike, SpotPrice = underlyingPrice, TradeDate = valueDate, ExerciseDate = exchangeOption.MaturityDate, IsMoneynessOption = "否", //CallPut = trade.CallPut; UnderlyingId = underlying.id, UnderlyingCode = underlying.UnderlyingCode, UnderlyingName = underlying.UnderlyingName, UnderlyingTypeId = underlying.UnderlyingTypeId, UserGroup = request.UserGroup }; double? volValue = null; try { volValue = SingleVolService.GetSingleVol(req, 0); } catch { } return (volValue, ExchangeOptionVolResultType.UnderlyingVol); } } } /// /// 场内期权波动率查询 /// public class ExchangeOptionVolRequest { public ExchangeOptionVolRequest() { } /// /// 必需, 场内期权代码 /// public string OptionCode { get; set; } /// /// 估值日期,为null时取系统交易日期 /// public DateTime? ValueDate { get; set; } /// /// 必需,场内期权价格提供,用于计算隐含波动率 /// public Lazy ExchangeOptionPriceProvider { get; set; } /// /// 标的价格, savedVol无效时用于取隐含波动率或曲面波动率,为null时使用IUnderlyingPriceProvider获取 /// public double? UnderlyingPrice { get; set; } /// /// 获取标的价格的接口,UnderlyingPrice为null时使用此接口 /// public Lazy UnderlyingPriceProvider { get; set; } /// /// 用户组,用于取曲面波动率 /// public string UserGroup { get; set; } /// /// 波动率类型,未传入时TradeVol模式下使用交易Mid波动率,Volsurface模式下使用配置的结算波动率 /// public string VolType { get; set; } } /// /// 场内期权波动率结果类型 /// public enum ExchangeOptionVolResultType { /// /// 保存的固定波动率 /// SavedFixVol, /// /// 曲面波动率 /// UnderlyingVol, /// /// 隐含波动率 /// ImpliedVol } }