257 lines
9.2 KiB
C#
257 lines
9.2 KiB
C#
using YLErp.Abstract.DataProviders;
|
|
using YLErp.BLL;
|
|
using YLErp.Modules.VolatilityModule;
|
|
|
|
namespace YLErp.Modules.ExchangeOptionTradeModule
|
|
{
|
|
/// <summary>
|
|
/// 场内期权波动率查询
|
|
/// </summary>
|
|
public class ExchangeOptionVolQueryService : YLBaseService
|
|
{
|
|
public ExchangeOptionVolQueryService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取场内期权保存的波动率
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取场内期权波动率
|
|
/// </summary>
|
|
/// <param name="valueDate">nullable时使用当前交易日期</param>
|
|
/// <param name="optionCode"></param>
|
|
/// <param name="underlyingPrice"></param>
|
|
/// <param name="userGroup"></param>
|
|
/// <returns></returns>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据配置获取系统或隐含波动率
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 场内期权波动率查询
|
|
/// </summary>
|
|
public class ExchangeOptionVolRequest
|
|
{
|
|
public ExchangeOptionVolRequest()
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 必需, 场内期权代码
|
|
/// </summary>
|
|
public string OptionCode { get; set; }
|
|
|
|
/// <summary>
|
|
/// 估值日期,为null时取系统交易日期
|
|
/// </summary>
|
|
public DateTime? ValueDate { get; set; }
|
|
|
|
/// <summary>
|
|
/// 必需,场内期权价格提供,用于计算隐含波动率
|
|
/// </summary>
|
|
public Lazy<IPriceProvider> ExchangeOptionPriceProvider { get; set; }
|
|
|
|
/// <summary>
|
|
/// 标的价格, savedVol无效时用于取隐含波动率或曲面波动率,为null时使用IUnderlyingPriceProvider获取
|
|
/// </summary>
|
|
public double? UnderlyingPrice { get; set; }
|
|
|
|
/// <summary>
|
|
/// 获取标的价格的接口,UnderlyingPrice为null时使用此接口
|
|
/// </summary>
|
|
public Lazy<IPriceProvider> UnderlyingPriceProvider { get; set; }
|
|
|
|
/// <summary>
|
|
/// 用户组,用于取曲面波动率
|
|
/// </summary>
|
|
public string UserGroup { get; set; }
|
|
|
|
/// <summary>
|
|
/// 波动率类型,未传入时TradeVol模式下使用交易Mid波动率,Volsurface模式下使用配置的结算波动率
|
|
/// </summary>
|
|
public string VolType { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 场内期权波动率结果类型
|
|
/// </summary>
|
|
public enum ExchangeOptionVolResultType
|
|
{
|
|
/// <summary>
|
|
/// 保存的固定波动率
|
|
/// </summary>
|
|
SavedFixVol,
|
|
|
|
/// <summary>
|
|
/// 曲面波动率
|
|
/// </summary>
|
|
UnderlyingVol,
|
|
|
|
/// <summary>
|
|
/// 隐含波动率
|
|
/// </summary>
|
|
ImpliedVol
|
|
}
|
|
}
|