151 lines
5.9 KiB
C#
151 lines
5.9 KiB
C#
using Qdp.Foundation.Implementations;
|
|
using Qdp.Pricing.Base.Enums;
|
|
using Qdp.Pricing.Base.Implementations;
|
|
using Qdp.Pricing.Base.Interfaces;
|
|
using Qdp.Pricing.Library.Options.MonteCarlo;
|
|
using Qdp.Pricing.Library.Options.Products.Autocall.Phoenix;
|
|
using Qdp.Pricing.Library.Options.Products.Autocall.Phoenix.Numerical;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.CalcModules
|
|
{
|
|
/// <summary>
|
|
/// 凤凰期权计算测试
|
|
/// </summary>
|
|
[TestClass]
|
|
public class AutocalllOptionCalcTest : UnitTestBase
|
|
{
|
|
[TestMethod("看跌凤凰")]
|
|
public void SnowballOptionCalcTest1()
|
|
{
|
|
var ValueDate = new Date(2019, 11, 26);
|
|
var maturityDate = new Date(2020, 2, 24);
|
|
const double SPOT = 3899;
|
|
const double NOTIONAL = 1000000.0 / SPOT;
|
|
|
|
var tradeId = Guid.NewGuid().ToString();
|
|
|
|
var tdParam = new AutocallOptionTradeParam
|
|
{
|
|
annualizedFactor = 1,
|
|
annualizedOptionPayoff = false,
|
|
barrierStatus = null,
|
|
buysell = null,
|
|
callput = OptionType.Put,
|
|
coupon = 0.05,
|
|
couponBarrier = 1.05,
|
|
couponDayCount = "Act365",
|
|
couponPayAtMaturity = false,
|
|
dividendRate = 0.01,
|
|
dividends = null,
|
|
endDate = maturityDate,
|
|
exerciseDate = maturityDate,
|
|
exerciseType = "European",
|
|
happenedObservations = null,
|
|
hasNightMarket = false,
|
|
//includeCouponAfterKI = true,
|
|
initialSpotPrice = SPOT,
|
|
isAnnualized = false,
|
|
isFixedCoupon = false,
|
|
isForwardTrade = false,
|
|
isMoneynessOption = true,
|
|
kiBarrier = 1.05,
|
|
kiOptionType = "Call",
|
|
koBarrier = 0.8,
|
|
koObservationDateStr = "",
|
|
notional = NOTIONAL,
|
|
observationDateStr = "",
|
|
participationRate = 1,
|
|
preciseTimeMode = false,
|
|
principalRate = 0,
|
|
riskFreeRate = 0.05,
|
|
settlementDate = maturityDate,
|
|
strike = 1,
|
|
startDate = ValueDate,
|
|
timeToMaturityDays = double.NaN,
|
|
tradeDate = ValueDate,
|
|
tradeId = tradeId,
|
|
underlyingInstrumentType = ConsGlobal.InstrumentType.Stock,
|
|
underlyingTickers = new[] { "AAA9999" },
|
|
volSurfaceNames = new[] { tradeId }
|
|
};
|
|
|
|
using var market = new MarketProxy(ValueDate, 0.05);
|
|
market.SetStockPrice("AAA9999", SPOT);
|
|
market.SetVolSurface(tradeId, 0.2);
|
|
|
|
var val = TradeRiskCalcUtil.GetAutocallOptionValue(market, new OptionCalcParam<AutocallOptionTradeParam>(tdParam)
|
|
{
|
|
CalcDeltaT1 = false,
|
|
calcScenario = Enums.CalcScenarioEnum.Pricing,
|
|
engineName = null,
|
|
pricingRequest = PricingRequest.Pv,
|
|
quadratureFastMode = false,
|
|
spotPrices = new[] { SPOT }
|
|
});
|
|
|
|
//Assert.IsTrue(Math.Abs(val.Pv / -32652.810546875 - 1) < 0.01);
|
|
|
|
Assert.AreEqual((-32785 / val.Pv) - 1, 0, 1e-3);
|
|
}
|
|
|
|
[TestMethod("看跌凤凰")]
|
|
public void TestPhoenixPriceOfDownAndOut()
|
|
{
|
|
var ValueDate = new Date(2019, 11, 26);
|
|
var maturityDate = new Date(2020, 2, 24);
|
|
var Calendar = CalendarImpl.Get("chn");
|
|
IDayCount DayCount = new Bus252();
|
|
var InstrumentType = Qdp.Pricing.Base.Enums.InstrumentType.Stock;
|
|
const double VOL = 0.2;
|
|
const double SPOT = 3899;
|
|
const double RISK_FREE_RATE = 0.05;
|
|
const double DIVIDEND_RATE = 0.01;
|
|
const double NOTIONAL = 1000000.0 / SPOT;
|
|
|
|
var market = QdpTestHelper.CreateMarket(ValueDate, VOL, SPOT, RISK_FREE_RATE, DIVIDEND_RATE);
|
|
var newEngine = new QuadAutoCallEngine();
|
|
var mcEngine = new GbmMonteCarloEngine(1000000, 1e-3, 1e-6, 1);
|
|
|
|
var option2 = new AutoCall(
|
|
startDate: ValueDate,
|
|
maturityDate: maturityDate,
|
|
koBarrier: 0.8,
|
|
kiBarrier: 1.05,
|
|
couponBarrier: 1.05,
|
|
coupon: 0.05,
|
|
couponPayAtMaturity: false,
|
|
includeCouponAfterKI: true,
|
|
optionParticipationRate: 1.0,
|
|
koObsDates: QdpTestHelper.GenerateObservationDates(Calendar, ValueDate, maturityDate, new Term("1M"), BusinessDayConvention.Following),
|
|
kiObsDates: null,
|
|
observationDates: QdpTestHelper.GenerateObservationDates(Calendar, ValueDate, maturityDate),
|
|
notional: NOTIONAL,
|
|
initialSpotPrice: SPOT,
|
|
underlyingType: InstrumentType,
|
|
calendar: Calendar,
|
|
dayCount: DayCount,
|
|
payoffCcy: CurrencyCode.CNY,
|
|
settlementCcy: CurrencyCode.CNY,
|
|
exerciseDates: new Date[] { maturityDate },
|
|
exercise: OptionExercise.European,
|
|
optionType: OptionType.Put,
|
|
barrierType: BarrierType.DownAndOut,
|
|
strike: 1.0,
|
|
spreadStrike: 1.1,
|
|
annualizedOptionPayoff: false,
|
|
isMoneynessOption: true,
|
|
kiOptionType: OptionType.Call);
|
|
|
|
var json = Newtonsoft.Json.JsonConvert.SerializeObject(option2);
|
|
|
|
var mcPv2 = mcEngine.Calculate(option2, market, PricingRequest.Pv).Pv;
|
|
Assert.IsTrue(Math.Abs((mcPv2 / -32652.810546875) - 1) < 0.01);
|
|
|
|
var newPv2 = newEngine.Calculate(option2, market, PricingRequest.Pv).Pv;
|
|
Assert.AreEqual((-32737.653776411829 / newPv2) - 1, 0, 1e-3);
|
|
}
|
|
}
|
|
}
|