using KellermanSoftware.CompareNetObjects;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using YLErp.Commons;
using YLErp.DBModels;
using YLErp.DBModels.Consts;
using YLErp.DBModels.Helpers;
using YLErp.Model;
namespace YLErp.Modules.TradeModule.OrderModule
{
///
/// 测试交易保存服务
///
[TestClass]
public class OtcTradeSaveServiceTest : YLUnitTestBase
{
readonly bool _delete = true;
readonly CompareLogic _compareLogic;
public OtcTradeSaveServiceTest()
{
_compareLogic = new CompareLogic(new ComparisonConfig
{
MaxDifferences = 10,
DoublePrecision = 5,
MembersToIgnore = new List { nameof(trade.id), nameof(trade.EncryptId),
nameof(trade.CreateDate), nameof(trade.UnderlyingAssetClass) },
CaseSensitive = false,
});
}
[TestMethod("测试保存香草期权交易")]
public void TestSaveVanillaOption()
{
var asset = GetAssetUnit();
var client = GetClient();
var uly = GetUnderlyingManager(true);
var valueDate = ValueDate;
var td = new OtcOptionTradeFullEx
{
AssetBookName = asset.Name,
TraderName = "Admin",
ClientNumber = client.Number,
ClientName = client.Name,
TradeType = "香草期权",
TradeNumber = "UAT-" + UniqueTimeId.GetStr(),
UnderlyingCode= uly.UnderlyingCode,
BuySell="买入",
ExerciseMode= "European",
OptionType="Put",
SpotPrice=12900,
IsMoneynessOption="否",
Strike= 12900,
TradeDate=valueDate,
ExerciseDate=valueDate.AddMonths(3),
SettlementDate = valueDate.AddMonths(3),
Notional = 400,
TradeSinglePrice=100,
SettlementType=0,
ParticipationRate=1,
IsAnnualized=false,
PrincipalRate=0,
NoRiskRate=0.05,
DividendRate=0,
TradeOpenVolatility=0.1616,
TradeCloseVolatility = 0.1616,
NumOfSmoothingDays=1,
Comments="测试API"
};
var td2 = new OtcTradeSaveService(this.OptUser).SaveOptionTradeFromApiOrImport(td, Model.Enum.TradeSourceEnum.WebApiV2);
Assert.IsTrue(td.TradeSinglePrice==td2.TradeSinglePrice);
}
[TestMethod("测试保存亚式期权交易")]
public void TestSaveAsianOption()
{
InnerTest("亚式期权");
}
[TestMethod("测试保存二元期权交易")]
public void TestSaveBinaryOption()
{
InnerTest("二元期权");
}
[TestMethod("测试保存障碍期权交易")]
public void TestSaveBarrierOption()
{
InnerTest("障碍期权");
}
[TestMethod("测试保存双鲨期权交易")]
public void TestSaveDoubleSharkfinOption()
{
InnerTest("双鲨期权");
}
[TestMethod("测试保存区间累积期权交易")]
public void TestSaveRangeAccOption()
{
InnerTest("区间累积期权");
}
[TestMethod("测试保存气囊结构交易")]
public void TestSaveAirBagOption()
{
InnerTest("气囊结构");
}
[TestMethod("测试保存收益增强结构交易")]
public void TestSaveUnderlyingEnhanceOption()
{
InnerTest("收益增强结构");
}
[TestMethod("测试保存雪球期权交易")]
public void TestSaveSnowballOption()
{
InnerTest("雪球期权");
}
[TestMethod("测试保存凤凰期权交易")]
public void TestSaveAutoCallOption()
{
InnerTest("凤凰期权");
}
private void InnerTest(string tradeType) where TExtend : TradeExtendBase
{
var asset = GetAssetUnit();
var client = GetClient();
var uly = GetUnderlyingManager(true);
var valueDate = ValueDate;
var td = new OtcOptionTradeFull
{
AnnualizedEnhanceRate = 0.01,
AnnualizedPremiumRate = 0.01,
AnnualizeFactor = 100.0 / 244,
AnnualizeFactor2 = 0.9,
AssetBookName = asset.Name,
AssetId = asset.id,
AveragingPeriodStartDate = valueDate,
BarrierHigh = 1.05,
BarrierLow = 0.95,
BarrierShift = 10,
BarrierType = "双障碍敲出",
BasisGap = 1,
BasisUnderlyingCode = "RB00",
BasisUnderlyingId = uly.id,
BonusRate = 0.1,
BuySell = "卖出",
CalcFlag = 0,
CalcId = "CalcId",
OptionType = "看涨",
CashOrNothingAmount = 500,
CashOrNothingAmountHigh = 1000,
CashOrNothingAmountHighRate = 0.1,
CashOrNothingAmountRate = 0.05,
CheckStatus = 0,
CheckTradeUpdate = 0,
ClientId = client.id,
ClientName = client.Name,
Comments = "单元测试",
ContractVersion = "V2",
Coupon = 0.1,
CouponBarrier = 1.05,
CouponPayType = CouponPayTypeEnum.AtMaturity,
CreateDate = valueDate,
DividendDate = DateTime.MinValue,
DividendRate = 0.1,
DurationDays = 10,
ExerciseDate = valueDate.AddMonths(3),
ExerciseMode = ConsGlobal.ExerciseMode.American,
FinalPrice = 3700,
GroupId = 1,
GroupName = "Test",
HasPartialUnWind = 0,
HasPayoffLimit = true,
HighStrike = 1.05,
IncludeCouponAfterKI = true,
InitialSpotPriceState = "期初价格已确认",
IsAnnualized = true,
IsAnnualized2 = true,
IsDiscreteMonitored = true,
IsFixedCoupon = false,
IsMoneynessOption = "是",
IsSingleContract = 1,
IsTradePricePayType = false,
IsUsePremiumRate = true,
InitialMargin = 100,
KIBarrier = 0.9,
KIParticipationRate = 0.1,
KIPayoffType = KIPayoffTypeEnum.ToCallSpreadOption,
KOBarrier = 1.05,
KOObservationDates = valueDate.OtcFormatDate(),
KOObservationSettleDates = valueDate.OtcFormatDate(),
KOPayoffType = KOPayoffTypeEnum.ToSpreadOption,
KORebate = 0.1,
KORebateType = RebateTypeEnum.AtEnd,
Lots = 10,
LowerRange = 0.9,
MaturityDate = uly.MaturityDate,
MonitorType = "离散",
NoRiskRate = 0.05,
NumOfSmoothingDays = 10,
Notional = 100,
ObservationDates = valueDate.OtcFormatDate(),
ObservationDateStr = valueDate.OtcFormatDate(),
OptDate = OptDate,
OptId = UserId,
OptName = UserName,
OriginalNotional = 100,
OriginalStockEqvNotional = 0,
PairTrade = "",
ParentTradeId = 0,
ParticipationRate = 0.5,
PayoffType = "DoubleNoTouch",
PremiumPayDate = valueDate.AddMonths(3),
PremiumRate = 0.1,
PricingModel = "",
PrincipalRate = 0.05,
ProcessOptDate = null,
ProcessOrderId = 0,
ProcessStatus = "",
Rebate = 500,
RebateHigh = 1000,
RebateRate = 0.05,
RebateHighRate = 0.1,
RebateType = "AtHit",
SentMailCount = 0,
SettlementDate = valueDate.AddMonths(3),
SettlementType = 0,
SpreadStrike = 0.95,
SpreadStrike1 = 0.9,
SpreadStrikeAtKO = 1.06,
SpreadStrikeAtKO1 = 1.01,
StartDate = valueDate,
StockEqvNotional = 0,
StockEqvNotionalMax = 0,
StockEqvNotionalReal = 100 * 3600,
Strike = 1.002,
StrikeGearingFactor = 1,
StrikeHigh = 1.02,
StrikeType = ConsTrade.AsiaStrikeType.Fixed,
StructureIntroduction = "StructureIntroduction",
StructureType = "",
TradeAmount = 100,
TradeDate = valueDate,
TradeInstruction = "TradeInstruction",
TradeCloseVolatility = 0.5,
TradeNumber = "UT-" + Guid.NewGuid().ToString("N"),
TradeOpenVolatility = 0.45,
TradePremium = 0.03,
TraderId = 1,
TraderName = "Admin",
TradeSavedVol = 0.4,
TradeSource = "系统交易",
TradeStatus = "新增待确认",
TradeType = tradeType,
TradeUnit = "吨",
TTMDays = null,
UnderlyingAssetClass = "螺纹钢",
UnderlyingCode = uly.UnderlyingCode,
UnderlyingId = uly.id,
UnderlyingInstrumentType = uly.UnderlyingInstrumentType,
UnderlyingAssetName = uly.UnderlyingName,
UnderlyingPrice = null,
UnWindDate = null,
UnWindNotional = null,
UpperRange = 1.1,
ValidState = ConsGlobal.Valid,
Vol = null,
VolType = null,
SpotPrice = 3600
};
td.KOObservationDates += "," + td.ExerciseDate.OtcFormatDate();
if (tradeType == "雪球期权" || tradeType == "凤凰期权")
{
td.IsAnnualized = false;
td.AnnualizeFactor = 1;
td.MetaDic[nameof(td.AnnualizeFactor)] = "/";
td.ExerciseMode = ConsTrade.ExerciseType.European;
td.StockEqvNotionalMax = td.OriginalStockEqvNotional = td.StockEqvNotional = td.StockEqvNotionalReal;
var spotPrice = Math.Abs(td.SpotPrice.Value);
td.StockEqvNotionalReal = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor);
td.TradeAmount = td.Notional = spotPrice > 0 ? td.StockEqvNotionalReal / spotPrice : 0;
}
else
{
td.MetaDic[nameof(td.AnnualizeFactor)] = "100/244";
if (tradeType == "双鲨期权")
{
td.ExerciseMode = ConsTrade.ExerciseType.European;
}
else if (tradeType == "亚式期权")
{
td.PayoffType = ConsTrade.AsianAverageType.ArithmeticAverage;
}
td.StockEqvNotionalMax = td.OriginalStockEqvNotional = td.StockEqvNotional = TradeHelper.GetStockEqvNotional(td.StockEqvNotionalReal, td.ParticipationRate, td.AnnualizeFactor);
}
td.OriginalNotional = td.Notional;
td.TradePrice = TradeHelper.GetTradePriceByPremiumRate(td.PremiumRate, td.StockEqvNotional, td.ParticipationRate, td.PrincipalRate, td.AnnualizeFactor,td.BuySell,td.TradeType,false);
td.TradeSinglePrice = TradeHelper.GetTradeSinglePriceByPremiumRate(td.PremiumRate, td.SpotPrice);
var saved = new OtcTradeSaveService(this).SaveOptionTradesFromTradeEdit(td);
td.id = saved.id;
var dbTrade = new TradeDetailsQueryService(this).GetOtcTradeFull(saved.TradeNumber);
if (_delete)
{
AddClearSQL("id=" + td.id);
AddClearSQL("TradeId=" + td.id);
AddClearSQL("TradeId=" + td.id);
}
var map1 = YLAutoMapper.Map(td);
var map2 = YLAutoMapper.Map(dbTrade);
ComparisonResult result = _compareLogic.Compare(map1, map2);
Assert.IsTrue(result.AreEqual, result.DifferencesString);
var tdex1 = YLAutoMapper.Map(td);
var tdex2 = YLAutoMapper.Map(dbTrade);
Assert.IsTrue(tdex2.TradeId > 0, "TradeId映射失败");
result = _compareLogic.Compare(tdex1, tdex2);
Assert.IsTrue(result.AreEqual, result.DifferencesString);
}
class VanillaTrade : TradeExtendBase
{
}
}
}