348 lines
13 KiB
C#
348 lines
13 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// 测试交易保存服务
|
|
/// </summary>
|
|
|
|
[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<string> { 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<trade_asian_option>("亚式期权");
|
|
}
|
|
|
|
[TestMethod("测试保存二元期权交易")]
|
|
public void TestSaveBinaryOption()
|
|
{
|
|
InnerTest<trade_binary_option>("二元期权");
|
|
}
|
|
|
|
[TestMethod("测试保存障碍期权交易")]
|
|
public void TestSaveBarrierOption()
|
|
{
|
|
InnerTest<trade_barrier_option>("障碍期权");
|
|
}
|
|
|
|
[TestMethod("测试保存双鲨期权交易")]
|
|
public void TestSaveDoubleSharkfinOption()
|
|
{
|
|
InnerTest<trade_double_sharkfin_option>("双鲨期权");
|
|
}
|
|
|
|
[TestMethod("测试保存区间累积期权交易")]
|
|
public void TestSaveRangeAccOption()
|
|
{
|
|
InnerTest<trade_rangeaccrual>("区间累积期权");
|
|
}
|
|
|
|
[TestMethod("测试保存气囊结构交易")]
|
|
public void TestSaveAirBagOption()
|
|
{
|
|
InnerTest<trade_airbag>("气囊结构");
|
|
}
|
|
|
|
[TestMethod("测试保存收益增强结构交易")]
|
|
public void TestSaveUnderlyingEnhanceOption()
|
|
{
|
|
InnerTest<trade_underlying_enhance>("收益增强结构");
|
|
}
|
|
|
|
[TestMethod("测试保存雪球期权交易")]
|
|
public void TestSaveSnowballOption()
|
|
{
|
|
InnerTest<trade_snowball>("雪球期权");
|
|
}
|
|
|
|
[TestMethod("测试保存凤凰期权交易")]
|
|
public void TestSaveAutoCallOption()
|
|
{
|
|
InnerTest<trade_autocall>("凤凰期权");
|
|
}
|
|
|
|
private void InnerTest<TExtend>(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<trade>("id=" + td.id);
|
|
AddClearSQL<TradeMeta>("TradeId=" + td.id);
|
|
AddClearSQL<TExtend>("TradeId=" + td.id);
|
|
}
|
|
|
|
var map1 = YLAutoMapper.Map<OtcTradeBase>(td);
|
|
var map2 = YLAutoMapper.Map<OtcTradeBase>(dbTrade);
|
|
ComparisonResult result = _compareLogic.Compare(map1, map2);
|
|
Assert.IsTrue(result.AreEqual, result.DifferencesString);
|
|
|
|
var tdex1 = YLAutoMapper.Map<TExtend>(td);
|
|
var tdex2 = YLAutoMapper.Map<TExtend>(dbTrade);
|
|
Assert.IsTrue(tdex2.TradeId > 0, "TradeId映射失败");
|
|
result = _compareLogic.Compare(tdex1, tdex2);
|
|
Assert.IsTrue(result.AreEqual, result.DifferencesString);
|
|
}
|
|
|
|
class VanillaTrade : TradeExtendBase
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|