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

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'");
}
}
}
}