using Microsoft.VisualStudio.TestTools.UnitTesting;
using Qdp.Pricing.Base.Enums;
using System;
using YLErp.BLL;
using YLErp.BLL.Calculation;
using YLErp.DBModels;
using YLErp.QdpModule;
namespace YLErp.Modules.CalculationModule
{
///
/// 期权计算比较(新版本和老版本)
///
[TestClass]
public class OptionCalculatorCompare
{
const double ConstVol = 0.3;
const double Notional = 1;
const double SpotPrice = 3000;
const double RiskFreeRate = 0.03;
const string ExerciseType = "European";
const string UnderlyingCode = "RB00";
const int TTMDays = 36;
const string InstrumentType = "CommodityFutures";
static readonly string QdpMarketID = Guid.NewGuid().ToString();
static readonly DateTime TradeDate = new DateTime(2021, 1, 4);
static readonly DateTime ExerciseDate = new DateTime(2021, 3, 1);
[TestMethod]
public void TestVanillaOption()
{
var vols = QdpVolHelper.GetDefaultVolatility(ConstVol);
var valueDateStr = TradeDate.ToString("yyyy-MM-dd");
var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(QdpMarketID);
var underlying = new
{
UnderlyingCode = UnderlyingCode,
UnderlyingInstrumentType = InstrumentType,
Price = SpotPrice
};
//使用全局的DiscountCurve以提高计算效率
var discountCurveName = Guid.NewGuid().ToString();
var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, valuedateBLL.RiskFreeRate / 100.0);
marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve);
var initParam = new VolSurfaceInitParamsBuilder(QdpMarketID)
.SetValueDate(TradeDate)
.SetUnderlying(0, UnderlyingCode, UnderlyingCode)
.SetVolatility(vols).Build(QdpMarketID);
VolSurfaceInitializerSingleton.GetInitializer(false).InitializeMarketProxy(initParam);
var bidMaturityDate = ExerciseDate.ToString(ConsGlobal.DateFormat);
var tv1 = OptionCalculatorV1.ValueVanillaOptionTrade(
marketProxy: marketProxy,
valueDate: valueDateStr,
underlyingTicker: underlying.UnderlyingCode,
underlyingInstrumentType: underlying.UnderlyingInstrumentType,
strike: SpotPrice,
startDate: valueDateStr,
endDate: bidMaturityDate,
optionType: "Call",
exerciseType: ExerciseType,
spotPrice: underlying.Price,
notional: Notional,
volSurfaceName: initParam.volSurfaceNameKey,
riskFreeRate: RiskFreeRate,
modelName: null,
tradeType: "Buy",
exerciseDate: bidMaturityDate,
hasNightMarket: false,
commodityFuturesPreciseTimeMode: true,
discountCurveName: discountCurveName,
participationRate: 1.0,
principalRate: 0.0,
isAnnualized: false,
annualizeFactor: 1.0,
timeToMaturityDays: TTMDays);
System.Diagnostics.Debug.WriteLine("V1 PV:" + tv1.Pv);
var vtParam = new VanillaOptionTradeParam
{
annualizedFactor = 0,
isAnnualized = false,
buysell = "买入",
commodityFuturesPreciseTimeMode = true,
dividendRate = 0,
dividends = null,
endDate = ExerciseDate,
exerciseDate = ExerciseDate,
exerciseType = ExerciseType,
hasNightMarket = false,
initialSpotPrice = SpotPrice,
isForwardTrade = false,
isMoneynessOption = false,
notional = Notional,
optionType = OptionType.Call,
participationRate = 1,
principalRate = 0,
riskFreeRate = RiskFreeRate,
settlementDate = ExerciseDate,
startDate = TradeDate,
strike = SpotPrice,
timeToMaturityDays = TTMDays,
tradeDate = TradeDate,
tradeId = QdpMarketID,
underlyingInstrumentType = InstrumentType,
underlyingTickers = new[] { UnderlyingCode },
volSurfaceNames = new[] { QdpMarketID }
};
TradeValueResult tv2;
using (var mp = new MarketProxy(TradeDate, 0.03))
{
mp.SaveVolSurface(QdpMarketID, vols);
tv2 = TradeRiskCalcUtil.GetVanillaOptionValue(mp, new OptionCalcParam(vtParam)
{
pricingRequest = QdpPricingRequest.BASIC_GREEKS,
spotPrices = new[] { 3000d },
});
}
System.Diagnostics.Debug.WriteLine("V2 PV:" + tv2.Pv);
Assert.AreEqual(tv1.Pv, tv2.Pv, 1e-6);
Assert.AreEqual(tv1.Delta, tv2.Delta, 1e-6);
Assert.AreEqual(tv1.Gamma, tv2.Gamma, 1e-6);
Assert.AreEqual(tv1.Theta, tv2.Theta, 1e-6);
Assert.AreEqual(tv1.Rho, tv2.Rho, 1e-6);
Assert.AreEqual(tv1.Vega, tv2.Vega, 1e-6);
}
[TestMethod]
public void TestAsiaOption()
{
var vols = QdpVolHelper.GetDefaultVolatility(ConstVol);
var valueDateStr = TradeDate.ToString("yyyy-MM-dd");
var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(QdpMarketID);
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(UnderlyingCode);
//使用全局的DiscountCurve以提高计算效率
var discountCurveName = Guid.NewGuid().ToString();
var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, valuedateBLL.RiskFreeRate / 100.0);
marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve);
var initParam = new VolSurfaceInitParamsBuilder(QdpMarketID)
.SetValueDate(TradeDate)
.SetUnderlying(0, UnderlyingCode, UnderlyingCode)
.SetVolatility(vols).Build(QdpMarketID);
VolSurfaceInitializerSingleton.GetInitializer(false).InitializeMarketProxy(initParam);
underlying.Price = SpotPrice;
underlying.QuotationDate = TradeDate;
var td = new trade()
{
TradeType = "亚式期权",
UnderlyingCode = underlying.UnderlyingCode,
UnderlyingInstrumentType = InstrumentType,
TradeDate = TradeDate,
StartDate = TradeDate,
MaturityDate = ExerciseDate,
ExerciseDate = ExerciseDate,
OptionType = "看涨",
ExerciseMode = ExerciseType,
Strike = SpotPrice,
SpotPrice = SpotPrice,
Notional = Notional,
NoRiskRate = RiskFreeRate,
BuySell = "Buy",
QuotationType = "波动率调整",
TradeOpenVolatility = ConstVol,
TTMDays = TTMDays,
trade_asian_option = new trade_asian_option()
{
PayoffType = "ArithmeticAverage",
StrikeType = "Fixed",
AveragingPeriodStartDate = TradeDate
}
};
var tv1 = OptionCalculatorV1.GetOptionValueResult(QdpMarketID, underlying, td, new[] { SpotPrice },
useTradeVolMode: true, volSurfaceNames: new[] { initParam.volSurfaceNameKey },
fixing: $"{TradeDate:yyyy-MM-dd},{SpotPrice}", commodityFuturesPreciseTimeMode: false);
System.Diagnostics.Debug.WriteLine("V1 PV:" + tv1.Pv);
var vtParam = new AsianOptionTradeParam
{
annualizedFactor = 0,
isAnnualized = false,
buysell = "买入",
commodityFuturesPreciseTimeMode = false,
dividendRate = 0,
dividends = null,
endDate = ExerciseDate,
exerciseDate = ExerciseDate,
exerciseType = ExerciseType,
hasNightMarket = false,
initialSpotPrice = SpotPrice,
isForwardTrade = false,
isMoneynessOption = false,
notional = 1,
optionType = OptionType.Call,
participationRate = 1,
principalRate = 0,
riskFreeRate = RiskFreeRate,
settlementDate = ExerciseDate,
startDate = TradeDate,
strike = SpotPrice,
timeToMaturityDays = TTMDays,
tradeDate = TradeDate,
tradeId = QdpMarketID,
underlyingInstrumentType = InstrumentType,
underlyingTickers = new[] { UnderlyingCode },
volSurfaceNames = new[] { QdpMarketID },
payoffType = "ArithmeticAverage",
strikeStyle = "Fixed",
averagingPeriodStartDate = TradeDate
};
TradeValueResult tv2;
using (var mp = new MarketProxy(TradeDate, RiskFreeRate))
{
mp.SaveVolSurface(QdpMarketID, vols);
tv2 = TradeRiskCalcUtil.GetAsianOptionValue(mp, new OptionCalcParam(vtParam)
{
pricingRequest = QdpPricingRequest.BASIC_GREEKS,
spotPrices = new[] { SpotPrice },
});
}
System.Diagnostics.Debug.WriteLine("V2 PV:" + tv2.Pv);
Assert.AreEqual(tv1.Pv, tv2.Pv, 1e-6);
Assert.AreEqual(tv1.Delta, tv2.Delta, 1e-6);
Assert.AreEqual(tv1.Gamma, tv2.Gamma, 1e-6);
Assert.AreEqual(tv1.Theta, tv2.Theta, 1e-6);
Assert.AreEqual(tv1.Rho, tv2.Rho, 1e-6);
Assert.AreEqual(tv1.Vega, tv2.Vega, 1e-6);
}
}
}