252 lines
10 KiB
C#
252 lines
10 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// 期权计算比较(新版本和老版本)
|
|
/// </summary>
|
|
[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<VanillaOptionTradeParam>(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<AsianOptionTradeParam>(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);
|
|
}
|
|
}
|
|
}
|