151 lines
6.0 KiB
C#
151 lines
6.0 KiB
C#
using BaseOUDAL;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.SkewMapVolModule;
|
|
using YLErp.QdpModule;
|
|
using YLErp.QdpModule.Constants;
|
|
|
|
namespace YLErp.Modules.VolatilityModule
|
|
{
|
|
/// <summary>
|
|
/// 波动率取值服务
|
|
/// </summary>
|
|
public class SingleVolService
|
|
{
|
|
public static double GetSingleVol(SingleVolReq singleVolReq, int userId, bool isEodCalc = false)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(singleVolReq.VolType))
|
|
{
|
|
throw new ServiceException("波动率类型不能为空");
|
|
}
|
|
|
|
if (singleVolReq.ExerciseDate == DateTime.MinValue)
|
|
{
|
|
throw new ServiceException("行权日不能为空");
|
|
}
|
|
|
|
if (singleVolReq.TradeDate == DateTime.MinValue)
|
|
{
|
|
throw new ServiceException("交易日期不能为空");
|
|
}
|
|
|
|
if (PS.Config.ErpElement.SkewMapVolConstruction)
|
|
{
|
|
return GetSingleVolWithSkewMapMode(singleVolReq, userId);
|
|
}
|
|
else
|
|
{
|
|
return GetSingleVolWithNormalMode(singleVolReq, userId, isEodCalc);
|
|
}
|
|
}
|
|
|
|
//获取正常模式的波动率
|
|
private static double GetSingleVolWithNormalMode(SingleVolReq singleVolReq, int userId, bool isEodCalc = false)
|
|
{
|
|
var userGroup = singleVolReq.UserGroup.TrimToNull() ?? UserBLL.GetUserGroup(userId);
|
|
var volatility = new VolatilityQueryService(OptUserInfo.SystemUser)
|
|
.GetVolatility(userGroup, singleVolReq.TradeDate, singleVolReq.VolType, singleVolReq.UnderlyingCode);
|
|
if (volatility == null)
|
|
{
|
|
throw new ServiceException($"没有找到{singleVolReq.VolType}波动率数据:{singleVolReq.UnderlyingCode}");
|
|
}
|
|
if (volatility is VolatilityDefault)
|
|
{
|
|
return ConsVolInfos.defVol;
|
|
}
|
|
var req = new InterpolatedVolReq
|
|
{
|
|
valueDate = singleVolReq.TradeDate,
|
|
exerciseDate = singleVolReq.ExerciseDate,
|
|
strike = singleVolReq.Strike,
|
|
isMoneynessOption = singleVolReq.IsMoneynessOption == "是",
|
|
isEodCalc = isEodCalc,
|
|
spot = singleVolReq.SpotPrice,
|
|
volSurfaceType = volatility.VolSurfaceMode
|
|
};
|
|
return QdpVolHelper.GetInterpolatedVolFromNormalSurface(volatility.VolTable, req, volatility.InterpolationMethod);
|
|
}
|
|
|
|
//获取skew模式的波动率
|
|
private static double GetSingleVolWithSkewMapMode(SingleVolReq req, int userId)
|
|
{
|
|
if (req.Vols == null)
|
|
{
|
|
var userGroup = UserBLL.GetUserGroup(userId);
|
|
req.Vols = new VolatilityQueryService(OptUserInfo.SystemUser)
|
|
.GetVolatility(userGroup, req.TradeDate, "交易", req.UnderlyingCode);
|
|
}
|
|
|
|
if (req.Vols == null || string.IsNullOrEmpty(req.Vols.VolSurfaceMode))
|
|
{
|
|
throw new InvalidOperationException($"找不到波动率曲面{req.UnderlyingCode}");
|
|
}
|
|
|
|
if (!req.BaseVol.HasValue)
|
|
{
|
|
throw new InvalidOperationException($"参数BaseVol缺失");
|
|
}
|
|
|
|
//var initParam = new VolSurfaceInitParamsBuilder(userId.ToString()).SetValueDate(singleVolReq.TradeDate)
|
|
// .SetUnderlying(singleVolReq.UnderlyingId, singleVolReq.UnderlyingCode, singleVolReq.UnderlyingName).SetVolatility(volatility).Build();
|
|
|
|
//VolSurfaceInitializerSingleton.GetInitializer(false).InitializeMarketProxy(initParam);
|
|
|
|
if (req.VolType == "报价Bid")
|
|
{
|
|
if (!req.BidVar.HasValue || req.BidVar.Value < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
//var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId.ToString());
|
|
var baseVolSurface = SkewMapVolHelper.GetSkewMapBaseVolSurface(req.UnderlyingCode, req.Vols);
|
|
var skewMapVolSurface = new SkewMapVolSurface(baseVolSurface.BaseVol);
|
|
|
|
var t = TradeCalcHelper.CalculateTTMDays(
|
|
req.TradeDate,
|
|
req.ExerciseDate,
|
|
req.UnderlyingTypeId,
|
|
precisionOfMinute: false);
|
|
|
|
return skewMapVolSurface.GetVolWithBaseVol(
|
|
baseVol: req.BaseVol.Value,
|
|
t: Math.Ceiling(t), //不考虑日内精确时间
|
|
k: req.Strike,
|
|
spot: req.SpotPrice,
|
|
isCall: req.CallPut == "Call",
|
|
isBuy: true,
|
|
var: req.BidVar ?? 0);
|
|
}
|
|
else if (req.VolType == "报价Ask")
|
|
{
|
|
if (!req.AskVar.HasValue || req.AskVar.Value < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId.ToString());
|
|
var baseVolSurface = SkewMapVolHelper.GetSkewMapBaseVolSurface(req.UnderlyingCode, req.Vols);
|
|
var skewMapVolSurface = new SkewMapVolSurface(baseVolSurface.BaseVol);
|
|
|
|
var t = TradeCalcHelper.CalculateTTMDays(
|
|
req.TradeDate,
|
|
req.ExerciseDate,
|
|
req.UnderlyingTypeId,
|
|
precisionOfMinute: false);
|
|
|
|
return skewMapVolSurface.GetVolWithBaseVol(
|
|
baseVol: req.BaseVol.Value,
|
|
t: Math.Ceiling(t), //不考虑日内精确时间
|
|
k: req.Strike,
|
|
spot: req.SpotPrice,
|
|
isCall: req.CallPut == "Call",
|
|
isBuy: false,
|
|
var: req.AskVar ?? 0);
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("波动率类型应为'报价Bid'或'报价Ask'");
|
|
}
|
|
}
|
|
}
|
|
}
|