using NPOI.SS.Formula.Functions;
using System.Linq.Expressions;
using System.Reflection;
using YLErp.Commons;
using YLErp.Modules.TradeModule.AccumulatorOptionModule;
namespace YLErp.Modules.TradeModule
{
///
/// 交易复核
///
public class TradeCheckUtil
{
private static readonly OtcOptionTradeFull tf;
static TradeCheckUtil()
{
tf = null;
}
#region---交易要比较差异的字段----
///
/// 交易要比较差异的字段
///
public static IEnumerable GetCheckFields(trade td)
{
var fields = new List() {
nameof(td.ClientId),
nameof(td.SettlementDate),
nameof(td.BuySell),
nameof(td.ExerciseMode),
nameof(td.TradeSinglePrice),
nameof(td.TradeType),
nameof(td.ParticipationRate),
nameof(td.OriginalPrincipalSum),
nameof(td.PrincipalRateWrite),
nameof(td.SinglePrincipalWrite),
nameof(td.OptionType),
nameof(td.SettlementType),
nameof(td.TradeDate),
nameof(td.ExerciseDate),
nameof(td.IsAnnualized),
nameof(td.AnnualizeFactor),
nameof(td.IsMoneynessOption),
nameof(td.Strike),
nameof(td.PremiumRate),
nameof(td.SpotPrice),
nameof(td.TradePrice),
nameof(td.Notional),
nameof(td.TradeAmount),
nameof(td.StockEqvNotional),
nameof(td.StockEqvNotionalReal),
nameof(td.ExtendInfo),
"TradeAmountV",
};
var tradeType = td.TradeType == "结构化交易" ? td.StructureType : td.TradeType;
switch (tradeType)
{
case "亚式期权":
{
trade_asian_option ag;
fields.AddRange(new[] {
nameof(ag.PayoffType),
nameof(ag.SettleMode),
nameof(ag.StrikeType),
nameof(ag.AveragingPeriodStartDate),
nameof(ag.EnhancedPrice)
});
}
break;
case "二元期权":
{
trade_binary_option ag;
fields.AddRange(new[] {
nameof(ag.PayoffType),
nameof(ag.CashOrNothingAmount),
nameof(ag.CashOrNothingAmountRate),
nameof(tf.BarrierHigh),
nameof(ag.CashOrNothingAmountHigh),
nameof(ag.CashOrNothingAmountHighRate),
nameof(ag.MonitorType),
nameof(ag.RebateType),
});
}
break;
case "障碍期权":
{
trade_barrier_option ag;
fields.AddRange(new[] {
nameof(ag.BarrierType),
nameof(tf.BarrierLow),
nameof(tf.BarrierHigh),
nameof(ag.Rebate),
nameof(ag.RebateRate),
nameof(ag.RebateHigh),
nameof(ag.RebateHighRate),
nameof(ag.BarrierShift),
nameof(tf.MonitorType),
nameof(ag.RebateType),
});
}
break;
case "双鲨期权":
{
trade_double_sharkfin_option ag;
fields.AddRange(new[] {
nameof(ag.BarrierLow),
nameof(ag.BarrierHigh),
nameof(ag.StrikeHigh),
nameof(ag.Rebate),
nameof(ag.RebateHigh),
nameof(ag.RebateRate),
nameof(ag.RebateHighRate),
nameof(tf.MonitorType),
nameof(ag.RebateType),
nameof(ag.CallParticipationRate),
nameof(ag.PutParticipationRate),
});
}
break;
case "区间累积期权":
{
trade_rangeaccrual ag;
fields.AddRange(new[] {
nameof(ag.LowerRange),
nameof(ag.UpperRange),
nameof(ag.BonusRate)
});
}
break;
case "收益增强结构":
{
trade_underlying_enhance ag;
fields.AddRange(new[] {
nameof(ag.AnnualizedEnhanceRate)
});
}
break;
case "气囊结构":
{
trade_airbag ag;
fields.AddRange(new[] {
nameof(tf.BarrierLow),
nameof(ag.IsDiscreteMonitored),
nameof(ag.KIParticipationRate),
nameof(ag.NotKIParticipationRate),
nameof(ag.HasPayoffLimit),
nameof(ag.HighStrike)
});
}
break;
case "雪球期权":
{
trade_snowball ag;
fields.AddRange(new[] {
nameof(ag.KOBarrier),
nameof(ag.AnnualizedPremiumRate),
nameof(ag.KIBarrier),
nameof(ag.KORebate),
nameof(ag.Coupon),
nameof(ag.SpreadStrikeAtKO1),
nameof(ag.SpreadStrikeAtKO),
nameof(tf.SpreadStrike1),
nameof(tf.SpreadStrike),
nameof(ag.IsFixedCoupon),
nameof(ag.KORebateType),
nameof(ag.KOPayoffType),
nameof(ag.KIPayoffType),
nameof(ag.IsAnnualized2),
nameof(ag.AnnualizeFactor2),
nameof(ag.IsInitialKnockedIn),
});
}
break;
case "凤凰期权":
{
trade_autocall ag;
fields.AddRange(new[] {
nameof(ag.KOBarrier),
nameof(ag.KIBarrier),
nameof(ag.CouponBarrier),
nameof(ag.Coupon),
nameof(ag.SpreadStrike1),
nameof(ag.SpreadStrike),
nameof(ag.IsFixedCoupon),
nameof(ag.KIPayoffType),
nameof(ag.CouponPayType),
nameof(ag.IncludeCouponAfterKI),
nameof(ag.IsAnnualized2),
nameof(ag.AnnualizeFactor2),
});
}
break;
case "累计期权":
{
trade_accumulator_option ag;
fields.AddRange(new[] {
nameof(ag.KOBarrier),
nameof(ag.AccumuType),
nameof(ag.PayoffType),
nameof(ag.Coupon),
nameof(ag.Coupon2),
nameof(ag.CouponDayCount),
nameof(ag.IsFixedCoupon),
nameof(ag.CallMultiplier),
nameof(ag.PutMultiplier),
nameof(ag.EarlyTerminate),
nameof(ag.SettlementMode),
nameof(tf.StrikeGearingFactor),
nameof(ag.AccumuTradeAmount),
nameof(ag.ForwardPriceType),
nameof(ag.ForwardDateType),
nameof(ag.Strike2),
nameof(ag.Strike3),
nameof(ag.Multiplier),
nameof(ag.Multiplier2),
nameof(ag.Multiplier3),
nameof(ag.SettlementMode2),
nameof(ag.ForwardPriceType2),
nameof(ag.ForwardDateType2),
nameof(ag.SettlementMode3),
nameof(ag.ForwardPriceType3),
nameof(ag.ForwardDateType3),
nameof(ag.AccumulatorStructureType),
});
}
break;
case "现金流交易":
{
trade_cashflow ag;
fields.AddRange(new[] {
nameof(ag.ProfitRate),
nameof(ag.DepositType),
nameof(ag.RateType),
nameof(tf.CouponDayCount),
nameof(ag.PrepayRatio),
});
}
break;
case "Risky期权":
{
trade_risky_option ridky;
fields.AddRange(new[] {
nameof(ridky.Strike1),
nameof(ridky.Strike2),
nameof(ridky.Strike3),
});
}
break;
}
return fields;
}
#endregion
///
/// 获取差异
///
public static HashSet GetDiffs(trade sourceTrade, trade reviewTrade)
{
BLL.tradeBLL.SetFieldsByTradeType(sourceTrade);
var diffList = new HashSet(StringComparer.OrdinalIgnoreCase);
var tradeType = sourceTrade.TradeType == "结构化交易" ? sourceTrade.StructureType : sourceTrade.TradeType;
if (tradeType == "自定义交易")
{
CustomTradeCheck(sourceTrade, reviewTrade, diffList);
}
else if (tradeType == "远期")
{
ForwardTradeCheck(sourceTrade, reviewTrade, diffList);
}
else
{
BaseTradeCheck(sourceTrade, reviewTrade, diffList);
switch (tradeType)
{
case "香草期权":
case "合成价差期权":
break;
case "亚式期权":
AsianTradeCheck(sourceTrade, reviewTrade, diffList);
break;
case "二元期权":
BinaryTradeCheck(sourceTrade, reviewTrade, diffList);
break;
case "障碍期权":
BarrierTradeCheck(sourceTrade, reviewTrade, diffList);
break;
case "双鲨期权":
DoubleSharkTradeCheck(sourceTrade, reviewTrade, diffList);
break;
case "区间累积期权":
RangeAccrualTradeCheck(sourceTrade, reviewTrade, diffList);
break;
case "收益增强结构":
UnderlyingEnhanceTradeCheck(sourceTrade, reviewTrade, diffList);
break;
case "气囊结构":
AirBagTradeCheck(sourceTrade, reviewTrade, diffList);
break;
case "雪球期权":
SnowballTradeCheck(sourceTrade, reviewTrade, diffList);
break;
case "凤凰期权":
AutocallTradeCheck(sourceTrade, reviewTrade, diffList);
break;
case "累计期权":
AccumulatorTradeCheck(sourceTrade, reviewTrade, diffList);
break;
case "现金流交易":
CashflowTradeCheck(sourceTrade, reviewTrade, diffList);
break;
case "Risky期权":
RiskyTradeCheck(sourceTrade, reviewTrade, diffList);
break;
default:
if (sourceTrade.IsGroup == 1)
{
OtherGroupCheck(sourceTrade, reviewTrade, diffList);
}
break;
}
}
if (diffList.Contains(nameof(trade.ExtendInfo)))
{
foreach (var item in sourceTrade.Propertys)
{
var obj = reviewTrade.Propertys.FirstOrDefault(O => O.name == item.name);
if (obj == null || obj.value != item.value)
{
diffList.Add($"{item.name}");
}
}
}
return diffList;
}
#region----期权基本要素----
///
/// 期权基本要素
///
private static void BaseTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var innerCheck = new InnerCheck(sourceTrade, reviewTrade);
var t = sourceTrade;
innerCheck.AddCheckFields(new CheckField[] {
nameof(t.ClientId),
nameof(t.ParticipationRate),
nameof(t.BuySell),
nameof(t.ExerciseMode),
nameof(t.OptionType),
nameof(t.SettlementType),
nameof(t.TradeDate),
nameof(t.ExerciseDate),
nameof(t.SettlementDate),
nameof(t.SpotPrice),
nameof(t.IsAnnualized),
});
if (!string.IsNullOrEmpty(sourceTrade.ExtendInfo) && sourceTrade.ExtendInfo != "[]")
{
innerCheck.AddCheckFields(nameof(t.ExtendInfo));
}
if (reviewTrade.TradeType != "现金流交易")
{
innerCheck.AddCheckFields(new CheckField(nameof(t.IsMoneynessOption))
{
RecheckIfDiff = () => sourceTrade.IsMoneynessOption == "是" || reviewTrade.IsMoneynessOption == "是"
});
}
if (reviewTrade.TradeType != "雪球期权" && reviewTrade.TradeType != "凤凰期权")
{
innerCheck.AddCheckFields(nameof(t.Strike));
}
if (reviewTrade.TradeType != "累计期权")
{
innerCheck.AddCheckFields(nameof(t.TradePrice));
if (reviewTrade.IsUsePremiumRate == true)
{
innerCheck.AddCheckFields(new CheckField(nameof(t.StockEqvNotional)) { NumberPrecision = OtcFormatHelper.GetMaxPrecision(OtcFormatFlag.StockEqvNotional) }
, new CheckField(nameof(t.StockEqvNotionalReal)) { NumberPrecision = OtcFormatHelper.GetMaxPrecision(OtcFormatFlag.StockEqvNotional) });
}
else
{
innerCheck.AddCheckFields(nameof(t.Notional), nameof(t.TradeAmount));
}
}
else
{
if (sourceTrade.IsTradePricePayType)
{
innerCheck.AddCheckFields(nameof(t.TradePrice));
}
else
{
innerCheck.AddCheckFields(nameof(t.TradeSinglePrice));
}
}
if (reviewTrade.IsTradePricePayType == true || reviewTrade.TradeType == "现金流交易")
{
innerCheck.AddCheckFields(nameof(t.TradePrice));
}
else
{
innerCheck.AddCheckFields(reviewTrade.IsUsePremiumRate == true ? nameof(t.PremiumRate) : nameof(t.TradeSinglePrice));
}
if (sourceTrade.IsAnnualized)
{
innerCheck.AddCheckFields(nameof(t.AnnualizeFactor));
}
innerCheck.AddCheckFields(new CheckField(nameof(t.OriginalPrincipalSum)) { NumberPrecision = 2 });
innerCheck.GetDiffs(diffList);
#region 对TradeAmountV 进行验证 判断diffList列表是否含有 有效成交数量 tw 2021/12/22
if (diffList.Contains(nameof(t.TradeAmount)))
{
diffList.Add("TradeAmountV");
}
if (diffList.Contains(nameof(t.AnnualizeFactor)))
{
if (reviewTrade.IsAnnualized)
{
var arr1 = sourceTrade.MetaDic["AnnualizeFactor"].Split('/');
var arr2 = reviewTrade.MetaDic["AnnualizeFactor"].Split('/');
if (arr1.Length == 2 && arr2.Length == 2)
{
if (arr1[0] != arr2[0])
{
diffList.Add("AnnualizeFactorL");
}
if (arr1[1] != arr2[1])
{
diffList.Add("AnnualizeFactorR");
}
}
diffList.Remove("AnnualizeFactor");
}
}
#endregion
}
#endregion
#region----二元期权----
private static void BinaryTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_binary_option;
var rev = reviewTrade.trade_binary_option;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.PayoffType)
});
if (sourceTrade.ExerciseMode == "American")
{
diffList.Remove(nameof(sourceTrade.OptionType));
innerCheck.AddCheckFields(nameof(src.MonitorType));
if (!src.PayoffType.Contains("NoTouch"))
{
innerCheck.AddCheckFields(nameof(src.RebateType));
}
}
if (reviewTrade.IsUsePremiumRate == true)
{
innerCheck.AddCheckFields(nameof(src.CashOrNothingAmountRate));
}
else
{
innerCheck.AddCheckFields(nameof(src.CashOrNothingAmount));
}
if (src.PayoffType.IndexOf("Double") >= 0)
{
innerCheck.AddCheckFields(new CheckField(nameof(src.UpperBarrier), nameof(tf.BarrierHigh)));
if (reviewTrade.IsUsePremiumRate == true)
{
innerCheck.AddCheckFields(nameof(src.CashOrNothingAmountHighRate));
}
else
{
innerCheck.AddCheckFields(nameof(src.CashOrNothingAmountHigh));
}
}
innerCheck.GetDiffs(diffList);
}
#endregion
#region----亚式期权----
private static void AsianTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_asian_option;
var rev = reviewTrade.trade_asian_option;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.AveragingPeriodStartDate),
nameof(src.StrikeType),
nameof(src.PayoffType),
});
if (rev.PayoffType == "EnhancedArithmeticAverage")
{
innerCheck.AddCheckFields(nameof(src.SettleMode));
innerCheck.AddCheckFields(nameof(src.EnhancedPrice));
}
innerCheck.GetDiffs(diffList);
}
#endregion
#region----障碍期权----
private static void BarrierTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_barrier_option;
var rev = reviewTrade.trade_barrier_option;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
new CheckField(nameof(src.BarrierPrice),nameof(tf.BarrierLow)),
new CheckField(nameof(src.UpperBarrierPrice),nameof(tf.BarrierHigh)),
nameof(src.BarrierShift),
nameof(src.BarrierType),
new CheckField(nameof(src.Discrete), nameof(tf.MonitorType)),
//new CheckField(nameof(src.ObservationDates), ObservationRate),
nameof(src.RebateType),
});
if (reviewTrade.IsUsePremiumRate == true)
{
innerCheck.AddCheckFields(nameof(src.RebateRate), nameof(src.RebateHighRate));
}
else
{
innerCheck.AddCheckFields(nameof(src.Rebate), nameof(src.RebateHigh));
}
innerCheck.GetDiffs(diffList);
}
#endregion
#region----双鲨期权----
private static void DoubleSharkTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_double_sharkfin_option;
var rev = reviewTrade.trade_double_sharkfin_option;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.BarrierLow),
nameof(src.BarrierHigh),
nameof(src.StrikeHigh),
nameof(src.RebateType),
nameof(src.CallParticipationRate),
nameof(src.PutParticipationRate),
new CheckField(nameof(src.Discrete),nameof(tf.MonitorType))
});
if (reviewTrade.IsUsePremiumRate == true)
{
innerCheck.AddCheckFields(nameof(src.RebateRate), nameof(src.RebateHighRate));
}
else
{
innerCheck.AddCheckFields(nameof(src.Rebate), nameof(src.RebateHigh));
}
innerCheck.GetDiffs(diffList);
}
#endregion
#region----区间累积----
private static void RangeAccrualTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_rangeaccrual;
var rev = reviewTrade.trade_rangeaccrual;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.LowerRange),
nameof(src.UpperRange),
nameof(src.BonusRate),
});
innerCheck.GetDiffs(diffList);
//remove diff
diffList.Remove(nameof(tf.OptionType));
}
#endregion
#region----收益增强结构----
private static void UnderlyingEnhanceTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_underlying_enhance;
var rev = reviewTrade.trade_underlying_enhance;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.AnnualizedEnhanceRate),
});
innerCheck.GetDiffs(diffList);
//remove diff
diffList.Remove(nameof(tf.OptionType));
}
#endregion
#region----气囊结构----
private static void AirBagTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_airbag;
var rev = reviewTrade.trade_airbag;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.IsDiscreteMonitored),
nameof(src.KIParticipationRate),
nameof(src.NotKIParticipationRate),
nameof(src.HasPayoffLimit),
nameof(src.HighStrike),
new CheckField(nameof(src.Barrier), nameof(tf.BarrierLow))
});
innerCheck.GetDiffs(diffList);
//remove diff
diffList.Remove(nameof(tf.OptionType));
}
#endregion
#region----雪球期权----
private static void SnowballTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_snowball;
var rev = reviewTrade.trade_snowball;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.KOBarrier),
nameof(src.Coupon),
nameof(src.KORebateType),
nameof(src.KOPayoffType),
nameof(src.KIPayoffType),
nameof(src.IsAnnualized2),
nameof(src.AnnualizeFactor2),
});
if (src.KOPayoffType == KOPayoffTypeEnum.Rebate)
{
innerCheck.AddCheckFields(nameof(src.AnnualizedPremiumRate), nameof(src.KORebate), nameof(src.IsFixedCoupon));
}
else
{
innerCheck.AddCheckFields(nameof(src.SpreadStrikeAtKO1));
}
if (src.KOPayoffType == KOPayoffTypeEnum.ToSpreadOption)
{
innerCheck.AddCheckFields(nameof(src.SpreadStrikeAtKO));
}
if (src.KIPayoffType != KIPayoffTypeEnum.None)
{
innerCheck.AddCheckFields(new CheckField(nameof(src.SpreadStrikeAtMaturity1), nameof(tf.SpreadStrike1)));
}
if (src.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption || src.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption)
{
innerCheck.AddCheckFields(new CheckField(nameof(src.SpreadStrikeAtMaturity), nameof(tf.SpreadStrike)));
}
innerCheck.GetDiffs(diffList);
//remove diff
diffList.Remove(nameof(tf.IsAnnualized));
diffList.Remove(nameof(tf.AnnualizeFactor));
if (sourceTrade.OptionType != reviewTrade.OptionType && !diffList.Contains(nameof(tf.KOPayoffType)) && (src.KOPayoffType == KOPayoffTypeEnum.ToSpreadOption || src.KOPayoffType == KOPayoffTypeEnum.ToOption))
{
diffList.Add("KOPayoffType");
}
if (diffList.Contains(nameof(tf.AnnualizeFactor2)))
{
var arr1 = sourceTrade.MetaDic["AnnualizeFactor2"].Split('/');
var arr2 = reviewTrade.MetaDic["AnnualizeFactor2"].Split('/');
if (arr1.Length == 2 && arr2.Length == 2)
{
if (arr1[0] != arr2[0])
{
diffList.Add("AnnualizeFactor2L");
}
if (arr1[1] != arr2[1])
{
diffList.Add("AnnualizeFactor2R");
}
}
diffList.Remove("AnnualizeFactor2");
}
}
#endregion
#region----凤凰期权----
private static void AutocallTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_autocall;
var rev = reviewTrade.trade_autocall;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.KOBarrier),
nameof(src.KIBarrier),
nameof(src.CouponBarrier),
nameof(src.Coupon),
nameof(src.IsFixedCoupon),
nameof(src.KIPayoffType),
nameof(src.CouponPayType),
nameof(src.IncludeCouponAfterKI),
nameof(src.IsAnnualized2),
nameof(src.AnnualizeFactor2),
});
if (src.KIPayoffType != KIPayoffTypeEnum.None)
{
innerCheck.AddCheckFields(nameof(src.SpreadStrike1));
}
if (src.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption)
{
innerCheck.AddCheckFields(nameof(src.SpreadStrike));
}
innerCheck.GetDiffs(diffList);
//remove diff
diffList.Remove(nameof(tf.IsAnnualized));
diffList.Remove(nameof(tf.AnnualizeFactor));
}
#endregion
#region----累计期权----
private static void AccumulatorTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_accumulator_option;
var rev = reviewTrade.trade_accumulator_option;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.KOBarrier),
nameof(src.AccumulatorStructureType),
nameof(src.PayoffType),
nameof(src.EarlyTerminate),
nameof(src.SettlementMode),
nameof(src.AccumuTradeAmount)
});
if (src.AccumulatorStructureType == AccumulatorStructureTypeEnum.Segmented)
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.Strike2),
nameof(src.Strike3),
nameof(src.SettlementMode2),
nameof(src.SettlementMode3),
});
if (src.PayoffType == "固定")
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.Coupon),
nameof(src.Coupon2),
nameof(src.CouponDayCount),
nameof(src.IsFixedCoupon),
});
if (sourceTrade.OptionType == "看涨")
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.Multiplier),
});
}
else
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.Multiplier3),
});
}
}
else
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.Multiplier),
nameof(src.Multiplier2),
nameof(src.Multiplier3),
});
}
if (src.SettlementMode == "实物交割")
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.ForwardPriceType),
nameof(src.ForwardDateType)
});
}
if (src.SettlementMode2 == "实物交割")
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.ForwardPriceType2),
nameof(src.ForwardDateType2)
});
}
if (src.SettlementMode3 == "实物交割")
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.ForwardPriceType3),
nameof(src.ForwardDateType3)
});
}
}
else
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.AccumuType)
});
if (PS.Config.ErpElement.AccumulatorShowMultiplier1)
{
if (ConsGlobal.CallPut.IsCall(reviewTrade.CallPut))
{
src.StrikeGearingFactor = src.PutMultiplier;
}
else
{
src.StrikeGearingFactor = src.CallMultiplier;
}
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.StrikeGearingFactor)
});
}
else
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.CallMultiplier),
nameof(src.PutMultiplier)
});
}
if (src.PayoffType == "固定")
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.Coupon),
nameof(src.CouponDayCount),
nameof(src.IsFixedCoupon),
});
}
if (src.SettlementMode == "实物交割")
{
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.ForwardPriceType),
nameof(src.ForwardDateType)
});
}
}
innerCheck.GetDiffs(diffList);
}
#endregion
#region----现金流交易----
private static void CashflowTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_cashflow;
var rev = reviewTrade.trade_cashflow;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.ProfitRate),
nameof(src.DepositType),
nameof(src.PrepayRatio),
nameof(src.RateType),
new CheckField(nameof(src.ProfitDayCount), nameof(tf.CouponDayCount))
});
innerCheck.GetDiffs(diffList);
//remove diff
diffList.Remove(nameof(tf.ExerciseMode));
diffList.Remove(nameof(tf.StockEqvNotionalReal));
}
#endregion
#region----Risky交易----
private static void RiskyTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade.trade_risky_option;
var rev = reviewTrade.trade_risky_option;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.Strike1),
nameof(src.Strike2),
nameof(src.Strike3)
});
innerCheck.GetDiffs(diffList);
//remove diff
}
#endregion
#region----自定义交易----
private static void CustomTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var src = sourceTrade;
var rev = reviewTrade;
var innerCheck = new InnerCheck(src, rev);
innerCheck.AddCheckFields(new CheckField[] {
nameof(src.ClientId),
nameof(src.BuySell),
nameof(src.TradeDate),
nameof(src.ExerciseDate),
nameof(src.SpotPrice),
nameof(src.ExtendInfo),
nameof(src.ParticipationRate),
nameof(src.OriginalPrincipalSum),
nameof(src.SettlementDate)
});
if (src.IsUsePremiumRate == true)
{
innerCheck.AddCheckFields(new CheckField(nameof(src.StockEqvNotional)) { NumberPrecision = OtcFormatHelper.GetMaxPrecision(OtcFormatFlag.StockEqvNotional) });
}
else
{
innerCheck.AddCheckFields(nameof(src.TradeAmount), nameof(src.Notional));
}
if (src.IsTradePricePayType == true)
{
innerCheck.AddCheckFields(nameof(src.TradePrice));
}
else
{
if (src.IsUsePremiumRate == true)
{
innerCheck.AddCheckFields(nameof(src.PremiumRate));
}
else
{
innerCheck.AddCheckFields(nameof(src.TradeSinglePrice));
}
}
innerCheck.GetDiffs(diffList);
#region 对TradeAmountV 进行验证 判断错误列表是否含有 有效成交数量 tw 2021/12/22
if (diffList.Contains(nameof(src.TradeAmount)))
{
diffList.Add("TradeAmountV");
}
#endregion
}
#endregion
#region----远期交易----
private static void ForwardTradeCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
var innerCheck = new InnerCheck(sourceTrade, reviewTrade);
innerCheck.AddCheckFields(new CheckField[] {
nameof(sourceTrade.BuySell),
nameof(sourceTrade.TradeDate),
nameof(sourceTrade.ExerciseDate),
nameof(sourceTrade.SettlementDate),
nameof(sourceTrade.OptionType),
nameof(sourceTrade.Lots),
new CheckField(nameof(sourceTrade.SpotPrice),nameof(sourceTrade.InitialSpotPrice)),
nameof(sourceTrade.Strike),
nameof(sourceTrade.TradePrice),
});
if (PS.Config.Is浙期 && sourceTrade.UnderlyingInstrumentType == "CommoditySpot" && sourceTrade.TradeType == "远期")
{
if (sourceTrade.MetaDic.TryGetValue("ActualExerciseDate", out var ActualExerciseDateStr))
{
sourceTrade.ActualExerciseDate = Convert.ToDateTime(ActualExerciseDateStr);
innerCheck.AddCheckFields(new CheckField[] {
nameof(sourceTrade.ActualExerciseDate)
});
}
}
innerCheck.GetDiffs(diffList);
//forward
var src = sourceTrade.trade_forward;
var rev = reviewTrade.trade_forward;
var innerCheck2 = new InnerCheck(src, rev);
innerCheck2.AddCheckFields(new CheckField[] {
new CheckField(nameof(src.OpenCommission),"trade_forward.OpenCommission"),
});
innerCheck2.GetDiffs(diffList);
}
#endregion
#region----组合主交易----
private static void OtherGroupCheck(trade sourceTrade, trade reviewTrade, HashSet diffList)
{
if (sourceTrade.ExtendInfo != reviewTrade.ExtendInfo && sourceTrade.StructureType != "气囊结构")
{
diffList.Add(nameof(sourceTrade.ExtendInfo));
}
//remove diff
diffList.Remove(nameof(sourceTrade.OptionType));
diffList.Remove(nameof(sourceTrade.ExerciseMode));
}
#endregion
#region----保存交易复核----
///
/// 保存交易复核
///
public static void SaveTradeCheck(trade sourceTrade, trade reviewTrade, int optId, string optName)
{
if (reviewTrade is null)
{
throw new ArgumentNullException(nameof(reviewTrade));
}
using (var db = DbContextFactory.GetYLDbContext())
{
var tradeCheck = db.trade_check.FirstOrDefault(t => t.TradeId == sourceTrade.id && t.ValidState != ConsGlobal.InValid);
if (tradeCheck == null)
{
tradeCheck = new trade_check
{
TradeId = sourceTrade.id
};
db.trade_check.Add(tradeCheck);
}
tradeCheck.OptId = optId;
tradeCheck.OptName = optName;
tradeCheck.OptDate = DateTime.Now;
tradeCheck.ValidState = ConsGlobal.Valid;
tradeCheck.TradeObject = reviewTrade.ToJson();
db.SaveChanges();
}
}
#endregion
#region----内部类----
class CheckField
{
public CheckField(string fieldName, string diffName = null)
{
FieldName = fieldName ?? throw new ArgumentNullException(nameof(fieldName));
DiffName = diffName;
}
///
/// 字段名
///
public string FieldName { get; }
///
/// 差异时使用的名称
///
public string DiffName { get; }
///
/// 差异时重新检查并以返回的结果为准
///
public Func RecheckIfDiff { get; set; }
///
/// 数字小数精度
///
public int? NumberPrecision { get; set; }
public static implicit operator CheckField(string fieldName)
{
return new CheckField(fieldName);
}
public override string ToString()
{
return $"{FieldName}--precision:{NumberPrecision}--diff name: {DiffName}";
}
}
class InnerCheck where T : class
{
readonly T _src, _rev;
readonly ParameterExpression _instance;
readonly List _checkFields;
public InnerCheck(T src, T rev)
{
_src = src ?? throw new ArgumentNullException(nameof(src));
_rev = rev ?? throw new ArgumentNullException(nameof(rev));
_checkFields = new List();
_instance = Expression.Parameter(typeof(T), "instance");
}
///
/// 浮点数最小差额,默认1e-6
///
public double DoubleMinDiff { get; set; } = 1e-6;
public void AddCheckFields(params CheckField[] fields)
{
_checkFields.AddRange(fields);
}
///
/// 检查多个字段不同
///
///
public void GetDiffs(HashSet diffList)
{
if (_checkFields is null)
{
return;
}
foreach (var f in _checkFields)
{
CheckDiff(f, diffList);
}
}
///
/// 检查单个字段不同
///
private void CheckDiff(CheckField field, HashSet diffList)
{
if (field is null)
{
throw new ArgumentNullException(nameof(field));
}
var property = Expression.Property(_instance, field.FieldName);
var convert = Expression.Convert(property, typeof(object));
var getter = Expression.Lambda>(convert, _instance).Compile();
var srcValue = getter(_src);
var revValue = getter(_rev);
var propInfo = (PropertyInfo)property.Member;
if (!IsEquals(propInfo.PropertyType, srcValue, revValue, field.NumberPrecision))
{
if (field.RecheckIfDiff != null && field.RecheckIfDiff())
{
diffList.Add(field.DiffName ?? field.FieldName);
}
else
{
diffList.Add(field.DiffName ?? field.FieldName);
}
}
}
private bool IsEquals(Type propType, object srcValue, object revValue, int? precision)
{
if (propType == typeof(string))
{
var srcStr = (srcValue?.ToString()?.TrimToNull()) ?? string.Empty;
var revStr = (revValue?.ToString()?.TrimToNull()) ?? string.Empty;
return string.Equals(srcStr, revStr);
}
if (propType == typeof(double?))
{
return IsEquals((double?)srcValue, (double?)revValue, precision);
}
if (propType == typeof(double))
{
return IsEquals((double)srcValue, (double)revValue, precision);
}
return string.Equals(srcValue?.ToString(), revValue?.ToString());
}
///
/// 判断两个double?的值是否相同
///
private bool IsEquals(double? d1, double? d2, int? precision)
{
var minDiff = precision.HasValue ? 1 / Math.Pow(10, precision.Value) : DoubleMinDiff;
return Math.Abs((d1 ?? 0) - (d2 ?? 0)) < minDiff;
}
///
/// 判断两个double的值是否相同
///
private bool IsEquals(double d1, double d2, int? precision)
{
var minDiff = precision.HasValue ? 1 / Math.Pow(10, precision.Value) : DoubleMinDiff;
return Math.Abs(d1 - d2) < minDiff;
}
}
#endregion
}
}