165 lines
6.5 KiB
C#
165 lines
6.5 KiB
C#
using Qdp.ComputeService.Data.CommonModels.ValuationParams.Equity;
|
|
using Qdp.Pricing.Library.Options.Products.Autocall.Snowball;
|
|
using YLErp.BLL.Calculation;
|
|
using YLErp.BLL.Calculation.Engine;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.TradeModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.CalcModules
|
|
{
|
|
/// <summary>
|
|
/// 雪球期权计算测试
|
|
/// </summary>
|
|
[TestClass]
|
|
public class SnowballOptionCalcTest : UnitTestBase
|
|
{
|
|
[TestMethod("雪球期权-行权价和执行价近似相等时计算非常慢")]
|
|
public void SnowballOptionCalcTest1()
|
|
{
|
|
var data = DeserializeFormData<OtcOptionTradeFullFormData>("TradeJson\\SnowballTrade1.txt");
|
|
|
|
Assert.IsTrue(data.trades != null && data.trades.Any());
|
|
|
|
var tdfull = data.trades.First();
|
|
var tdconv = TradeConverter.ConvertOptionTrade(tdfull);
|
|
|
|
var sw = new System.Diagnostics.Stopwatch();
|
|
sw.Start();
|
|
|
|
//为解决慢的问题,TradeRiskCalcUtil类加了优化处理方法:OptimizeSpotPrice
|
|
var result = OptionCalculatorV2.GetOptionValueResult(new DateTime(2021, 5, 12), tdconv, new OptionValueCalcRequest(0.04)
|
|
{
|
|
spotPrices = new[] { 6512.0501 },
|
|
vols = new[] { 0.18 },
|
|
pricingRequest = QdpModule.QdpPricingRequest.BASIC_GREEKS
|
|
}, out _);
|
|
|
|
sw.Stop();
|
|
|
|
Console.WriteLine($"耗时{sw.ElapsedMilliseconds / 1000}秒,pv:{result.Pv}");
|
|
|
|
Assert.IsTrue(sw.ElapsedMilliseconds < 10 * 1000);
|
|
}
|
|
|
|
[TestMethod("雪球期权计算--海通认为算的不对")]
|
|
public void SnowballOptionCalcTest2()
|
|
{
|
|
var json = ReadResourceFile("TradeJson\\SnowballTrade2.json");
|
|
var td = JsonHelper.Deserialize<trade>(json);
|
|
Assert.IsNotNull(td);
|
|
var result = OptionCalculatorV2.GetOptionValueResult(new DateTime(2021, 5, 28), td, new OptionValueCalcRequest(0)
|
|
{
|
|
spotPrices = new[] { 13660d },
|
|
vols = new[] { 0.254561403508772 }
|
|
}, out _);
|
|
|
|
Assert.IsTrue(Math.Abs(Math.Abs(result.Pv) - 213772.8) < 10);
|
|
}
|
|
|
|
[TestMethod("雪球期权计算--和Excel模板算的不一致")]
|
|
public void SnowballOptionCalcTest3()
|
|
{
|
|
var optionTrade = QdpTradeBuilder.GetSnowballOptionTrade(new SnowballOptionTradeParam
|
|
{
|
|
annualizedFactor = 1,
|
|
annualizedOptionPayoff = true,
|
|
annualizedPremiumRate = null,
|
|
barrierStatus = "",
|
|
buysell = "Buy",
|
|
callput = Qdp.Pricing.Base.Enums.OptionType.Put,
|
|
coupon = 0.3149,
|
|
couponDayCount = "Act365",
|
|
couponPaymentDateStr = "2022-04-06,2022-05-05,2022-06-06,2022-07-04",
|
|
dividendRate = 0.015,
|
|
dividends = null,
|
|
endDate = new Qdp.Foundation.Implementations.Date(2022, 7, 4),
|
|
exerciseDate = new Qdp.Foundation.Implementations.Date(2022, 7, 4),
|
|
exerciseType = null,
|
|
hasNightMarket = false,
|
|
initialSpotPrice = 100,
|
|
isAnnualized = false,
|
|
isFixedCoupon = false,
|
|
isForwardTrade = false,
|
|
isMoneynessOption = false,
|
|
kiBarrier = 120,
|
|
kiOptionType = Qdp.Pricing.Base.Enums.OptionType.CallSpread,
|
|
koBarrier = 100,
|
|
koBarrierAdjustStep = 0,
|
|
koObservationDateStr = "2022-04-06,2022-05-05,2022-06-06,2022-07-04",
|
|
koOptionType = Qdp.Pricing.Base.Enums.OptionType.Coupon,
|
|
koRebate = 0.3149,
|
|
koStrike = -1,
|
|
notional = 1,
|
|
observationDateStr = null,
|
|
optionType = Qdp.Pricing.Base.Enums.OptionType.Put,
|
|
participationRate = 1,
|
|
preciseTimeMode = false,
|
|
principalRate = 0,
|
|
riskFreeRate = 0.015,
|
|
settlementDate = new Qdp.Foundation.Implementations.Date(2022, 7, 4),
|
|
spreadStrikeAtKO = -1,
|
|
spreadStrikeAtMaturity = 100,
|
|
startDate = new Qdp.Foundation.Implementations.Date(2022, 3, 4),
|
|
strike = 120,
|
|
timeToMaturityDays = double.NaN,
|
|
tradeDate = new Qdp.Foundation.Implementations.Date(2022, 3, 4),
|
|
tradeId = "111111",
|
|
underlyingInstrumentType = "Stock",
|
|
underlyingTickers = new[] { "000001.sz" },
|
|
useOptionPayoffAtKO = false,
|
|
useOptionPayoffAtMaturity = true,
|
|
volSurfaceNames = new[] { "2222" }
|
|
}, SnowBallOptionMode.SimpleSnowball);
|
|
|
|
var option = optionTrade.Instrument as SimpleSnowball;
|
|
var factory = OptionEngineFactory.GetEngineFactory("SnowBall");
|
|
var engine = factory.GetEngine(null, option.Exercise);
|
|
|
|
var tenors = new string[]
|
|
{
|
|
"1D",
|
|
"2M",
|
|
"1Y"
|
|
};
|
|
|
|
var strikes = new double[]
|
|
{
|
|
0.95,
|
|
1.0,
|
|
1.05,
|
|
};
|
|
var vols = new double[3, 3];
|
|
var singleVols = new List<SingleVol>();
|
|
for (var i = 0; i < vols.GetLength(0); ++i)
|
|
{
|
|
for (var j = 0; j < vols.GetLength(1); ++j)
|
|
{
|
|
vols[i, j] = 0.2;
|
|
singleVols.Add(new SingleVol()
|
|
{
|
|
Strike = strikes[j],
|
|
Expire = tenors[i],
|
|
Vol = 0.44
|
|
});
|
|
}
|
|
}
|
|
|
|
using var mp = new MarketProxy(new DateTime(2022, 3, 4), 0.015);
|
|
mp.SetVolSurface("2222", new VolatilityImpl { VolTable = singleVols });
|
|
|
|
mp.SetStockPrice("000001.sz", 100);
|
|
|
|
var _dividendCurveName = Guid.NewGuid().ToString();
|
|
var dividendCurve = CalculatorHelper.CreateConstantRiskFreeCurve(_dividendCurveName, 0.015);
|
|
mp.SetYieldCurve(_dividendCurveName, dividendCurve);
|
|
|
|
var pps = new OptionValuationParameters(_dividendCurveName,
|
|
_dividendCurveName, "2222", "000001.sz");
|
|
var results = optionTrade.CalculateRisks(mp.QdpMarket, Qdp.Pricing.Base.Implementations.PricingRequest.Pv
|
|
, engine, pps);
|
|
Assert.IsTrue(Math.Abs(results.Pv) > 1);
|
|
}
|
|
}
|
|
}
|