从山证v2.3.0拷贝
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user