140 lines
5.8 KiB
C#
140 lines
5.8 KiB
C#
using Qdp.ComputeService.Data.CommonModels.ValuationParams.Equity;
|
|
using Qdp.Foundation.Implementations;
|
|
using YLErp.Abstract;
|
|
using YLErp.BLL.Calculation;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.CalculationModule
|
|
{
|
|
/// <summary>
|
|
/// 隐含波动率计算服务
|
|
/// </summary>
|
|
public class ImpliedVolCalcService
|
|
{
|
|
/// <summary>
|
|
/// 根据权利金计算隐含波动率
|
|
/// </summary>
|
|
/// <param name="premium">期权单价</param>
|
|
/// <param name="valueDate">计算日期</param>
|
|
public static double ImpliedVolFromPremium(
|
|
double premium,
|
|
DateTime valueDate,
|
|
string underlyingTicker,
|
|
string underlyingInstrumentType,
|
|
double strike,
|
|
DateTime startDate,
|
|
DateTime endDate,
|
|
string optionType,
|
|
string exerciseType,
|
|
double spotPrice,
|
|
double notional,
|
|
double riskFreeRate,
|
|
string tradeType,
|
|
DateTime exerciseDate,
|
|
double participationRate,
|
|
double principalRate,
|
|
bool isAnnualized,
|
|
double annualizeFactor,
|
|
double dividendRate = 0.0,
|
|
bool isMoneynessOption = false,
|
|
double initialSpotPrice = 0.0,
|
|
Dictionary<Date, double> dividends = null,
|
|
bool hasNightMarket = false,
|
|
bool preciseTimeMode = false,
|
|
double ttmDays = double.NaN, IVolatility volatility = null)
|
|
{
|
|
var optionTradeParam = new VanillaOptionTradeParam
|
|
{
|
|
annualizedFactor = annualizeFactor,
|
|
buysell = tradeType,
|
|
preciseTimeMode = preciseTimeMode,
|
|
dividendRate = dividendRate,
|
|
dividends = dividends,
|
|
endDate = endDate,
|
|
exerciseDate = exerciseDate,
|
|
exerciseType = exerciseType,
|
|
hasNightMarket = hasNightMarket,
|
|
initialSpotPrice = initialSpotPrice,
|
|
isAnnualized = isAnnualized,
|
|
isMoneynessOption = isMoneynessOption,
|
|
notional = notional,
|
|
optionType = QdpConverter.ConvertOptionType(optionType),
|
|
participationRate = participationRate,
|
|
principalRate = principalRate,
|
|
riskFreeRate = riskFreeRate,
|
|
settlementDate = exerciseDate,
|
|
startDate = startDate,
|
|
strike = strike,
|
|
timeToMaturityDays = ttmDays,
|
|
tradeDate = startDate,
|
|
underlyingInstrumentType = underlyingInstrumentType,
|
|
underlyingTickers = new[] { underlyingTicker },
|
|
tradeId = null,
|
|
volSurfaceNames = null,
|
|
isForwardTrade = false
|
|
};
|
|
|
|
return ImpliedVolFromPremium(premium, valueDate, optionTradeParam, spotPrice, volatility);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据权利金计算隐含波动率
|
|
/// </summary>
|
|
/// <param name="premium">期权单价</param>
|
|
/// <param name="valueDate">计算日期</param>
|
|
/// <param name="optionTradeParam">期权要素</param>
|
|
/// <param name="spotPrice">标的现价</param>
|
|
public static double ImpliedVolFromPremium(double premium, DateTime valueDate
|
|
, VanillaOptionTradeParam optionTradeParam, double spotPrice, IVolatility volatility = null)
|
|
{
|
|
//在计算ImpliedVol时,提前处理strike,然后都当做非MoneynessOption处理
|
|
if (optionTradeParam.isMoneynessOption)
|
|
{
|
|
optionTradeParam.isMoneynessOption = false;
|
|
optionTradeParam.strike *= optionTradeParam.initialSpotPrice;
|
|
}
|
|
|
|
if (optionTradeParam.volSurfaceNames == null || !optionTradeParam.volSurfaceNames.Any())
|
|
{
|
|
optionTradeParam.volSurfaceNames = new[] { Guid.NewGuid().ToString() };
|
|
}
|
|
|
|
var volSurfaceName = optionTradeParam.volSurfaceNames[0];
|
|
|
|
if (optionTradeParam.underlyingTickers == null || !optionTradeParam.underlyingTickers.Any())
|
|
{
|
|
throw new Exception("缺少标的代码");
|
|
}
|
|
|
|
var underlyingTicker = optionTradeParam.underlyingTickers[0];
|
|
|
|
optionTradeParam.buysell = "买入";
|
|
var optionTrade = QdpTradeBuilder.GetVanillaOptionTrade(optionTradeParam);
|
|
|
|
using (var marketProxy = new MarketProxy(valueDate, optionTradeParam.riskFreeRate))
|
|
{
|
|
//设置标的价格
|
|
marketProxy.SetStockPrice(underlyingTicker, spotPrice);
|
|
marketProxy.SetVolSurface(volSurfaceName, volatility ?? QdpVolHelper.GetDefaultVolatility(0.3));
|
|
|
|
OptionValuationParameters parameters;
|
|
|
|
if (optionTradeParam.underlyingInstrumentType == ConsGlobal.InstrumentType.Stock)
|
|
{
|
|
//设置DividendCurve
|
|
var dividendCurveName = Guid.NewGuid().ToString();
|
|
var dividendCurve = CalculatorHelper.CreateConstantRiskFreeCurve(dividendCurveName, optionTradeParam.dividendRate);
|
|
marketProxy.SetYieldCurve(dividendCurveName, dividendCurve);
|
|
parameters = new OptionValuationParameters(marketProxy.DiscountCurveName, dividendCurveName, volSurfaceName, underlyingTicker);
|
|
}
|
|
else
|
|
{
|
|
parameters = new OptionValuationParameters(marketProxy.DiscountCurveName, MarketProxy.ConstantZeroCurve, volSurfaceName, underlyingTicker);
|
|
}
|
|
|
|
return optionTrade.ImpliedVolFromPremium(premium, marketProxy.QdpMarket, parameters);
|
|
}
|
|
}
|
|
}
|
|
}
|