Files
zszq-trs/UnitTestProject/Modules/CalcModules/CalculationTest.cs
T
2025-04-21 15:15:08 +08:00

3029 lines
123 KiB
C#

using Qdp.Pricing.Base.Enums;
using Qdp.Pricing.Base.Implementations;
using YLErp.BLL.Calculation;
using YLErp.BLL.Calculation.V2;
using YLErp.BLL.Calculation.V2.Parameter;
using YLErp.DBModels.Enums;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.SkewMapVolModule;
using YLErp.OldVersion;
using YLErp.QdpModule;
using YLErp.QdpModule.Constants;
namespace YLErp.Modules.CalcModules
{
[TestClass]
public class CalculationTest
{
[TestMethod]
public void QuoteMaturityDateTest()
{
var maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2019, 11, 15), "RB1911");
Assert.AreEqual(new DateTime(2019, 11, 15), maturity, "RB1911");
maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2019, 12, 15), "RB1912");
Assert.AreEqual(new DateTime(2019, 12, 15), maturity, "RB1912");
maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2020, 01, 15), "RB2001");
Assert.AreEqual(new DateTime(2020, 1, 15), maturity, "RB2001");
maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2020, 02, 15), "RB2002");
Assert.AreEqual(new DateTime(2020, 2, 15), maturity, "RB2002");
maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2019, 10, 20), "SC1911");
Assert.AreEqual(new DateTime(2019, 11, 20), maturity, "SC1911");
maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2019, 11, 20), "SC1912");
Assert.AreEqual(new DateTime(2019, 12, 20), maturity, "SC1912");
maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2019, 12, 20), "SC2001");
Assert.AreEqual(new DateTime(2020, 1, 20), maturity, "SC2001");
maturity = CalculatorHelper.GetContractMaturityDateForQuote(new DateTime(2020, 1, 20), "SC2002");
Assert.AreEqual(new DateTime(2020, 2, 20), maturity, "SC2002");
}
[TestMethod]
public void CalendarTest()
{
var date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 15), 0);
Assert.AreEqual(new DateTime(2018, 6, 15), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 15), 1);
Assert.AreEqual(new DateTime(2018, 6, 19), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 16), 0);
Assert.AreEqual(new DateTime(2018, 6, 19), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 17), 0);
Assert.AreEqual(new DateTime(2018, 6, 19), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 18), 0);
Assert.AreEqual(new DateTime(2018, 6, 19), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 19), 0);
Assert.AreEqual(new DateTime(2018, 6, 19), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 16), 1);
Assert.AreEqual(new DateTime(2018, 6, 20), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 17), 1);
Assert.AreEqual(new DateTime(2018, 6, 20), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 18), 1);
Assert.AreEqual(new DateTime(2018, 6, 20), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 19), 1);
Assert.AreEqual(new DateTime(2018, 6, 20), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 16), -1);
Assert.AreEqual(new DateTime(2018, 6, 15), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 17), -1);
Assert.AreEqual(new DateTime(2018, 6, 15), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 18), -1);
Assert.AreEqual(new DateTime(2018, 6, 15), date, "");
date = QdpCalendarHelper.BizDayShift(new DateTime(2018, 6, 19), -1);
Assert.AreEqual(new DateTime(2018, 6, 15), date, "");
}
[TestMethod]
public void CalendarBLLTest()
{
var date20190705 = new DateTime(2019, 07, 05);
var date20190706 = new DateTime(2019, 07, 06);
var date20190707 = new DateTime(2019, 07, 07);
var date20190708 = new DateTime(2019, 07, 08);
#region IsHoliday
Assert.IsFalse(QdpCalendarHelper.IsHoliday(date20190705));
Assert.IsTrue(QdpCalendarHelper.IsHoliday(date20190706));
Assert.IsTrue(QdpCalendarHelper.IsHoliday(date20190707));
Assert.IsFalse(QdpCalendarHelper.IsHoliday(date20190708));
#endregion
#region GetWorkDayCount
Assert.AreEqual(0, QdpCalendarHelper.GetWorkDayCount(date20190705, date20190705));
Assert.AreEqual(1, QdpCalendarHelper.GetWorkDayCount(date20190705, date20190708));
#endregion
#region GetWorkingDay
Assert.AreEqual(new DateTime(2019, 7, 10), QdpCalendarHelper.GetWorkingDay(date20190705, 3));
Assert.AreEqual(new DateTime(2019, 6, 28), QdpCalendarHelper.GetWorkingDay(date20190705, -5));
#endregion
#region GetWrokingDatesBeforeDate
var dates = QdpCalendarHelper.GetWorkingDatesBeforeDate(date20190708, 7);
Assert.AreEqual(7, dates.Count);
Assert.AreEqual(date20190708, dates[0]);
Assert.AreEqual(new DateTime(2019, 6, 28), dates[6]);
#endregion
#region GetNonHolidayDaysBetween
Assert.AreEqual(0, QdpCalendarHelper.GetNonHolidayDaysBetween(date20190705, date20190705));
Assert.AreEqual(1, QdpCalendarHelper.GetNonHolidayDaysBetween(date20190705, date20190708));
#endregion
#region GetNonHoliday
Assert.AreEqual(date20190705, QdpCalendarHelper.GetNonHoliday(date20190705));
Assert.AreEqual(date20190708, QdpCalendarHelper.GetNonHoliday(date20190706));
Assert.AreEqual(date20190708, QdpCalendarHelper.GetNonHoliday(date20190707));
#endregion
#region GetNonHolidayBefore
Assert.AreEqual(date20190705, QdpCalendarHelper.GetNonHolidayDefore(date20190705));
Assert.AreEqual(date20190705, QdpCalendarHelper.GetNonHolidayDefore(date20190706));
Assert.AreEqual(date20190705, QdpCalendarHelper.GetNonHolidayDefore(date20190707));
Assert.AreEqual(date20190708, QdpCalendarHelper.GetNonHolidayDefore(date20190708));
#endregion
}
[TestMethod]
public void CalendarBLLGetNonHolidayDeforeTest()
{
var date20250421 = new DateTime(2025, 04, 21);
var date20250418 = new DateTime(2025, 04, 18);
var cudate = QdpCalendarHelper.GetNonHolidayDefore(date20250421.AddDays(0));
var preDate = QdpCalendarHelper.GetNonHolidayDefore(date20250421.AddDays(-1));
Assert.AreEqual(date20250421, cudate);
Assert.AreEqual(date20250418, preDate);
}
[TestMethod]
public void GetObservationDateStringTest()
{
var str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 8, 23), "1W", BusinessDayConvention.None);
Assert.AreEqual("2019-07-30,2019-08-06,2019-08-13,2019-08-20,2019-08-23", str);
str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 8, 23), "11D", BusinessDayConvention.Following);
Assert.AreEqual("2019-08-05,2019-08-14,2019-08-23", str);
str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 7, 30), "1W", BusinessDayConvention.ModifiedFollowing);
Assert.AreEqual("2019-07-30", str);
str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 7, 31), "1W", BusinessDayConvention.ModifiedFollowing);
Assert.AreEqual("2019-07-30,2019-07-31", str);
str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 8, 6), "1W", BusinessDayConvention.ModifiedFollowing);
Assert.AreEqual("2019-07-30,2019-08-06", str);
str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 8, 7), "1W", BusinessDayConvention.ModifiedFollowing);
Assert.AreEqual("2019-07-30,2019-08-06,2019-08-07", str);
str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 7, 29), "1D", BusinessDayConvention.Previous);
Assert.AreEqual("2019-07-24,2019-07-25,2019-07-26,2019-07-29", str);
str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 7, 29), "2D", BusinessDayConvention.Previous);
Assert.AreEqual("2019-07-25,2019-07-26,2019-07-29", str);
str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 7, 23), new DateTime(2019, 7, 29), "3D", BusinessDayConvention.Previous);
Assert.AreEqual("2019-07-26,2019-07-29", str);
str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 9, 11), new DateTime(2019, 12, 26), "1M", BusinessDayConvention.None);
Assert.AreEqual("2019-10-11,2019-11-11,2019-12-11,2019-12-26", str);
str = QdpObservationHelper.GetObservationDateString(new DateTime(2019, 9, 11), new DateTime(2019, 12, 26), "1M", BusinessDayConvention.None, true);
Assert.AreEqual("2019-09-26,2019-10-26,2019-11-26,2019-12-26", str);
}
#region GetOptionValueResultTest
/// <summary>
/// 在Bus244情况下测试通过
/// </summary>
[TestMethod]
public void GetOptionValueResultTest()
{
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
//var privateType = new PrivateType(typeof(VolSurfaceInitializerSingleton));
//privateType.SetStaticField("_volConstructionType", VolConstructionType.Normal);
//1. Normal mode, vol Surface
NormalVolWithSurfaceTest();
//2. Normal mode, trade vol
NormalVolWithTradeVolTest();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"true\"}");
//privateType = new PrivateType(typeof(VolSurfaceInitializerSingleton));
//privateType.SetStaticField("_volConstructionType", VolConstructionType.SkewMap);
PrepareGlobalSkewMap();
//3. SkewMap mode, vol surface
SkewMapVolWithSurfaceTest();
//4. SkewMap mode, trade vol
SkewMapVolWithTradeVolTest();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
//privateType = new PrivateType(typeof(VolSurfaceInitializerSingleton));
//privateType.SetStaticField("_volConstructionType", VolConstructionType.Normal);
}
private underlying_manager CreateTestUnderlying()
{
return new underlying_manager()
{
UnderlyingInstrumentType = "CommodityFutures",
UnderlyingCode = "RB1909",
MaturityDate = new DateTime(2019, 9, 15)
};
}
private trade CreateTestTrade()
{
return new trade()
{
TradeType = "香草期权",
Strike = 3050,
OptionType = "看涨",
ExerciseMode = "European",
ExerciseDate = new DateTime(2019, 7, 12),
UnderlyingCode = "RB1909",
UnderlyingInstrumentType = "CommodityFutures",
BuySell = "卖出",
MaturityDate = new DateTime(2019, 7, 12),
Notional = 1.0,
TTMDays = 22
};
}
private volatility CreateTestVolSurface()
{
return new volatility()
{
VolSurfaceMode = "MoneynessVol",
InterpolationMethod = ConsVolMethod.BiLinear,
Data = "[{\"Strike\":0.9,\"Expire\":\"1W\",\"Vol\":0.2152},{\"Strike\":0.95,\"Expire\":\"1W\",\"Vol\":0.2106},{\"Strike\":1.0,\"Expire\":\"1W\",\"Vol\":0.2077},{\"Strike\":1.05,\"Expire\":\"1W\",\"Vol\":0.2064},{\"Strike\":1.1,\"Expire\":\"1W\",\"Vol\":0.2066},{\"Strike\":0.9,\"Expire\":\"2W\",\"Vol\":0.2152},{\"Strike\":0.95,\"Expire\":\"2W\",\"Vol\":0.2106},{\"Strike\":1.0,\"Expire\":\"2W\",\"Vol\":0.2077},{\"Strike\":1.05,\"Expire\":\"2W\",\"Vol\":0.2064},{\"Strike\":1.1,\"Expire\":\"2W\",\"Vol\":0.2066},{\"Strike\":0.9,\"Expire\":\"1M\",\"Vol\":0.2152},{\"Strike\":0.95,\"Expire\":\"1M\",\"Vol\":0.2106},{\"Strike\":1.0,\"Expire\":\"1M\",\"Vol\":0.2077},{\"Strike\":1.05,\"Expire\":\"1M\",\"Vol\":0.2064},{\"Strike\":1.1,\"Expire\":\"1M\",\"Vol\":0.2066}]"
};
}
private void NormalVolWithSurfaceTest()
{
var underlying = CreateTestUnderlying();
var trade = CreateTestTrade();
var vol = CreateTestVolSurface();
var valueDateStr = "2019-06-13";
underlying.QuotationDate = DateTime.Parse(valueDateStr);
trade.StartDate = DateTime.Parse(valueDateStr);
var userId = Guid.NewGuid().ToString();
var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId);
var initParam = new VolSurfaceInitParamsBuilder(userId)
.SetUnderlying(underlying).SetVolatility(vol).SetValueDate(valueDateStr)
.Build(underlying.UnderlyingCode);
VolSurfaceInitializerSingleton.GetInitializer(false).InitializeMarketProxy(initParam);
var discountCurveName = Guid.NewGuid().ToString();
var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, 0.04);
marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve);
var result = OptionCalculatorV1.GetOptionValueResult(
userId,
underlying,
trade,
new double[] { 3000.0 },
fixing: null,
useTradeVolMode: false,
preciseTimeMode: false,
discountCurveName: discountCurveName);
QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userId);
Assert.AreEqual(0.20726666666666666, result.Vol, 1E-8, "NormalVolWithSurfaceTest Vol");
Assert.AreEqual(-52.53732559515695, result.Pv, 1E-8, "NormalVolWithSurfaceTest Pv");
Assert.AreEqual(-0.40892373614411781, result.Delta, 1E-8, "NormalVolWithSurfaceTest Delta");
Assert.AreEqual(-0.0020790010069049458, result.Gamma, 1E-8, "NormalVolWithSurfaceTest Gamma");
Assert.AreEqual(-3.4837223134672968, result.Vega, 1E-8, "NormalVolWithSurfaceTest Vega");
Assert.AreEqual(0.00047367584343049884, result.Rho, 1E-8, "NormalVolWithSurfaceTest Rho");
Assert.AreEqual(1.6504286616814952, result.Theta, 1E-8, "NormalVolWithSurfaceTest Theta");
}
private void NormalVolWithTradeVolTest()
{
var underlying = CreateTestUnderlying();
var trade = CreateTestTrade();
const double vol = 0.2075;
var volTable = new List<SingleVol>
{
new SingleVol
{
Strike = 1,
Expire = "1D",
Vol = vol
},
new SingleVol
{
Strike = 1,
Expire = "1Y",
Vol = vol
}
};
var valueDateStr = "2019-06-13";
underlying.QuotationDate = DateTime.Parse(valueDateStr);
trade.StartDate = DateTime.Parse(valueDateStr);
var userId = Guid.NewGuid().ToString();
var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId);
var initParam = new VolSurfaceInitParamsBuilder(userId)
.SetUnderlying(underlying).SetValueDate(valueDateStr)
.Build("MoneynessVol", volTable, trade.id.ToString());
VolSurfaceInitializerSingleton.GetInitializer(true).InitializeMarketProxy(initParam);
var discountCurveName = Guid.NewGuid().ToString();
var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, 0.04);
marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve);
var result = OptionCalculatorV1.GetOptionValueResult(
userId,
underlying,
trade,
new double[] { 3000.0 },
fixing: null,
useTradeVolMode: true,
preciseTimeMode: false,
discountCurveName: discountCurveName);
QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userId);
Assert.AreEqual(0.2075, result.Vol, 1E-8, "NormalVolWithTradeVolTest Vol");
Assert.AreEqual(-52.618615629338535, result.Pv, 1E-8, "NormalVolWithTradeVolTest Pv");
Assert.AreEqual(-0.40598319079236944, result.Delta, 1E-8, "NormalVolWithTradeVolTest Delta");
Assert.AreEqual(-0.0020691189206445415, result.Gamma, 1E-8, "NormalVolWithTradeVolTest Gamma");
Assert.AreEqual(-3.483994693558401, result.Vega, 1E-8, "NormalVolWithTradeVolTest Vega");
Assert.AreEqual(0.00047440875331972165, result.Rho, 1E-8, "NormalVolWithTradeVolTest Rho");
Assert.AreEqual(1.6524160238749488, result.Theta, 1E-8, "NormalVolWithTradeVolTest Theta");
}
private volatility CreateSkewMapBaseVolSurface()
{
return new volatility()
{
VolSurfaceMode = "MoneynessVol",
InterpolationMethod = ConsVolMethod.BiLinear,
Data = "[{\"Strike\":\"1.0000\",\"Expire\":\"1M\",\"Vol\":0.21},{\"Strike\":\"1.0000\",\"Expire\":\"3M\",\"Vol\":0.1937},{\"Strike\":\"1.0000\",\"Expire\":\"6M\",\"Vol\":0.1605},{\"Strike\":1,\"Expire\":\"AskVar\",\"Vol\":30},{\"Strike\":1,\"Expire\":\"BidVar\",\"Vol\":30}]"
};
}
private void PrepareGlobalSkewMap()
{
var data = File.ReadAllText("GlobalSkewMap.csv");
VolSkewMapInitializerSingleton.Instance.SetSkewMapData(data, isBuy: false);
}
private void SkewMapVolWithSurfaceTest()
{
var underlying = CreateTestUnderlying();
var trade = CreateTestTrade();
var vol = CreateSkewMapBaseVolSurface();
var valueDateStr = "2019-06-13";
underlying.QuotationDate = DateTime.Parse(valueDateStr);
trade.StartDate = DateTime.Parse(valueDateStr);
var userId = Guid.NewGuid().ToString();
var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId);
var initParam = new VolSurfaceInitParamsBuilder(userId)
.SetUnderlying(underlying).SetVolatility(vol).SetValueDate(valueDateStr)
.Build(underlying.UnderlyingCode);
VolSurfaceInitializerSingleton.GetInitializer(false).InitializeMarketProxy(initParam);
var discountCurveName = Guid.NewGuid().ToString();
var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, 0.04);
marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve);
var result = OptionCalculatorV1.GetOptionValueResult(
userId,
underlying,
trade,
new double[] { 3000.0 },
fixing: null,
useTradeVolMode: false,
preciseTimeMode: false,
discountCurveName: discountCurveName);
QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userId);
Assert.AreEqual(0.27703706146327278, result.Vol, 1E-8, "SkewMapVolWithSurfaceTest Vol");
Assert.AreEqual(-77.05603142631152, result.Pv, 1E-8, "SkewMapVolWithSurfaceTest Pv");
Assert.AreEqual(-0.43601254203338158, result.Delta, 1E-8, "SkewMapVolWithSurfaceTest Delta");
Assert.AreEqual(-0.0015732894098619, result.Gamma, 1E-8, "SkewMapVolWithSurfaceTest Gamma");
Assert.AreEqual(-3.5368906374252163, result.Vega, 1E-8, "SkewMapVolWithSurfaceTest Vega");
Assert.AreEqual(0.000694736175923083, result.Rho, 1E-8, "SkewMapVolWithSurfaceTest Rho");
Assert.AreEqual(2.2395635945358663, result.Theta, 1E-8, "SkewMapVolWithSurfaceTest Theta");
}
private void SkewMapVolWithTradeVolTest()
{
var underlying = CreateTestUnderlying();
var trade = CreateTestTrade();
const double vol = 0.2075;
var volTable = new List<SingleVol>
{
new SingleVol
{
Strike = 1,
Expire = "1D",
Vol = vol
},
new SingleVol
{
Strike = 1,
Expire = "1Y",
Vol = vol
}
};
var valueDateStr = "2019-06-13";
underlying.QuotationDate = DateTime.Parse(valueDateStr);
trade.StartDate = DateTime.Parse(valueDateStr);
var userId = Guid.NewGuid().ToString();
var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(userId);
var initParam = new VolSurfaceInitParamsBuilder(userId)
.SetUnderlying(underlying).SetValueDate(valueDateStr)
.Build("MoneynessVol", volTable, trade.id.ToString());
VolSurfaceInitializerSingleton.GetInitializer(true).InitializeMarketProxy(initParam);
var discountCurveName = Guid.NewGuid().ToString();
var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, 0.04);
marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve);
var result = OptionCalculatorV1.GetOptionValueResult(
userId,
underlying,
trade,
new double[] { 3000.0 },
fixing: null,
useTradeVolMode: true,
preciseTimeMode: false,
discountCurveName: discountCurveName);
QdpMarketManager.Instance.RemovePrebuiltMarketProxy(userId);
Assert.AreEqual(0.2075, result.Vol, 1E-8, "SkewMapVolWithSurfaceTest Vol");
Assert.AreEqual(-52.618615629338535, result.Pv, 1E-8, "SkewMapVolWithSurfaceTest Pv");
Assert.AreEqual(-0.40598319079236944, result.Delta, 1E-8, "SkewMapVolWithSurfaceTest Delta");
Assert.AreEqual(-0.0020691189206445415, result.Gamma, 1E-8, "SkewMapVolWithSurfaceTest Gamma");
Assert.AreEqual(-3.483994693558401, result.Vega, 1E-8, "SkewMapVolWithSurfaceTest Vega");
Assert.AreEqual(0.00047440875331972165, result.Rho, 1E-8, "SkewMapVolWithSurfaceTest Rho");
Assert.AreEqual(1.6524160238749488, result.Theta, 1E-8, "SkewMapVolWithSurfaceTest Theta");
}
#endregion
/// <summary>
/// 商品期货交易手续费测试
/// </summary>
[TestMethod]
public void CommodityFuturesCommissionTest()
{
underlying_manager rb1910 = null, m1908 = null, ru1907 = null;
using (var db = new YLContext())
{
rb1910 = db.underlying_manager.FirstOrDefault(x => x.UnderlyingCode == "RB1910");
m1908 = db.underlying_manager.FirstOrDefault(x => x.UnderlyingCode == "M1908");
ru1907 = db.underlying_manager.FirstOrDefault(x => x.UnderlyingCode == "RU1907");
}
Assert.IsNotNull(rb1910, "rb1910 null");
Assert.IsNotNull(rb1910, "m1908 null");
Assert.IsNotNull(ru1907, "RU1907 null");
#region 按比例收取手续费
var trades = new List<ExchangeTrade>() {
new ExchangeTrade() {
id = 1,
UnderlyingCode = "RB1910",
TradeSide = "多头开仓",
Notional = 1000,
TradeSinglePrice = 4000,
CommissionType = CommissionType.系统计算
},
new ExchangeTrade() {
id = 2,
UnderlyingCode = "RB1910",
TradeSide = "多头平仓",
Notional = 800,
TradeSinglePrice = 4100,
CommissionType = CommissionType.系统计算
},
new ExchangeTrade() {
id = 3,
UnderlyingCode = "RB1910",
TradeSide = "多头开仓",
Notional = 1000,
TradeSinglePrice = 4200,
CommissionType = CommissionType.系统计算
},
new ExchangeTrade() {
id = 4,
UnderlyingCode = "RB1910",
TradeSide = "多头平仓",
Notional = 100,
TradeSinglePrice = 4250,
CommissionType = CommissionType.不收取 //这笔不会计算手续费
},
new ExchangeTrade() {
id = 5,
UnderlyingCode = "RB1910",
TradeSide = "多头平仓",
Notional = 1300,
TradeSinglePrice = 4150,
CommissionType = CommissionType.系统计算
}
};
var commissions = CommissionCalcHelper.GetCommissionForTrade(rb1910, trades);
Assert.AreEqual(4, commissions.Count, "RB1910 commissions count");
Assert.AreEqual(2000, commissions[1], 1e-8, "RB1910 trade 1 commission");
Assert.AreEqual(1640, commissions[2], 1e-8, "RB1910 trade 2 commission");
Assert.AreEqual(2100, commissions[3], 1e-8, "RB1910 trade 3 commission");
Assert.AreEqual(2697.5, commissions[5], 1e-8, "RB1910 trade 3 commission");
#endregion
#region 按固定收取手续费
trades = new List<ExchangeTrade>() {
new ExchangeTrade() {
id = 1,
UnderlyingCode = "M1908",
TradeSide = "多头开仓",
Notional = 1000,
TradeSinglePrice = 2800,
CommissionType = CommissionType.系统计算
},
new ExchangeTrade() {
id = 2,
UnderlyingCode = "M1908",
TradeSide = "多头平仓",
Notional = 800,
TradeSinglePrice = 2800,
CommissionType = CommissionType.系统计算
},
new ExchangeTrade() {
id = 3,
UnderlyingCode = "M1908",
TradeSide = "多头开仓",
Notional = 1000,
TradeSinglePrice = 2800,
CommissionType = CommissionType.系统计算
},
new ExchangeTrade() {
id = 4,
UnderlyingCode = "M1908",
TradeSide = "多头平仓",
Notional = 100,
TradeSinglePrice = 2800,
CommissionType = CommissionType.不收取 //这笔不会计算手续费
},
new ExchangeTrade() {
id = 5,
UnderlyingCode = "M1908",
TradeSide = "多头平仓",
Notional = 1300,
TradeSinglePrice = 2800,
CommissionType = CommissionType.系统计算
}
};
commissions = CommissionCalcHelper.GetCommissionForTrade(m1908, trades);
Assert.AreEqual(4, commissions.Count, "M1908 commissions count");
Assert.AreEqual(150, commissions[1], 1e-8, "M1908 trade 1 commission");
Assert.AreEqual(120, commissions[2], 1e-8, "M1908 trade 2 commission");
Assert.AreEqual(150, commissions[3], 1e-8, "M1908 trade 3 commission");
Assert.AreEqual(195, commissions[5], 1e-8, "M1908 trade 3 commission");
#endregion
#region 带有平今仓手续费规则
trades = new List<ExchangeTrade>() {
new ExchangeTrade() {
id = 1,
UnderlyingCode = "RU1909",
TradeSide = "多头开仓",
Notional = 1000,
TradeSinglePrice = 12000,
CommissionType = CommissionType.系统计算
},
new ExchangeTrade() {
id = 2,
UnderlyingCode = "RU1909",
TradeSide = "多头平仓",
Notional = 800,
TradeSinglePrice = 11000,
CommissionType = CommissionType.系统计算
},
new ExchangeTrade() {
id = 3,
UnderlyingCode = "RU1909",
TradeSide = "多头开仓",
Notional = 1000,
TradeSinglePrice = 11500,
CommissionType = CommissionType.系统计算
},
new ExchangeTrade() {
id = 4,
UnderlyingCode = "RU1909",
TradeSide = "多头平仓",
Notional = 100,
TradeSinglePrice = 13000,
CommissionType = CommissionType.不收取 //这笔不会计算手续费
},
new ExchangeTrade() {
id = 5,
UnderlyingCode = "RU1909",
TradeSide = "多头平仓",
Notional = 1300,
TradeSinglePrice = 12500,
CommissionType = CommissionType.系统计算
}
};
commissions = CommissionCalcHelper.GetCommissionForTrade(ru1907, trades);
Assert.AreEqual(4, commissions.Count, "RU1909 commissions count");
Assert.AreEqual(540, commissions[1], 1e-8, "RU1909 trade 1 commission");
Assert.AreEqual(160, commissions[2], 1e-8, "RU1909 trade 2 commission");
Assert.AreEqual(517.5, commissions[3], 1e-8, "RU1909 trade 3 commission");
Assert.AreEqual(296.25, commissions[5], 1e-8, "RU1909 trade 3 commission");
#endregion
}
[TestMethod]
public void CommodityFutureOptionMarginTest()
{
double premium = 45,
amount = 3,
strike = 4000,
futureMarginRatio = 0.09;
var optionType = "Call";
#region Call
//InTheMoney
double spotPrice = 4100;
var benchmark = premium + spotPrice * amount * futureMarginRatio;
var margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType);
Assert.AreEqual(benchmark, margin, double.Epsilon);
//AtTheMoney
spotPrice = 4000;
benchmark = premium + (spotPrice * amount * futureMarginRatio);
margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType);
Assert.AreEqual(benchmark, margin, double.Epsilon);
//OutTheMoney and Value < futureMargin
spotPrice = 3900;
benchmark = premium + (spotPrice * amount * futureMarginRatio) - ((strike - spotPrice) * amount * 0.5);
margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType);
Assert.AreEqual(benchmark, margin, double.Epsilon);
//OutTheMoney and Value > futureMargin
spotPrice = 3500;
benchmark = premium + (spotPrice * amount * futureMarginRatio * 0.5);
margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType);
Assert.AreEqual(benchmark, margin, double.Epsilon);
#endregion
#region Put
optionType = "Put";
//InTheMoney
spotPrice = 3900;
benchmark = premium + (spotPrice * amount * futureMarginRatio);
margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType);
Assert.AreEqual(benchmark, margin, double.Epsilon);
//AtTheMoney
spotPrice = 4000;
benchmark = premium + (spotPrice * amount * futureMarginRatio);
margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType);
Assert.AreEqual(benchmark, margin, double.Epsilon);
//OutTheMoney and Value < futureMargin
spotPrice = 4100;
benchmark = premium + (spotPrice * amount * futureMarginRatio) - ((spotPrice - strike) * amount * 0.5);
margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType);
Assert.AreEqual(benchmark, margin, double.Epsilon);
//OutTheMoney and Value > futureMargin
spotPrice = 4500;
benchmark = premium + (spotPrice * amount * futureMarginRatio * 0.5);
margin = OptionCalculatorV1.CommodityFutureOptionMargin(premium, amount, strike, spotPrice, futureMarginRatio, optionType);
Assert.AreEqual(benchmark, margin, double.Epsilon);
#endregion
}
[TestMethod]
public void ValueVanillaOptionWithVolSettingTest()
{
var valueDate = new DateTime(2019, 4, 4);
var underlyingTicker = "RB00";
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.2
});
}
}
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
TradeValueResult result = null;
using (var mp = new MarketProxy(valueDate, 0.035))
{
var tradeParam = new VanillaOptionTradeParam
{
underlyingTickers = new[] { underlyingTicker },
underlyingInstrumentType = "CommodityFutures",
strike = 2900.0,
startDate = valueDate,
endDate = new DateTime(2019, 05, 06),
optionType = OptionType.Call,// "Call",
exerciseType = "European",
initialSpotPrice = 2900.0,
notional = 100.0,
volSurfaceNames = new[] { underlyingTicker + "_VolSurface" },
riskFreeRate = 0.035,
buysell = "Buy",
exerciseDate = new DateTime(2019, 05, 06),
dividendRate = 0,
timeToMaturityDays = 18,
participationRate = 1.0,
principalRate = 0.0,
isAnnualized = false,
annualizedFactor = 1.0,
preciseTimeMode = false,
};
mp.SetVolSurface(tradeParam.volSurfaceNames[0], new VolatilityImpl { VolTable = singleVols });
result = TradeRiskCalcUtil.GetVanillaOptionValue(mp, new OptionCalcParam<VanillaOptionTradeParam>(tradeParam)
{
spotPrices = new[] { 2900.0 }
});
}
//var initParam = new VolSurfaceInitParamsBuilder()
// .SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols);
//new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam);
//计算
//result = OptionCalculator.ValueVanillaOptionTrade(
// marketProxy: marketProxy,
// valueDate: valueDate + "",
// underlyingTicker: underlyingTicker,
// underlyingInstrumentType: "CommodityFutures",
// strike: 2900.0,
// startDate: valueDate + "",
// endDate: "2019-05-06",
// optionType: "Call",
// exerciseType: "European",
// spotPrice: 2900.0,
// notional: 100.0,
// volSurfaceName: underlyingTicker + "_VolSurface",
// riskFreeRate: 0.035,
// modelName: null,
// tradeType: "Buy",
// exerciseDate: "2019-05-06",
// dividendRate: 0,
// timeToMaturityDays: 18,
// ignoreSkewMap: true,
// participationRate: 1.0,
// principalRate: 0.0,
// isAnnualized: false,
// annualizeFactor: 1.0);
Assert.AreEqual(6267.6490467250824, result.Pv, 1E-8, "");
Assert.AreEqual(50.9516973058509, result.Delta, 1E-8, "");
Assert.AreEqual(0.25249779355362989, result.Gamma, 1E-8, "");
Assert.AreEqual(313.305398649345, result.Vega, 1E-8, "");
Assert.AreEqual(-175.67364449584602, result.Theta, 1E-8, "");
//Assert.AreEqual(-0.04623504985065665, result.Rho, 1E-8, "");
}
[TestMethod]
public void ValueVanillaOptionWithVolSettingTestV2()
{
var valueDate = "2019-04-04";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var trade = new trade()
{
TradeType = "香草期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 2900,
Notional = 100
};
var parameter = new VanillaOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 2900 } },
OverrideTTM = 18,
RiskFreeRate = 0.035
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(6267.6490467250824, result.Pv, 1E-8, "");
Assert.AreEqual(50.95295979454022, result.Delta, 1E-8, "");
Assert.AreEqual(0.25249779355362989, result.Gamma, 1E-8, "");
Assert.AreEqual(313.305398649345, result.Vega, 1E-8, "");
Assert.AreEqual(-175.67364449584602, result.Theta, 1E-8, "");
Assert.AreEqual(-0.04623504985065665, result.Rho, 1E-8, "");
}
/// <summary>
/// 在期权定价时调整定价日
/// </summary>
private DateTime AdjustQuotationDate(DateTime quotationDate, string tradeType)
{
// 对凤凰雪球不做报价日调整
if (tradeType == "雪球期权" || tradeType == "凤凰期权")
{
return quotationDate;
}
//为了暂时修复一个QDP计算方式与客户需求不匹配的情况
//在非精确模式下,QDP不包括交易日当天的时间价值,但根据报价需求,需要将交易日当天的时间价值计算在内,
//所以要将交易日向前移动一天。未来QDP支持传递TTM来计算时,可以直接在TTM上加1,而不用移动交易日
//注意:当前这个临时修改必须在波动率插值之前调用,这样才能正确设置波动率日期
var calendar = CalendarImpl.Get("chn");
return calendar.PrevBizDay(quotationDate).DateTime;
}
[TestMethod]
public void ValueBarrierOptionTest()
{
var valueDate = new DateTime(2019, 04, 04);
var underlyingTicker = "RB00";
TradeValueResult result;
if (valueDate != valuedateBLL.ValueDate.Date)
{
valueDate = AdjustQuotationDate(valueDate, "障碍期权");
}
var tradeId = Guid.NewGuid().ToString();
using (var mp = new MarketProxy(valueDate, 0.035))
{
var vols = QdpVolHelper.GetDefaultVolatility(0.2);
mp.SetVolSurface(tradeId, vols);
var tdParam = new BarrierOptionTradeParam
{
underlyingTickers = new[] { underlyingTicker },
underlyingInstrumentType = "CommodityFutures",
strike = 2900.0,
startDate = valueDate,
endDate = new DateTime(2024, 2, 5),
optionType = OptionType.Call,
exerciseType = "European",
barrierType = "UpAndOut",
barrierPrice = 3000.0,
upperBarrierPrice = 0.0,
isDiscrete = true,
initialSpotPrice = 2900.0,
rebate = 20.0,
notional = 100.0,
volSurfaceNames = new[] { tradeId },
riskFreeRate = 0.035,
buysell = "Buy",
exerciseDate = new DateTime(2019, 05, 06),
rebateType = "AtHit",
observationDateStr = "2019-04-09,2019-04-16,2019-04-23,2019-04-29,2019-05-06",
dividendRate = 0.0,
barrierShift = 0.0,
participationRate = 1.0,
principalRate = 0.0,
isAnnualized = false,
annualizedFactor = 1.0,
rebateAnnualizedAtKO = false,
rebateDayCount = "",
timeToMaturityDays = 19
};
result = TradeRiskCalcUtil.GetBarrierOptionValue(mp, new OptionCalcParam<BarrierOptionTradeParam>(tdParam)
{
spotPrices = new[] { tdParam.initialSpotPrice },
quadratureFastMode = true
});
}
Assert.AreEqual(1439.9127764086413, result.Pv, 1E-8, "");
Assert.AreEqual(5.1646784276044855, result.Delta, 1E-8, "");
Assert.AreEqual(-0.016520966710231733, result.Gamma, 1E-8, "");
Assert.AreEqual(-17.501027350181175, result.Vega, 1E-8, "");
Assert.AreEqual(10.403561845246486, result.Theta, 1E-8, "");
Assert.AreEqual(0.12190782245161244, result.Rho, 1E-8, "");
}
[TestMethod]
public void ValueBarrierOptionTestV2()
{
var valueDate = "2019-04-04";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var trade = new trade()
{
TradeType = "障碍期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 2900.0,
Notional = 100,
trade_barrier_option = new trade_barrier_option()
{
BarrierType = "上升敲出",
BarrierPrice = 3000.0,
BarrierShift = 0.0,
Discrete = "离散",
Rebate = 20.0,
KnockInOutStatus = "Monitoring"
}
};
var parameter = new BarrierOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 2900.0 } },
RiskFreeRate = 0.035
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(1353.9894515364406, result.Pv, 1E-8, "");
Assert.AreEqual(5.6636792255631008, result.Delta, 1E-8, "");
Assert.AreEqual(-0.0058651176004786976, result.Gamma, 1E-8, "");
Assert.AreEqual(-2.900013280566327, result.Vega, 1E-8, "");
Assert.AreEqual(4.7292177906094821, result.Theta, 1E-8, "");
Assert.AreEqual(-0.0035508358797642359, result.Rho, 1E-8, "");
//双障碍
trade = new trade()
{
TradeType = "障碍期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 130.0,
Notional = 100,
trade_barrier_option = new trade_barrier_option()
{
BarrierType = "DoubleTouchOut",
BarrierPrice = 100.0,
UpperBarrierPrice = 144.0,
BarrierShift = 0.0,
Discrete = "离散",
Rebate = 20.0,
KnockInOutStatus = "Monitoring"
}
};
parameter = new BarrierOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 120.0 } },
RiskFreeRate = 0.035
};
result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(31.52299607431015, result.Pv, 1E-8, "");
Assert.AreEqual(8.7249908156710632, result.Delta, 1E-8, "");
Assert.AreEqual(2.989637326322736, result.Gamma, 1E-8, "");
Assert.AreEqual(7.0000209372153677, result.Vega, 1E-8, "");
Assert.AreEqual(-3.570910197936211, result.Theta, 1E-8, "");
Assert.AreEqual(0.00835458118292216, result.Rho, 1E-8, "");
//KIKO
trade = new trade()
{
TradeType = "障碍期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 145,
Notional = 100,
trade_barrier_option = new trade_barrier_option()
{
BarrierType = "KIKO",
BarrierPrice = 146,
UpperBarrierPrice = 148,
BarrierShift = 0.0,
Discrete = "离散",
Rebate = 20.0,
KnockInOutStatus = "Monitoring"
}
};
parameter = new BarrierOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 146.9 } },
RiskFreeRate = 0.035
};
result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(-414.20440415099324, result.Pv, 1E-8, "");
Assert.AreEqual(186.12515246873045, result.Delta, 1E-8, "");
Assert.AreEqual(5.5092195839279157, result.Gamma, 1E-8, "");
Assert.AreEqual(9.4165577108014986, result.Vega, 1E-8, "");
Assert.AreEqual(-10.397275659495108, result.Theta, 1E-8, "");
Assert.AreEqual(0.01632015110478733, result.Rho, 1E-8, "");
//自定义观察日
trade = new trade()
{
TradeType = "障碍期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 2900.0,
Notional = 100,
trade_barrier_option = new trade_barrier_option()
{
BarrierType = "上升敲出",
BarrierPrice = 3000.0,
BarrierShift = 0.0,
Discrete = "离散",
Rebate = 20.0,
KnockInOutStatus = "Monitoring",
ObservationDates = "2019-04-09,2019-04-16,2019-04-23,2019-04-29,2019-05-06"
}
};
parameter = new BarrierOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 2900.0 } },
RiskFreeRate = 0.035
};
result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(1439.9127764086413, result.Pv, 1E-8, "");
Assert.AreEqual(5.1646784276044855, result.Delta, 1E-8, "");
Assert.AreEqual(-0.016520966710231733, result.Gamma, 1E-8, "");
Assert.AreEqual(-17.501027350181175, result.Vega, 1E-8, "");
Assert.AreEqual(10.403561845246486, result.Theta, 1E-8, "");
Assert.AreEqual(0.12190782245161244, result.Rho, 1E-8, "");
}
[TestMethod]
public void ValueAsianOptionTest()
{
var valueDate = "2019-04-04";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker
};
//创建默认市场,并设置波动率曲面
var marketProxy = new PrebuiltQdpMarketProxy();
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.2
});
}
}
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var initParam = new VolSurfaceInitParamsBuilder()
.SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols);
new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam);
var result = OptionCalculatorV1.ValueAsianOptionTrade(
marketProxy,
valueDate,
underlyingTicker,
"CommodityFutures",
2900.0,
valueDate,
"2019-05-06",
"Call",
"European",
"ArithmeticAverage",
"Fixed",
2900.0,
100.0,
underlyingTicker + "_VolSurface",
0.035,
"Buy",
"2019-05-06",
isAnnualized: false,
annualizeFactor: 1.0,
dividendRate: 0.0,
fixings: "2019-04-01,2850;2019-04-02,2855;2019-04-03,2899",
averagingPeriodStartDate: "2019-04-01",
ignoreSkewMap: true);
Assert.AreEqual(3164.92251559125, result.Pv, 1E-8, "");
Assert.AreEqual(44.185302306550511, result.Delta, 1E-8, "");
Assert.AreEqual(0.38820497138658538, result.Gamma, 1E-8, "");
Assert.AreEqual(165.84751675402458, result.Vega, 1E-8, "");
Assert.AreEqual(-294.4723867871885, result.Theta, 1E-8, "");
Assert.AreEqual(-0.02594092466551956, result.Rho, 1E-8, "");
//增强型
result = OptionCalculatorV1.ValueAsianOptionTrade(
marketProxy,
valueDate,
underlyingTicker,
"CommodityFutures",
2900.0,
valueDate,
"2019-05-06",
"Call",
"European",
"EnhancedArithmeticAverage",
"Fixed",
2900.0,
100.0,
underlyingTicker + "_VolSurface",
0.035,
"Buy",
"2019-05-06",
isAnnualized: false,
annualizeFactor: 1.0,
dividendRate: 0.0,
fixings: "",
averagingPeriodStartDate: "2019-04-04",
ignoreSkewMap: true);
Assert.AreEqual(4341.7462907276122, result.Pv, 1E-8, "");
Assert.AreEqual(53.059818666679348, result.Delta, 1E-8, "");
Assert.AreEqual(476.57855693614692, result.Gamma, 1E-8, "");
Assert.AreEqual(217.05074145074832, result.Vega, 1E-8, "");
Assert.AreEqual(-314.50937525089466, result.Theta, 1E-8, "");
Assert.AreEqual(-0.021944944954884704, result.Rho, 1E-8, "");
}
[TestMethod]
public void ValueAsianOptionTestV2()
{
var valueDate = "2019-04-04";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var trade = new trade()
{
TradeType = "亚式期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 2900.0,
Notional = 100,
trade_asian_option = new trade_asian_option()
{
PayoffType = "ArithmeticAverage",
StrikeType = "Fixed",
AveragingPeriodStartDate = new DateTime(2019, 4, 1)
}
};
var parameter = new AsianOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 2900.0 } },
RiskFreeRate = 0.035,
Fixings = "2019-04-01,2850;2019-04-02,2855;2019-04-03,2899"
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(3164.92251559125, result.Pv, 1E-8, "");
Assert.AreEqual(44.185302306550511, result.Delta, 1E-8, "");
Assert.AreEqual(0.38820497138658538, result.Gamma, 1E-8, "");
Assert.AreEqual(165.84751675402458, result.Vega, 1E-8, "");
Assert.AreEqual(-294.4723867871885, result.Theta, 1E-8, "");
Assert.AreEqual(-0.02594092466551956, result.Rho, 1E-8, "");
//增强型
trade = new trade()
{
TradeType = "亚式期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 2900.0,
Notional = 100,
trade_asian_option = new trade_asian_option()
{
PayoffType = "EnhancedArithmeticAverage",
StrikeType = "Fixed",
AveragingPeriodStartDate = new DateTime(2019, 4, 4)
}
};
parameter = new AsianOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 2900.0 } },
RiskFreeRate = 0.035,
Fixings = ""
};
result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(4341.7462907276122, result.Pv, 1E-8, "");
Assert.AreEqual(53.059818666679348, result.Delta, 1E-8, "");
Assert.AreEqual(476.57855693614692, result.Gamma, 1E-8, "");
Assert.AreEqual(217.05074145074832, result.Vega, 1E-8, "");
Assert.AreEqual(-314.50937525089466, result.Theta, 1E-8, "");
Assert.AreEqual(-0.021944944954884704, result.Rho, 1E-8, "");
}
[TestMethod]
public void ValueBinaryOptionTest()
{
TradeValueResult result;
var valueDate = new DateTime(2019, 04, 04);
var underlyingTicker = "RB00";
var vol = QdpVolHelper.GetDefaultVolatility(0.2);
var valueDateStr = "2019-04-04";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDateStr),
UnderlyingCode = underlyingTicker
};
//创建默认市场,并设置波动率曲面
var marketProxy = new PrebuiltQdpMarketProxy();
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.2
});
}
}
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var initParam = new VolSurfaceInitParamsBuilder()
.SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols);
new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam);
result = OptionCalculatorV1.ValueBinaryOptionTrade(
marketProxy,
valueDateStr,
underlyingTicker,
"CommodityFutures",
2900.0,
valueDateStr,
"2019-05-06",
"Call",
"European",
"CashOrNothing", //payoffType
200.0,
2900.0,
100.0,
underlyingTicker + "_VolSurface",
0.035,
"Buy",
"2019-05-06",
dividendRate: 0.0,
binaryRebateType: "AtHit",
binaryOptionReplicationStrategy: "None",
replicationShiftSize: 0.0,
ignoreSkewMap: true,
participationRate: 1.0,
principalRate: 0.0,
isAnnualized: false,
annualizeFactor: 1.0);
Assert.AreEqual(9743.6044193724756, result.Pv, 1E-8, "");
Assert.AreEqual(47.892520332243294, result.Delta, 1E-8, "");
Assert.AreEqual(-0.0082573751569725573, result.Gamma, 1E-8, "");
Assert.AreEqual(-11.384297440145019, result.Vega, 1E-8, "");
Assert.AreEqual(7.1637717615885776, result.Theta, 1E-8, "");
Assert.AreEqual(-0.079862336903534017, result.Rho, 1E-8, "");
var tradeId = Guid.NewGuid().ToString();
using var mp = new MarketProxy(valueDate, 0.035);
mp.SetVolSurface(tradeId, vol);
var tdParam = new BinaryOptionTradeParam
{
underlyingTickers = new[] { underlyingTicker },
underlyingInstrumentType = "CommodityFutures",
strike = 2900.0,
startDate = valueDate,
endDate = new DateTime(2019, 05, 06),
optionType = OptionType.Call,
exerciseType = "European",
payoffType = "CashOrNothing", //payoffType
cashOrNothingAmount = 200.0,
initialSpotPrice = 2900.0,
notional = 100.0,
volSurfaceNames = new[] { tradeId },
riskFreeRate = 0.035,
buysell = "Buy",
exerciseDate = new DateTime(2019, 05, 06),
dividendRate = 0.0,
binaryRebateType = "AtHit",
binaryOptionReplicationStrategy = "None",
replicationShiftSize = 0.0,
participationRate = 1.0,
principalRate = 0.0,
isAnnualized = false,
annualizedFactor = 1.0
};
result = TradeRiskCalcUtil.GetBinaryOptionValue(mp, new OptionCalcParam<BinaryOptionTradeParam>(tdParam)
{
spotPrices = new[] { 2900d }
});
Assert.AreEqual(9743.6044193724756, result.Pv, 1E-8, "");
Assert.AreEqual(47.892520332243294, result.Delta, 1E-8, "");
Assert.AreEqual(-0.0082573751569725573, result.Gamma, 1E-8, "");
Assert.AreEqual(-11.384297440145019, result.Vega, 1E-8, "");
Assert.AreEqual(7.1637717615885776, result.Theta, 1E-8, "");
Assert.AreEqual(-0.079862336903534017, result.Rho, 1E-8, "");
tdParam = new BinaryOptionTradeParam
{
underlyingTickers = new[] { underlyingTicker },
underlyingInstrumentType = "CommodityFutures",
strike = 2900.0,
startDate = valueDate,
endDate = new DateTime(2019, 05, 06),
optionType = OptionType.Call,
exerciseType = "European",
payoffType = "CashOrNothing", //payoffType
cashOrNothingAmount = 200.0,
initialSpotPrice = 2900.0,
notional = 100.0,
volSurfaceNames = new[] { tradeId },
riskFreeRate = 0.035,
buysell = "Buy",
exerciseDate = new DateTime(2019, 05, 06),
dividendRate = 0.0,
binaryRebateType = "AtHit",
binaryOptionReplicationStrategy = "Down",
replicationShiftSize = 0.0,
participationRate = 1.0,
principalRate = 0.0,
isAnnualized = false,
annualizedFactor = 1.0
};
result = TradeRiskCalcUtil.GetBinaryOptionValue(mp, new OptionCalcParam<BinaryOptionTradeParam>(tdParam)
{
spotPrices = new[] { 2900d },
engineName = "AnalyticalBinaryEuropeanOptionReplicationEngine"
});
Assert.AreEqual(10439.754311151559, result.Pv, 1E-8, "");
Assert.AreEqual(47.767642553136, result.Delta, 1E-8, "");
Assert.AreEqual(-0.033387487778311659, result.Gamma, 1E-8, "");
Assert.AreEqual(-46.042248515481454, result.Vega, 1E-8, "");
Assert.AreEqual(0, result.Theta, 1E-8, "");
Assert.AreEqual(-0.085568249705202437, result.Rho, 1E-8, "");
//美式二元
tdParam = new BinaryOptionTradeParam
{
underlyingTickers = new[] { underlyingTicker },
underlyingInstrumentType = "CommodityFutures",
strike = 950.0,
startDate = valueDate,
endDate = new DateTime(2019, 05, 06),
optionType = OptionType.Call,
exerciseType = "American",
payoffType = "DoubleOneTouch", //payoffType
cashOrNothingAmount = 200.0,
initialSpotPrice = 990.0,
notional = 100.0,
volSurfaceNames = new[] { tradeId },
riskFreeRate = 0.035,
buysell = "Buy",
exerciseDate = new DateTime(2019, 05, 06),
upperBarrier = 1100.0,
dividendRate = 0.0,
binaryRebateType = "AtHit",
binaryOptionReplicationStrategy = "Down",
replicationShiftSize = 0.0,
participationRate = 1.0,
principalRate = 0.0,
isAnnualized = false,
annualizedFactor = 1.0
};
result = TradeRiskCalcUtil.GetBinaryOptionValue(mp, new OptionCalcParam<BinaryOptionTradeParam>(tdParam)
{
spotPrices = new[] { 990.0 }
});
Assert.AreEqual(10835.184736140083, result.Pv, 1E-8, "");
Assert.AreEqual(-165.90143058310787, result.Delta, 1E-8, "");
Assert.AreEqual(4.3446263953228481, result.Gamma, 1E-8, "");
Assert.AreEqual(696.36722659533916, result.Vega, 1E-8, "");
Assert.AreEqual(-354.58732062354829, result.Theta, 1E-8, "");
Assert.AreEqual(-0.040437084736549875, result.Rho, 1E-8, "");
}
[TestMethod]
public void ValueBinaryOptionTestV2()
{
var valueDate = "2019-04-04";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var trade = new trade()
{
TradeType = "二元期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 2900.0,
Notional = 100,
trade_binary_option = new trade_binary_option()
{
PayoffType = "CashOrNothing",
CashOrNothingAmount = 200,
RebateType = "AtHit"
}
};
var parameter = new BinaryOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 2900.0 } },
RiskFreeRate = 0.035
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(9743.6044193724756, result.Pv, 1E-8, "");
Assert.AreEqual(47.892520332243294, result.Delta, 1E-8, "");
Assert.AreEqual(-0.0082573751569725573, result.Gamma, 1E-8, "");
Assert.AreEqual(-11.384297440145019, result.Vega, 1E-8, "");
Assert.AreEqual(7.1637717615885776, result.Theta, 1E-8, "");
Assert.AreEqual(-0.079862336903534017, result.Rho, 1E-8, "");
parameter = new BinaryOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 2900.0 } },
RiskFreeRate = 0.035,
EngineName = "AnalyticalBinaryEuropeanOptionReplicationEngine",
BinaryReplicationStrategy = "Down",
ReplicationShiftSize = 0.0
};
result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(10439.754311151559, result.Pv, 1E-8, "");
Assert.AreEqual(47.767642553136, result.Delta, 1E-8, "");
Assert.AreEqual(-0.033387487778311659, result.Gamma, 1E-8, "");
Assert.AreEqual(-46.042248515481454, result.Vega, 1E-8, "");
Assert.AreEqual(0, result.Theta, 1E-8, "");
Assert.AreEqual(-0.085568249705202437, result.Rho, 1E-8, "");
//美式二元
trade = new trade()
{
TradeType = "二元期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "American",
BuySell = "Buy",
Strike = 950,
Notional = 100,
trade_binary_option = new trade_binary_option()
{
PayoffType = "DoubleOneTouch",
CashOrNothingAmount = 200,
RebateType = "AtHit",
UpperBarrier = 1100.0,
MonitorType = "连续",
}
};
parameter = new BinaryOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 990.0 } },
RiskFreeRate = 0.035
};
result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(10835.184736140083, result.Pv, 1E-8, "");
Assert.AreEqual(-165.90143058310787, result.Delta, 1E-8, "");
Assert.AreEqual(4.3446263953228481, result.Gamma, 1E-8, "");
Assert.AreEqual(696.36722659533916, result.Vega, 1E-8, "");
Assert.AreEqual(-354.58732062354829, result.Theta, 1E-8, "");
Assert.AreEqual(-0.040437084736549875, result.Rho, 1E-8, "");
}
[TestMethod]
public void ValueRainbowOptionTest()
{
var valueDate = "2019-04-04";
var underlyingTicker1 = "RB00";
var underlying1 = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker1
};
var underlyingTicker2 = "RB01";
var underlying2 = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker2
};
//创建默认市场,并设置波动率曲面
var marketProxy = new PrebuiltQdpMarketProxy();
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.2
});
}
}
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var initParam = new VolSurfaceInitParamsBuilder()
.SetUnderlying(underlying1).SetValueDate(valueDate).Build("MoneynessVol", singleVols);
new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam);
var singleVols2 = 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.25;
singleVols2.Add(new SingleVol()
{
Strike = strikes[j],
Expire = tenors[i],
Vol = 0.25
});
}
}
var initParam2 = new VolSurfaceInitParamsBuilder()
.SetUnderlying(underlying2).SetValueDate(valueDate).Build("MoneynessVol", singleVols2);
new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam2);
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var result = OptionCalculatorV1.ValueRainbowOptionTrade(
marketProxy,
valueDate,
"CommodityFutures",
new string[] { underlyingTicker1, underlyingTicker2 },
new string[] { underlyingTicker1 + "_VolSurface", underlyingTicker2 + "_VolSurface" },
new double[] { 2900.0, 2950.0 },
valueDate,
"2019-05-06",
"Call",
"European",
"BestOfAssetsOrCash", //rainbowType
150.0, // cashAmount
new double[] { 2900.0, 2950.0 },
100.0,
0.035,
0.85, //correlation
"Buy",
"2019-05-06",
dividendRate: 0.0,
ignoreSkewMap: true,
participationRate: 1.0,
principalRate: 0.0,
isAnnualized: false,
annualizeFactor: 1.0);
Assert.AreEqual(3010.0301061974196, result.Pv, 1E-8, "");
Assert.AreEqual(0.15599592643411597, result.Delta, 1E-8, "");
Assert.AreEqual(0.0022282620193436742, result.Gamma, 1E-8, "");
Assert.AreEqual(0.959972953476381, result.Vega, 1E-8, "");
Assert.AreEqual(0, result.Theta, 1E-8, "");
Assert.AreEqual(-0.024672276803812565, result.Rho, 1E-8, "");
Assert.AreEqual(0.50413404551363783, result.Delta2.Value, 1E-8, "");
Assert.AreEqual(0.0027284841053187847, result.Gamma2.Value, 1E-8, "");
Assert.AreEqual(2.9983269828480843, result.Vega2.Value, 1E-8, "");
Assert.AreEqual(-0.0016143530956469476, result.CrossGamma, 1E-8, "");
Assert.AreEqual(-0.062994161204528609, result.CrossVogga, 1E-8, "");
Assert.AreEqual(-0.56289229188678291, result.CorrVega, 1E-8, "");
}
[TestMethod]
public void ValueRainbowOptionTestV2()
{
var valueDate = "2019-04-04";
var underlyingTicker1 = "RB00";
var underlying1 = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker1,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var underlyingTicker2 = "RB01";
var underlying2 = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker2,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var trade = new trade()
{
TradeType = "彩虹期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 2900.0,
Notional = 100,
trade_rainbow_option = new trade_rainbow_option()
{
RainbowType = "BestOfAssetsOrCash",
CashAmount = 150.0,
UnderlyingAssetCode = underlyingTicker1,
UnderlyingAssetCode2 = underlyingTicker2,
Strike2 = 2950.0
}
};
var parameter = new RainbowOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
Volatility2 = 0.25,
SpotPrices = new Dictionary<string, double>() { { underlying1.UnderlyingCode, 2900.0 }, { underlying2.UnderlyingCode, 2950.0 } },
Correlation = 0.85,
RiskFreeRate = 0.035
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying1,
parameter);
Assert.AreEqual(3010.0301061974196, result.Pv, 1E-8, "");
Assert.AreEqual(0.15599592643411597, result.Delta, 1E-8, "");
Assert.AreEqual(0.0022282620193436742, result.Gamma, 1E-8, "");
Assert.AreEqual(0.959972953476381, result.Vega, 1E-8, "");
Assert.AreEqual(0, result.Theta, 1E-8, "");
Assert.AreEqual(-0.024672276803812565, result.Rho, 1E-8, "");
Assert.AreEqual(0.50413404551363783, result.Delta2.Value, 1E-8, "");
Assert.AreEqual(0.0027284841053187847, result.Gamma2.Value, 1E-8, "");
Assert.AreEqual(2.9983269828480843, result.Vega2.Value, 1E-8, "");
Assert.AreEqual(-0.0016143530956469476, result.CrossGamma, 1E-8, "");
Assert.AreEqual(-0.062994161204528609, result.CrossVogga, 1E-8, "");
Assert.AreEqual(-0.56289229188678291, result.CorrVega, 1E-8, "");
}
[TestMethod]
public void ValueSyntheticNormalSpreadOptionTest()
{
var valueDate = "2019-04-04";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker
};
//创建默认市场,并设置波动率曲面
var marketProxy = new PrebuiltQdpMarketProxy();
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.2
});
}
}
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var initParam = new VolSurfaceInitParamsBuilder()
.SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols);
new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam);
//计算
var result = OptionCalculatorV1.ValueSyntheticNormalSpreadOptionTrade(
marketProxy,
valueDate,
underlyingTicker,
"CommodityFutures",
2900.0,
valueDate,
"2019-05-06",
"Call",
"European",
2900.0,
100.0,
underlyingTicker + "_VolSurface",
0.035,
null,
"Buy",
"2019-05-06",
dividendRate: 0,
ignoreSkewMap: true,
participationRate: 1.0,
principalRate: 0.0,
isAnnualized: false,
annualizeFactor: 1.0);
Assert.AreEqual(2.2777928184782521, result.Pv, 1E-8, "");
Assert.AreEqual(53.321595022577874, result.Delta, 1E-8, "");
Assert.AreEqual(692.96641664031711, result.Gamma, 1E-8, "");
Assert.AreEqual(0.11388964092384768, result.Vega, 1E-8, "");
Assert.AreEqual(-0.057356519934982586, result.Theta, 1E-8, "");
Assert.AreEqual(-1.8669667777526655E-05, result.Rho, 1E-8, "");
}
[TestMethod]
public void ValueSyntheticNormalSpreadOptionTestV2()
{
var valueDate = "2019-04-04";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var trade = new trade()
{
TradeType = "合成价差期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 2900,
Notional = 100
};
var parameter = new SyntheticNormalSpreadOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 2900 } },
RiskFreeRate = 0.035
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(2.2777928184782521, result.Pv, 1E-8, "");
Assert.AreEqual(53.321595022577874, result.Delta, 1E-8, "");
Assert.AreEqual(692.96641664031711, result.Gamma, 1E-8, "");
Assert.AreEqual(0.11388964092384768, result.Vega, 1E-8, "");
Assert.AreEqual(-0.057356519934982586, result.Theta, 1E-8, "");
Assert.AreEqual(-1.8669667777526655E-05, result.Rho, 1E-8, "");
}
[TestMethod]
public void ValueAutocallTest()
{
var valueDate = "2019-07-30";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker
};
//创建默认市场,并设置波动率曲面
var marketProxy = new PrebuiltQdpMarketProxy();
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.35;
singleVols.Add(new SingleVol()
{
Strike = strikes[j],
Expire = tenors[i],
Vol = 0.35
});
}
}
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var initParam = new VolSurfaceInitParamsBuilder()
.SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols);
new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam);
//计算
var result = OptionCalculatorV1.ValueAutocallTrade(
marketProxy: marketProxy,
valueDate: valueDate,
underlyingCode: underlyingTicker,
underlyingInstrumentType: "CommodityFutures",
startDate: valueDate,
endDate: "2019-09-08",
callPut: "Call",
koBarrier: 100.0,
kiBarrier: 80.0,
couponBarrier: 80.0,
koObservationDateStr: "2019-08-30,2019-09-27,2019-10-31,2019-11-29,2019-12-27,2020-01-31",
observationDateStr: null,
coupon: 0.12,
couponPayAtMaturity: false,
includeCouponAfterKI: true,
isFixedCoupon: false,
annualizedOptionPayoff: false,
participationRate: 0.75,
principalRate: 0.0,
spotPrice: 100.0,
notional: 12.0,
volSurfaceName: underlyingTicker + "_VolSurface",
riskFreeRate: 0.035,
buySell: "Buy",
exerciseDate: "2020-02-01",
annualizeFactor: 1.0,
couponDayCount: "",
strike: 100.0,
spreadStrike: 0.0,
happenedObservations: null,
initialSpotPrice: 100.0);
Assert.AreEqual(8.5343, result.Pv, 0.01);
}
[TestMethod]
public void ValueAsianSyntheticNormalSpreadOptionTest()
{
var valueDate = "2019-04-04";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker
};
//创建默认市场,并设置波动率曲面
var marketProxy = new PrebuiltQdpMarketProxy();
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.3;
singleVols.Add(new SingleVol()
{
Strike = strikes[j],
Expire = tenors[i],
Vol = 0.3
});
}
}
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var initParam = new VolSurfaceInitParamsBuilder()
.SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols);
new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam);
var result = OptionCalculatorV1.ValueAsianSyntheticNormalSpreadOptionTrade(
marketProxy,
valueDate,
underlyingTicker,
"CommodityFutures",
100,
valueDate,
"2019-04-30",
"Call",
"European",
"ArithmeticAverage",
"Fixed",
100.0,
1000.0,
underlyingTicker + "_VolSurface",
0.03,
"Buy",
"2019-04-30",
isAnnualized: false,
annualizeFactor: 1.0,
dividendRate: 0.0,
averagingPeriodStartDate: null,
ignoreSkewMap: true);
Assert.AreEqual(18.200884513861684, result.Pv, 1E-8, "");
Assert.AreEqual(542.322618892204, result.Delta, 1E-8, "");
Assert.AreEqual(8673.3218846805466, result.Gamma, 1E-8, "");
Assert.AreEqual(0.606696150462227, result.Vega, 1E-8, "");
Assert.AreEqual(-0.54126177511056994, result.Theta, 1E-8, "");
Assert.AreEqual(-0.00012680502384547764, result.Rho, 1E-8, "");
}
[TestMethod]
public void ValueAsianSyntheticNormalSpreadOptionTestV2()
{
var valueDate = "2019-04-04";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var trade = new trade()
{
TradeType = "亚式合成价差期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 4, 30),
ExerciseDate = new DateTime(2019, 4, 30),
ExerciseMode = "European",
OptionType = "看涨",
BuySell = "Buy",
Strike = 100,
Notional = 1000,
trade_asian_option = new trade_asian_option()
{
PayoffType = "ArithmeticAverage",
StrikeType = "Fixed"
}
};
var parameter = new AsianSyntheticNormalSpreadOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.3,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 100 } },
RiskFreeRate = 0.03,
Fixings = ""
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(18.200884513861684, result.Pv, 1E-8, "");
Assert.AreEqual(542.322618892204, result.Delta, 1E-8, "");
Assert.AreEqual(8673.3218846805466, result.Gamma, 1E-8, "");
Assert.AreEqual(0.606696150462227, result.Vega, 1E-8, "");
Assert.AreEqual(-0.54126177511056994, result.Theta, 1E-8, "");
Assert.AreEqual(-0.00012680502384547764, result.Rho, 1E-8, "");
}
[TestMethod]
public void ValueAutocallTestV2()
{
var valueDate = "2019-07-30";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var trade = new trade()
{
TradeType = "凤凰期权",
TradeDate = new DateTime(2019, 7, 30),
MaturityDate = new DateTime(2020, 9, 8),
ExerciseDate = new DateTime(2020, 2, 1),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 100,
Notional = 12,
SpotPrice = 100,
ParticipationRate = 0.75,
trade_autocall = new trade_autocall()
{
KOBarrier = 100,
KIBarrier = 80,
Coupon = 0.12,
CouponPayType = CouponPayTypeEnum.AtMaturity,
KOObservationDates = "2019-08-30,2019-09-27,2019-10-31,2019-11-29,2019-12-27,2020-01-31"
}
};
var parameter = new AutocallParameter()
{
ValueDate = new DateTime(2019, 7, 30),
Volatility = 0.35,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 100 } },
RiskFreeRate = 0.035
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(8.5343, result.Pv, 0.01);
}
[TestMethod]
public void ValueSnowballTest()
{
var valueDate = new DateTime(2019, 07, 30);
var underlyingTicker = "RB00";
var vols = QdpVolHelper.GetDefaultVolatility(0.35);
var tradeId = Guid.NewGuid().ToString();
using var mp = new MarketProxy(valueDate, 0.035);
mp.SetVolSurface(tradeId, vols);
var tdparam = new SnowballOptionTradeParam
{
underlyingTickers = new[] { underlyingTicker },
underlyingInstrumentType = "CommodityFutures",
startDate = valueDate,
endDate = new DateTime(2019, 09, 08),
optionType = OptionType.Call,
koBarrier = 100.0,
kiBarrier = 80.0,
koObservationDateStr = "2019-08-30,2019-09-27,2019-10-31,2019-11-29,2019-12-27,2020-01-31",
observationDateStr = null,
coupon = 0.12,
participationRate = 0.75,
principalRate = 0.0,
initialSpotPrice = 100.0,
notional = 12.0,
volSurfaceNames = new[] { tradeId },
riskFreeRate = 0.035,
buysell = "Buy",
exerciseDate = new DateTime(2020, 1, 31),
isAnnualized = false,
annualizedFactor = 1.0,
strike = 100.0,
spreadStrikeAtKO = 0.0,
spreadStrikeAtMaturity = 0.0,
isFixedCoupon = false,
koRebate = 12.0,
koBarrierAdjustStep = 0.0,
useOptionPayoffAtKO = false,
useOptionPayoffAtMaturity = true,
annualizedOptionPayoff = false,
couponDayCount = "Act365",
kiOptionType = OptionType.Coupon,
koOptionType = OptionType.Call
};
var result = TradeRiskCalcUtil.GetSnowballOptionValue(mp, new OptionCalcParam<SnowballOptionTradeParam>(tdparam)
{
spotPrices = new[] { 100d },
pricingRequest = PricingRequest.Pv,
quadratureFastMode = true
});
Assert.AreEqual(8.4353, result.Pv, 0.01);
}
[TestMethod]
public void ValueSnowballTestV2()
{
var valueDate = "2019-07-30";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var trade = new trade()
{
TradeType = "雪球期权",
TradeDate = new DateTime(2019, 7, 30),
MaturityDate = new DateTime(2020, 9, 8),
ExerciseDate = new DateTime(2020, 2, 1),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 100,
Notional = 12,
SpotPrice = 100,
ParticipationRate = 0.75,
trade_snowball = new trade_snowball()
{
KOBarrier = 100,
KIBarrier = 80,
Coupon = 0.12,
KOObservationDates = "2019-08-30,2019-09-27,2019-10-31,2019-11-29,2019-12-27,2020-01-31"
}
};
var parameter = new SnowballParameter()
{
ValueDate = new DateTime(2019, 7, 30),
Volatility = 0.35,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 100 } },
RiskFreeRate = 0.035
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(8.4353, result.Pv, 0.01);
}
[TestMethod]
public void ValueDoubleSharkFinOptionTest()
{
var valueDate = "2019-04-04";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker
};
//创建默认市场,并设置波动率曲面
var marketProxy = new PrebuiltQdpMarketProxy();
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.2
});
}
}
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var initParam = new VolSurfaceInitParamsBuilder()
.SetUnderlying(underlying).SetValueDate(valueDate).Build("MoneynessVol", singleVols);
new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam);
var result = OptionCalculatorV1.ValueDoubleSharkFinOptionTrade(
marketProxy,
valueDate,
underlyingTicker,
"CommodityFutures",
125,
110,
valueDate,
"2019-05-06",
"Call",
"European",
144,
100,
true,
120,
20,
20,
"AtHit",
100,
underlyingTicker + "_VolSurface",
0.035,
"Buy",
"2019-05-06",
participationRate: 1.0,
principalRate: 0.0,
isAnnualized: false,
annualizeFactor: 1.0,
callParticipationRate: 1.0,
putParticipationRate: 1.0);
Assert.AreEqual(125.79272737448922, result.Pv, 1E-8, "");
Assert.AreEqual(20.046036888621188, result.Delta, 1E-8, "");
Assert.AreEqual(7.002952211507818, result.Gamma, 1E-8, "");
Assert.AreEqual(16.58915982588951, result.Vega, 1E-8, "");
Assert.AreEqual(-8.5410348523357555, result.Theta, 1E-8, "");
}
[TestMethod]
public void ValueDoubleSharkFinOptionTestV2()
{
var valueDate = "2019-04-04";
var underlyingTicker = "RB00";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var trade = new trade()
{
TradeType = "双鲨期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 110,
Notional = 100,
trade_double_sharkfin_option = new trade_double_sharkfin_option()
{
BarrierHigh = 144,
BarrierLow = 100,
StrikeHigh = 125,
StrikeLow = 110,
Discrete = "离散",
Rebate = 20.0,
KnockInOutStatus = "Monitoring"
}
};
var parameter = new DoubleSharkFinOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatility = 0.2,
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, 120.0 } },
RiskFreeRate = 0.035
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(125.79272737448922, result.Pv, 1E-8, "");
Assert.AreEqual(20.046036888621188, result.Delta, 1E-8, "");
Assert.AreEqual(7.002952211507818, result.Gamma, 1E-8, "");
Assert.AreEqual(16.58915982588951, result.Vega, 1E-8, "");
Assert.AreEqual(-8.5410348523357555, result.Theta, 1E-8, "");
}
[TestMethod]
public void ValueSpreadOptionTest()
{
var valueDate = "2019-04-04";
var underlyingTicker1 = "RB00";
var underlying1 = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker1
};
var underlyingTicker2 = "RB01";
var underlying2 = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker2
};
var underlyingTicker3 = "RB02";
var underlying3 = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker3
};
//创建默认市场,并设置波动率曲面
var marketProxy = new PrebuiltQdpMarketProxy();
var tenors = new string[]
{
"1D",
"2M",
"1Y"
};
var strikes = new double[]
{
0.95,
1.0,
1.05,
};
var vols1 = new double[3, 3];
var singleVols1 = new List<SingleVol>();
for (var i = 0; i < vols1.GetLength(0); ++i)
{
for (var j = 0; j < vols1.GetLength(1); ++j)
{
vols1[i, j] = 0.2;
singleVols1.Add(new SingleVol()
{
Strike = strikes[j],
Expire = tenors[i],
Vol = 0.2
});
}
}
var vols2 = new double[3, 3];
var singleVols2 = new List<SingleVol>();
for (var i = 0; i < vols2.GetLength(0); ++i)
{
for (var j = 0; j < vols2.GetLength(1); ++j)
{
vols2[i, j] = 0.23;
singleVols2.Add(new SingleVol()
{
Strike = strikes[j],
Expire = tenors[i],
Vol = 0.23
});
}
}
var vols3 = new double[3, 3];
var singleVols3 = new List<SingleVol>();
for (var i = 0; i < vols3.GetLength(0); ++i)
{
for (var j = 0; j < vols3.GetLength(1); ++j)
{
vols3[i, j] = 0.25;
singleVols3.Add(new SingleVol()
{
Strike = strikes[j],
Expire = tenors[i],
Vol = 0.25
});
}
}
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var initParam = new VolSurfaceInitParamsBuilder()
.SetUnderlying(underlying1).SetValueDate(valueDate).Build("MoneynessVol", singleVols1);
new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam);
var initParam2 = new VolSurfaceInitParamsBuilder()
.SetUnderlying(underlying2).SetValueDate(valueDate).Build("MoneynessVol", singleVols2);
new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam2);
var initParam3 = new VolSurfaceInitParamsBuilder()
.SetUnderlying(underlying3).SetValueDate(valueDate).Build("MoneynessVol", singleVols3);
new NormalVolSurfaceInitializer().InitializeMarketProxy(marketProxy, initParam3);
var payoff = new SpreadOptionPayoff("S1+S2-S3-K");
//计算
var result = OptionCalculatorV1.ValueSpreadOption(
marketProxy,
valueDate,
"CommodityFutures",
new string[] { underlyingTicker1, underlyingTicker2, underlyingTicker3 },
payoff.Weights,
payoff.SpreadType,
new string[] { underlyingTicker1 + "_VolSurface", underlyingTicker2 + "_VolSurface", underlyingTicker3 + "_VolSurface" },
2900.0,
valueDate,
"2019-05-06",
"Call",
"European",
new double[] { 2850, 2930, 2987 },
100.0,
0.035,
new double[] { 0.85, 0.9, 0.75 },
"Buy",
"2019-05-06",
1.0,
false,
1.0);
Assert.AreEqual(3712.3651708468392, result.Pv, 1E-8, "");
Assert.AreEqual(29.766132038275828, result.Delta, 1E-8, "");
Assert.AreEqual(0.17244019545614719, result.Gamma, 1E-8, "");
Assert.AreEqual(198.39776415513484, result.Vega, 1E-8, "");
Assert.AreEqual(0, result.Theta, 1E-8, "");
Assert.AreEqual(-0.030429098001604871, result.Rho, 1E-8, "");
Assert.AreEqual(30.391497575692483, result.Delta2.Value, 1E-8, "");
Assert.AreEqual(0.17016645870171487, result.Gamma2.Value, 1E-8, "");
Assert.AreEqual(257.01927094713324, result.Vega2.Value, 1E-8, "");
Assert.AreEqual(-29.403113571788708, result.Delta3.Value, 1E-8, "");
Assert.AreEqual(0.17698766896501184, result.Gamma3.Value, 1E-8, "");
Assert.AreEqual(-120.56156531622924, result.Vega3.Value, 1E-8, "");
}
[TestMethod]
public void ValueSpreadOptionTestV2()
{
var valueDate = "2019-04-04";
var underlyingTicker1 = "RB00";
var underlying1 = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker1,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var underlyingTicker2 = "RB01";
var underlying2 = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker2,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var underlyingTicker3 = "RB02";
var underlying3 = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
UnderlyingCode = underlyingTicker3,
UnderlyingInstrumentType = "CommodityFutures",
MaturityDate = new DateTime(2019, 5, 6)
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var trade = new trade()
{
TradeType = "价差期权",
TradeDate = new DateTime(2019, 4, 4),
MaturityDate = new DateTime(2019, 5, 6),
ExerciseDate = new DateTime(2019, 5, 6),
OptionType = "看涨",
ExerciseMode = "European",
BuySell = "Buy",
Strike = 2900,
Notional = 100,
trade_spread_option = new trade_spread_option()
{
Payoff = "S1+S2-S3-K",
UnderlyingAssetCode1 = underlyingTicker1,
UnderlyingAssetCode2 = underlyingTicker2,
UnderlyingAssetCode3 = underlyingTicker3,
}
};
var parameter = new SpreadOptionParameter()
{
ValueDate = new DateTime(2019, 4, 4),
Volatilities = new double[] { 0.2, 0.23, 0.25 },
SpotPrices = new Dictionary<string, double>() { { underlying1.UnderlyingCode, 2850 }, { underlying2.UnderlyingCode, 2930 }, { underlying3.UnderlyingCode, 2987 } },
RiskFreeRate = 0.035,
Correlations = new double[] { 0.85, 0.9, 0.75 }
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying1,
parameter);
Assert.AreEqual(3712.3651708468392, result.Pv, 1E-8, "");
Assert.AreEqual(29.766132038275828, result.Delta, 1E-8, "");
Assert.AreEqual(0.17244019545614719, result.Gamma, 1E-8, "");
Assert.AreEqual(198.39776415513484, result.Vega, 1E-8, "");
Assert.AreEqual(0, result.Theta, 1E-8, "");
Assert.AreEqual(-0.030429098001604871, result.Rho, 1E-8, "");
Assert.AreEqual(30.391497575692483, result.Delta2.Value, 1E-8, "");
Assert.AreEqual(0.17016645870171487, result.Gamma2.Value, 1E-8, "");
Assert.AreEqual(257.01927094713324, result.Vega2.Value, 1E-8, "");
Assert.AreEqual(-29.403113571788708, result.Delta3.Value, 1E-8, "");
Assert.AreEqual(0.17698766896501184, result.Gamma3.Value, 1E-8, "");
Assert.AreEqual(-120.56156531622924, result.Vega3.Value, 1E-8, "");
}
[TestMethod]
public void ValueCashFlowTradeTest()
{
var valueDate = "2020-01-04";
var underlying = new underlying_manager()
{
QuotationDate = DateTime.Parse(valueDate),
MaturityDate = new DateTime(2020, 5, 6)
};
var trade = new trade()
{
TradeType = "现金流交易",
StartDate = new DateTime(2020, 1, 4),
TradeDate = new DateTime(2020, 1, 4),
MaturityDate = new DateTime(2020, 5, 6),
BuySell = "Buy",
StockEqvNotional = 1000000,
trade_cashflow = new trade_cashflow()
{
ProfitRate = 0.03,
RateType = CashFlowRateTypeEnum.年化利率,
ProfitDayCount = "Act365",
}
};
var userId = Guid.NewGuid().ToString();
PS.ResetConfig("{\"SkewMapVolConstruction\":\"false\"}");
var parameter = new CashFlowTradeParameter()
{
ValueDate = new DateTime(2020, 1, 4),
RiskFreeRate = 0.035
};
var result = ValueCalculator.CalculateTradeValue(
userId,
trade,
underlying,
parameter);
Assert.AreEqual(999300.87674743345, result.Pv, 1E-8, "");
}
[TestMethod]
public void GetAddDaysWithPrecisionOfMinuteTest()
{
//var privateType = new PrivateType(typeof(OptionCalculatorV1));
////c1: after day close, before night market
//var t = new DateTime(2019, 6, 10, 20, 0, 0);
//var ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual(0, ttm, DELTA, "c1: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(0, ttm, DELTA, "c1: false");
////c2: after night market open
//t = new DateTime(2019, 6, 10, 21, 30, 0);
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual((1 - 0.5 / 6), ttm, DELTA, "c2: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(1, ttm, DELTA, "c1: false");
////c3: after night market active hour
//t = new DateTime(2019, 6, 10, 23, 30, 0);
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual((1 - 2.0 / 6), ttm, DELTA, "c3: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(1, ttm, DELTA, "c1: false");
////c4: before AM trading
//t = new DateTime(2019, 6, 10, 8, 30, 0);
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual((1 - 2.0 / 6), ttm, DELTA, "c4: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(1, ttm, DELTA, "c4: false");
////c5: AM trading
//t = new DateTime(2019, 6, 10, 9, 30, 0);
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual((1 - 2.5 / 6), ttm, DELTA, "c5: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(1 - 0.5 / 4, ttm, DELTA, "c5: false");
////c6: lunch break
//t = new DateTime(2019, 6, 10, 11, 40, 0);
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual((1 - 4.5 / 6), ttm, DELTA, "c6-1: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(1 - 2.5 / 4, ttm, DELTA, "c6-1: false");
//t = new DateTime(2019, 6, 10, 13, 00, 0);
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual((1 - 4.5 / 6), ttm, DELTA, "c6-2: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(1 - 2.5 / 4, ttm, DELTA, "c6-2: false");
////c7: pm trading
//t = new DateTime(2019, 6, 10, 13, 30, 0);
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual((1 - 4.5 / 6), ttm, DELTA, "c7-1: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(1 - 2.5 / 4, ttm, DELTA, "c7-1: false");
//t = new DateTime(2019, 6, 10, 14, 30, 0);
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual((1 - 5.5 / 6), ttm, DELTA, "c7-2: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(1 - 3.5 / 4, ttm, DELTA, "c7-2: false");
////c8: after pm trading
//t = new DateTime(2019, 6, 10, 15, 00, 0);
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual(0, ttm, DELTA, "c8-1: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(0, ttm, DELTA, "c8-1: false");
//t = new DateTime(2019, 6, 10, 20, 00, 0);
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual(0, ttm, DELTA, "c8-2: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(0, ttm, DELTA, "c8-2: false");
////c9: night market just open
//t = new DateTime(2019, 6, 10, 21, 00, 0);
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, true));
//Assert.AreEqual(1, ttm, DELTA, "c9: true");
//ttm = Convert.ToDouble(privateType.InvokeStatic("GetAddDaysWithPrecisionOfMinute", t, false));
//Assert.AreEqual(1, ttm, DELTA, "c9: false");
}
[TestMethod]
public void GetHistoricalPricesTest()
{
var priceCount = 20;
var volCurve = VolCaculator.Instance.GetHistoricalVolCurvePointsEx("I2012", DateTime.Now, priceCount, priceCount, 0.3, 0.7);
Assert.IsTrue(volCurve.Points.Count == priceCount);
}
[TestMethod]
public void GetSpotPriceFromBasisSpreadTest()
{
var valueDate = new DateTime(2020, 7, 24);
var maturityDate = new DateTime(2020, 9, 1);
var codelist = new List<string> { "Ab00", "Un00", "Ub22" };
var tenors = new List<string> { "1M", "2M", "3M" };
var spreads = new List<double> { 5.0, -3.0, 7.0 };
var isClosePrice = true;
var spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads);
Assert.AreEqual(4002.93548387, spotPrice, 1e-8);
maturityDate = new DateTime(2020, 8, 24);
spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads);
Assert.AreEqual(4005.0, spotPrice, 1e-8);
maturityDate = new DateTime(2020, 9, 24);
spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads);
Assert.AreEqual(3997.0, spotPrice, 1e-8);
maturityDate = new DateTime(2020, 10, 24);
spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads);
Assert.AreEqual(4007.0, spotPrice, 1e-8);
maturityDate = new DateTime(2020, 11, 24);
spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads);
Assert.AreEqual(4007.0, spotPrice, 1e-8);
maturityDate = new DateTime(2020, 7, 31);
spotPrice = CalculatorHelper.GetSpotPriceFromBasisSpread(valueDate, maturityDate, isClosePrice, codelist, tenors, spreads);
Assert.AreEqual(4005.0, spotPrice, 1e-8);
}
[TestMethod]
public void CCRService()
{
var tradeList = DbContextFactory.GetYLDbContext().trade.Where(O => O.TradeStatus == "确认成交" && O.ValidState != "InValid" && O.ExerciseDate >= valuedateBLL.ValueDate).ToList();
new CCRService(OptUserInfo.UnitTestUser).CalculationCCR(tradeList, 2, 485);
}
}
}