Files
zszq-trs/YLErpDAL/QdpModule/QdpVolHelper.cs
T
2024-05-09 14:06:26 +08:00

306 lines
10 KiB
C#

using Qdp.Foundation.Implementations;
using Qdp.Pricing.Base.Implementations;
using Qdp.Pricing.Base.Utilities;
using Qdp.Pricing.Library.Common.MathMethods.VolTermStructure;
using Qdp.Pricing.Library.Equity.Engines.Analytical;
using YLErp.Abstract;
using YLErp.BLL.Calculation;
using YLErp.Commons;
using YLErp.Models;
using YLErp.Modules.CalculationModule;
using YLErp.QdpModule.Constants;
namespace YLErp.QdpModule
{
/// <summary>
/// 波动率曲面帮助类
/// </summary>
public static class QdpVolHelper
{
public const string VOL_SURFACE_SUFFIX = "_VolSurface";
/// <summary>
/// 从交易的TradeVol构造一个波动率曲面
/// </summary>
public static IVolatility GetSurfaceFromTradeVol(DateTime valueDate, ITradeVolLinearParam para)
{
if (para == null)
{
throw new ArgumentNullException(nameof(para));
}
double constVol;
if (valueDate < para.GetStartDate())
{
constVol = para.GetTradeOpenVol();
}
else if (valueDate > para.GetMaturityDate())
{
constVol = para.GetTradeCloseVol();
}
else
{
var daycountMode = PS.Config.ErpElement.SmoothingDaycountMode == Configuration.Enums.SmoothingDaycountMode.CalendarDay
? Qdp.Pricing.Base.Enums.DayCountMode.CalendarDay
: Qdp.Pricing.Base.Enums.DayCountMode.TradingDay;
constVol = AnalyticalOptionTradeVolInterp.tradeVolLinearInterp(
new Date(valueDate),
para.GetTradeOpenVol(), para.GetTradeCloseVol(),
new Date(para.GetStartDate()),
new Date(para.GetMaturityDate()),
para.GetNumOfSmoothingDays(),
daycountMode,
CalendarImpl.Get("chn"),
para.IsIncludeStartDate());
}
//生成3*3水平的波动率曲面
return GenerateFlatSurface(OtcFormatHelper.FormatValue(constVol, 4));
}
/// <summary>
/// 生成平面波动率
/// </summary>
public static IVolatility GenerateFlatSurface(double constVol)
{
return GenerateFlatSurface(constVol, ConsVolInfos.DefaultVolStrikeList, ConsVolInfos.DefaultVolTenorList);
}
/// <summary>
/// 生成平面波动率
/// </summary>
public static IVolatility GenerateFlatSurface(double constVol, IEnumerable<double> strikes, IEnumerable<string> expires)
{
if (strikes == null)
{
throw new ArgumentNullException(nameof(strikes));
}
if (expires == null)
{
throw new ArgumentNullException(nameof(expires));
}
var volTable = new List<SingleVol>();
foreach (var strike in strikes)
{
foreach (var expire in expires)
{
volTable.Add(new SingleVol { Expire = expire, Strike = strike, Vol = constVol });
}
}
return new VolatilityImpl()
{
VolSurfaceMode = "StrikeVol",
InterpolationMethod = ConsVolMethod.BiLinear,
VolTable = volTable
};
}
/// <summary>
///
/// </summary>
public static List<SingleVol> GenerateFlatSingleVols(double vol)
{
var volTable = new List<SingleVol>(20);
foreach (var strike in ConsVolInfos.DefaultMoneynessVolStrikeList)
{
foreach (var expire in ConsVolInfos.DefaultVolTenorList)
{
volTable.Add(new SingleVol(strike, expire, vol));
}
}
return volTable;
}
/// <summary>
/// 根据一组波动率,算出所有的strike
/// </summary>
public static List<double> GetStrikes(IEnumerable<SingleVol> vols)
{
if (vols == null)
{
return new List<double>(0);
}
return vols.GroupBy(v => v.Strike).OrderBy(v => v.Key).Select(v => v.Key).ToList();
}
/// <summary>
/// 从波动率曲面上找到某点的波动率
/// </summary>
/// <param name="exerciseDate">某点的到期日</param>
/// <param name="strike">某点的行权价</param>
/// <returns>波动率</returns>
public static double GetInterpolatedVol(
ImpliedVolSurface volSurface,
DateTime exerciseDate,
double strike,
bool isMoneynessOption,
bool isEodCalc,
double spot = 0.0,
double? timeFraction = null)
{
double vol;
if (PS.Config.Is润和 && !isEodCalc)
{
vol = volSurface.GetValue(timeFraction.Value, strike);
}
else
{
if (isMoneynessOption)
{
vol = volSurface.GetValue(new Date(exerciseDate), strike * spot, spot);
}
else
{
vol = volSurface.GetValue(new Date(exerciseDate), strike, spot);
}
}
return PS.Config.Is润和 ? OtcFormatHelper.FormatValue(vol, 4) : vol;
}
/// <summary>
/// 从波动率曲面上找到某点的波动率
/// </summary>
/// <param name="exerciseDate">某点的到期日</param>
/// <param name="strike">某点的行权价</param>
/// <returns>波动率</returns>
public static double GetInterpolatedVol(
ImpliedVolSurface volSurface,
Date exerciseDate,
double strike,
string isMoneynessOption,
double spot = 0.0)
{
if (isMoneynessOption == "是" || isMoneynessOption == "True")
{
return volSurface.GetValue(exerciseDate, strike * spot, spot);
}
else
{
return volSurface.GetValue(exerciseDate, strike, spot);
}
}
/// <summary>
/// interpolatevol qdp中 根据波动率曲面得到一个波动率数值
/// </summary>
public static double GetInterpolatedVolFromNormalSurface(IEnumerable<SingleVol> vols, InterpolatedVolReq volReq, string interpolationMethod = ConsVolMethod.Default)
{
if (vols == null || !vols.Any())
{
return double.NaN;
}
var surfaceWrap = new VolSurfaceBuilder
{
interpolation = interpolationMethod,
volSurfaceName = "tempVolSurface",
volSurfaceType = volReq.volSurfaceType
}.SetVectors(vols).Build(volReq.valueDate);
double? timeFraction = null;
double strike = 0;
if (PS.Config.Is润和 && !volReq.isEodCalc)
{
var days = TradeCalcHelper.CalculateTTMDays(volReq.valueDate, volReq.exerciseDate, 0, false);
var daysInYear = (int)CalculatorHelper.GetTradeDayCount().ToDayCountImpl().DaysInYear();
timeFraction = days / daysInYear;
strike = volReq.volSurfaceType == "StrikeVol" ? (volReq.isMoneynessOption ? (volReq.strike * volReq.spot) : volReq.strike) : (volReq.isMoneynessOption ? volReq.strike : (volReq.strike / volReq.spot));
}
else
{
strike = volReq.strike;
}
return GetInterpolatedVol(
surfaceWrap.VolSurface,
volReq.exerciseDate,
strike,
volReq.isMoneynessOption,
volReq.isEodCalc,
volReq.spot,
timeFraction);
}
/// <summary>
///
/// </summary>
public static string GetVolSurfaceName(string referenceId, string secondUnderlyingCode = null)
{
if (string.IsNullOrEmpty(referenceId))
{
throw new ArgumentException($"“{nameof(referenceId)}”不能是 Null 或为空。", nameof(referenceId));
}
return string.IsNullOrWhiteSpace(secondUnderlyingCode)
? $"{referenceId}{VOL_SURFACE_SUFFIX}"
: $"{referenceId}_{secondUnderlyingCode}{VOL_SURFACE_SUFFIX}";
}
/// <summary>
///
/// </summary>
public static string GenerateVolSurfaceKey(this string underlyingCode)
{
return underlyingCode + VOL_SURFACE_SUFFIX;
}
/// <summary>
/// 用自定义波动率值构造一个水平的波动率曲面
/// </summary>
public static IVolatility GetDefaultVolatility(double vol)
{
var vols = new List<SingleVol>
{
new SingleVol
{
Strike = 1,
Expire = "1D",
Vol = vol
},
new SingleVol
{
Strike = 1,
Expire = "1Y",
Vol = vol
}
};
return new VolatilityImpl
{
VolTable = vols,
VolSurfaceMode = ConsVolInfos.defVolMode,
InterpolationMethod = ConsVolInfos.defInterpolationMethod
};
}
}
/// <summary>
///
/// </summary>
public class InterpolatedVolReq
{
public DateTime valueDate { get; set; }
public DateTime exerciseDate { get; set; }
public double strike { get; set; }
public bool isMoneynessOption { get; set; }
public string volSurfaceType { get; set; } = "StrikeVol";
public double spot { get; set; }
public bool isEodCalc { get; set; } = false;
}
}