1786 lines
111 KiB
C#
1786 lines
111 KiB
C#
using System.Data;
|
|
using YLErp.BLL;
|
|
using YLErp.Commons;
|
|
using YLErp.DBModels.Consts;
|
|
using YLErp.DBModels.Helpers;
|
|
using YLErp.Model;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.Modules.UnderlyingModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.TradeModule.DealModule
|
|
{
|
|
/// <summary>
|
|
/// 除权除息操作(请使用正常英文单词)
|
|
/// </summary>
|
|
public class DividendService : YLBaseService
|
|
{
|
|
public DividendService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 场内交易除权除息
|
|
/// </summary>
|
|
/// <param name="settleDate">除权日</param>
|
|
/// <param name="positions">持仓列表</param>
|
|
public List<BodTradePosition> Execute(DateTime settleDate, IEnumerable<EodTradePosition> positions)
|
|
{
|
|
var result = new List<BodTradePosition>();
|
|
var dict = DbContext.ex_dividend_info.Where(O => O.ValidStatus && O.ExDividendDate == settleDate).ToDictionary(K => K.UnderlyingId, V => V);
|
|
foreach (var item in positions)
|
|
{
|
|
double cost = item.Cost,
|
|
amount = item.Amount;
|
|
//averagePrice = item.AveragePrice;
|
|
var bodPosition = new BodTradePosition();
|
|
if (dict.ContainsKey(item.UnderlyingId))
|
|
{
|
|
var averagePrice = Math.Abs(item.Cost / item.Amount);
|
|
amount = GetPositionAmount(amount, dict[item.UnderlyingId]);
|
|
averagePrice = GetPrice(averagePrice, dict[item.UnderlyingId]);
|
|
cost = amount * averagePrice;
|
|
}
|
|
bodPosition.ValueDate = settleDate;
|
|
bodPosition.HedgeUniqueCode = item.HedgeUniqueCode;
|
|
bodPosition.ExchangeOptionCode = item.ExchangeOptionCode;
|
|
bodPosition.TradeType = item.TradeType;
|
|
bodPosition.PositionType = item.PositionType;
|
|
bodPosition.BookId = item.BookId;
|
|
bodPosition.UnderlyingId = item.UnderlyingId;
|
|
bodPosition.UnderlyingCode = item.UnderlyingCode;
|
|
bodPosition.BuySell = item.BuySell;
|
|
bodPosition.Cost = cost;
|
|
bodPosition.Amount = amount;
|
|
//bodPosition.AveragePrice = averagePrice;
|
|
bodPosition.Commission = item.Commission;
|
|
bodPosition.OptId = item.OptId;
|
|
bodPosition.OptName = item.OptName;
|
|
bodPosition.OptDate = DateTime.Now;
|
|
result.Add(bodPosition);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 场外交易除权除息
|
|
/// </summary>
|
|
/// <param name="settleDate">除权日</param>
|
|
/// <param name="trades">交易列表</param>
|
|
/// <param name="saveToDb">是否将结果保存到trade表</param>
|
|
/// <returns></returns>
|
|
public List<bod_trade> Execute(DateTime settleDate, IEnumerable<trade> trades, out List<trade> useSaveTrades, out List<underlying_manager> useSaveUndedrlyings)
|
|
{
|
|
useSaveTrades = new List<trade>();
|
|
useSaveUndedrlyings = new List<underlying_manager>();
|
|
var result = new List<bod_trade>();
|
|
var dict = DbContext.ex_dividend_info.Where(O => O.ValidStatus && O.ExDividendDate == settleDate).ToDictionary(K => K.UnderlyingId, V => V);
|
|
var tradeIds = trades.Select(O => O.id);
|
|
var dividendRatioDict = new DbRecordChangesService<TradeChanges>(this).GetValue(ConsInfoChangeType.UserChange, tradeIds, nameof(trade.DividendRatio), settleDate).ToDictionary(K => K.RecordId, V => { return double.TryParse(V.NewValue, out var temp) ? (double?)temp : null; });
|
|
foreach (var t in trades)
|
|
{
|
|
var bodTrade = new bod_trade();
|
|
if (dict.TryGetValue(t.UnderlyingId, out var dividendInfo))
|
|
{
|
|
var ratio = dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null;
|
|
//避免该字段为NULL时amount和notion不一致
|
|
//股票的amount和notion应相等
|
|
var unwindNotional = t.OriginalNotional - t.Notional;
|
|
t.TradeOriginalAmount = t.TradeOriginalAmount ?? t.OriginalNotional;
|
|
t.SpotPrice = GetPrice(t.SpotPrice, dividendInfo, ratio);
|
|
|
|
var annualizeFactor = t.AnnualizeFactor;
|
|
if (t.TradeType == "凤凰期权")
|
|
{
|
|
annualizeFactor = t.trade_autocall.AnnualizeFactor2;
|
|
}
|
|
else if (t.TradeType == "雪球期权")
|
|
{
|
|
annualizeFactor = t.trade_snowball.AnnualizeFactor2;
|
|
}
|
|
t.StockEqvNotionalReal = t.StockEqvNotionalReal == 0 ? TradeHelper.GetStockEqvNotionalReal(t.OriginalStockEqvNotional, t.ParticipationRate, annualizeFactor) : t.StockEqvNotionalReal;
|
|
t.OriginalNotional = t.StockEqvNotionalReal / t.SpotPrice;
|
|
t.TradeOriginalAmount = t.OriginalNotional / (t.CountRatio ?? 1);
|
|
//不管是不是名义本金方式了结,都应该按照比例了结。--时嬴政
|
|
//if (t.IsUsePremiumRate.HasValue && t.IsUsePremiumRate.Value)
|
|
//{
|
|
var settlePercent = (t.StockEqvNotional / t.OriginalStockEqvNotional) ?? 0;
|
|
t.Notional = (t.OriginalNotional * settlePercent) ?? 0;
|
|
t.TradeAmount = (t.TradeOriginalAmount * settlePercent) ?? 0;
|
|
//}
|
|
//else
|
|
//{
|
|
// t.Notional = (t.OriginalNotional - unwindNotional) ?? 0;
|
|
// t.TradeAmount = (t.TradeOriginalAmount - unwindNotional) ?? 0;
|
|
//}
|
|
|
|
t.TradeSinglePrice = TradeHelper.GetTradeSinglePriceByTradePrice(t.TradePrice, t.OriginalNotional, t.PrincipalSum(), t.BuySell, t.TradeType, true);
|
|
if (t.TradeType == "彩虹期权")
|
|
{
|
|
t.trade_rainbow_option.SpotPrice1 = GetPrice(t.trade_rainbow_option.SpotPrice1, dividendInfo, ratio);
|
|
t.trade_rainbow_option.SpotPrice2 = GetPrice(t.trade_rainbow_option.SpotPrice2, dividendInfo, ratio);
|
|
}
|
|
if (!t.IsMoneynessOptionData)
|
|
{
|
|
t.Strike = GetPrice(t.Strike, dividendInfo, ratio);
|
|
switch (t.TradeType)
|
|
{
|
|
case "亚式期权":
|
|
//获取fixings的时候,函数内部处理除权除息逻辑;
|
|
break;
|
|
case "障碍期权":
|
|
t.trade_barrier_option.BarrierPrice = GetPrice(t.trade_barrier_option.BarrierPrice, dividendInfo, ratio);
|
|
t.trade_barrier_option.UpperBarrierPrice = GetPrice(t.trade_barrier_option.UpperBarrierPrice, dividendInfo, ratio);
|
|
break;
|
|
case "彩虹期权":
|
|
t.trade_rainbow_option.Strike = GetPrice(t.trade_rainbow_option.Strike, dividendInfo, ratio);
|
|
t.trade_rainbow_option.Strike2 = GetPrice(t.trade_rainbow_option.Strike2, dividendInfo, ratio);
|
|
break;
|
|
case "凤凰期权":
|
|
t.trade_autocall.KIBarrier = GetPrice(t.trade_autocall.KIBarrier, dividendInfo, ratio);
|
|
t.trade_autocall.KOBarrier = GetPrice(t.trade_autocall.KOBarrier, dividendInfo, ratio);
|
|
t.trade_autocall.CouponBarrier = GetPrice(t.trade_autocall.CouponBarrier, dividendInfo, ratio);
|
|
t.trade_autocall.SpreadStrike = GetPrice(t.trade_autocall.SpreadStrike, dividendInfo, ratio);
|
|
t.trade_autocall.SpreadStrike1 = GetPrice(t.trade_autocall.SpreadStrike1, dividendInfo, ratio);
|
|
var obsInfos = QdpHelper.ParseAutocallCustomizedInfo(t.trade_autocall.KOObservationDates);
|
|
for (var i = 0; i < obsInfos.Item2.Length; i++)
|
|
{
|
|
obsInfos.Item2[i] = GetPrice(obsInfos.Item2[i], dividendInfo, ratio);
|
|
}
|
|
t.trade_autocall.KOObservationDates = $"{string.Join(",", obsInfos.Item1.Select(O => O.ToString()))};{string.Join(",", obsInfos.Item2.Select(O => O.OtcFormatUmPrice()))};{string.Join(",", obsInfos.Item3.Select(O => O.OtcFormatFlex(2)))}";
|
|
break;
|
|
case "双鲨期权":
|
|
t.trade_double_sharkfin_option.BarrierHigh = GetPrice(t.trade_double_sharkfin_option.BarrierHigh, dividendInfo, ratio);
|
|
t.trade_double_sharkfin_option.BarrierLow = GetPrice(t.trade_double_sharkfin_option.BarrierLow, dividendInfo, ratio);
|
|
t.trade_double_sharkfin_option.StrikeHigh = GetPrice(t.trade_double_sharkfin_option.StrikeHigh, dividendInfo, ratio);
|
|
t.trade_double_sharkfin_option.StrikeLow = GetPrice(t.trade_double_sharkfin_option.StrikeLow, dividendInfo, ratio);
|
|
break;
|
|
case "区间累积期权":
|
|
t.trade_rangeaccrual.LowerRange = GetPrice(t.trade_rangeaccrual.LowerRange, dividendInfo, ratio);
|
|
t.trade_rangeaccrual.UpperRange = GetPrice(t.trade_rangeaccrual.UpperRange, dividendInfo, ratio);
|
|
break;
|
|
case "雪球期权":
|
|
t.trade_snowball.KIBarrier = GetPrice(t.trade_snowball.KIBarrier, dividendInfo, ratio);
|
|
t.trade_snowball.KOBarrier = GetPrice(t.trade_snowball.KOBarrier, dividendInfo, ratio);
|
|
t.trade_snowball.SpreadStrikeAtKO = GetPrice(t.trade_snowball.SpreadStrikeAtKO, dividendInfo, ratio);
|
|
t.trade_snowball.SpreadStrikeAtKO1 = GetPrice(t.trade_snowball.SpreadStrikeAtKO1, dividendInfo, ratio);
|
|
t.trade_snowball.SpreadStrikeAtMaturity = GetPrice(t.trade_snowball.SpreadStrikeAtMaturity, dividendInfo, ratio);
|
|
t.trade_snowball.SpreadStrikeAtMaturity1 = GetPrice(t.trade_snowball.SpreadStrikeAtMaturity1, dividendInfo, ratio);
|
|
obsInfos = QdpHelper.ParseAutocallCustomizedInfo(t.trade_snowball.KOObservationDates);
|
|
for (var i = 0; i < obsInfos.Item2.Length; i++)
|
|
{
|
|
obsInfos.Item2[i] = GetPrice(obsInfos.Item2[i], dividendInfo, ratio);
|
|
}
|
|
t.trade_snowball.KOObservationDates = $"{string.Join(",", obsInfos.Item1.Select(O => O.ToString()))};{string.Join(",", obsInfos.Item2.Select(O => O.OtcFormatUmPrice()))};{string.Join(",", obsInfos.Item3.Select(O => O.OtcFormatFlex(2)))}";
|
|
break;
|
|
case "气囊结构":
|
|
t.trade_airbag.Barrier = GetPrice(t.trade_airbag.Barrier, dividendInfo, ratio);
|
|
t.trade_airbag.HighStrike = GetPrice(t.trade_airbag.HighStrike, dividendInfo, ratio);
|
|
break;
|
|
case "累计期权":
|
|
t.trade_accumulator_option.KOBarrier = GetPrice(t.trade_accumulator_option.KOBarrier, dividendInfo, ratio);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (t.TradeType == "累计期权")
|
|
{
|
|
var customObservDates = QdpHelper.ParseObservationDate(t.trade_accumulator_option.KOObservationDates);
|
|
if (customObservDates == null)
|
|
{
|
|
customObservDates = Qdp.Pricing.Base.Implementations.CalendarImpl.Get("chn")
|
|
.BizDaysBetweenDatesExcluStartDay(t.TradeDate.Value, t.ExerciseDate.Value).ToArray();
|
|
}
|
|
var unwindPercent = t.trade_accumulator_option.AccumuTradeAmount / t.trade_accumulator_option.OriginalAccumuTradeAmount;
|
|
t.trade_accumulator_option.OriginalAccumuTradeAmount = (t.OriginalNotional ?? 0) / (t.CountRatio ?? 1) / customObservDates.Length;
|
|
t.trade_accumulator_option.AccumuTradeAmount = t.trade_accumulator_option.OriginalAccumuTradeAmount * unwindPercent;
|
|
}
|
|
|
|
t.DividendDate = settleDate;
|
|
useSaveTrades.Add(t);
|
|
}
|
|
if (t.TradeType == "收益互换")
|
|
{
|
|
var originalNotional = 0d;
|
|
var notional = 0d;
|
|
if ((t.trade_swap.PayUnderlyingId ?? 0) > 0)
|
|
{
|
|
if (t.pay_trade_swap_details?.Count > 0)
|
|
{
|
|
double? ratio = 0d;
|
|
foreach (var item in t.pay_trade_swap_details)
|
|
{
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode);
|
|
if (dict.TryGetValue(um.id, out dividendInfo))
|
|
{
|
|
ratio = dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null;
|
|
var unwindNotional = item.OriginalNotional - item.Notional;
|
|
var OriginalStockEqvNotional = item.SpotPrice * item.OriginalNotional;
|
|
var StockEqvNotional = item.SpotPrice * item.Notional;
|
|
|
|
item.SpotPrice = GetPrice(item.SpotPrice, dividendInfo, ratio);
|
|
item.OriginalNotional = OriginalStockEqvNotional / item.SpotPrice;
|
|
if (t.IsUsePremiumRate.HasValue && t.IsUsePremiumRate.Value)
|
|
{
|
|
var settlePercent = (StockEqvNotional / OriginalStockEqvNotional) ?? 0;
|
|
item.Notional = (item.OriginalNotional * settlePercent) ?? 0;
|
|
}
|
|
else
|
|
{
|
|
item.Notional = (item.OriginalNotional - unwindNotional) ?? 0;
|
|
}
|
|
}
|
|
}
|
|
originalNotional = t.pay_trade_swap_details.Sum(O => O.OriginalNotional ?? 0);
|
|
notional = t.pay_trade_swap_details.Sum(O => O.Notional ?? 0);
|
|
if (!useSaveTrades.Contains(t))
|
|
{
|
|
t.DividendDate = settleDate;
|
|
useSaveTrades.Add(t);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
originalNotional = t.OriginalNotional ?? 1;
|
|
notional = t.Notional;
|
|
var useDividend = false;
|
|
double? ratio = 0d;
|
|
var payUm = DataCacheProvider.GetUnderlyingDataSource().GetData(t.trade_swap.PayUnderlyingId.Value);
|
|
if (payUm.IsBasket() && payUm.SubData != null)
|
|
{
|
|
var umchanges = new DbRecordChangesService<UnderlyingChanges>(this).GetValue(ConsInfoChangeType.Dividend, payUm.id, nameof(underlying_manager.SubData), settleDate);
|
|
if (umchanges != null)
|
|
{
|
|
payUm.SubData = umchanges.FieldValue;
|
|
}
|
|
else
|
|
{
|
|
useSaveUndedrlyings.Add(payUm);
|
|
}
|
|
var data = JsonHelper.Deserialize<List<BasketUnderlyingItem>>(payUm.SubData);
|
|
var originWeight = data.Sum(O => O.weight);
|
|
foreach (var item in data)
|
|
{
|
|
var tempUm = DataCacheProvider.GetUnderlyingDataSource().GetData(item.code);
|
|
if (dict.TryGetValue(tempUm?.id ?? 0, out dividendInfo))
|
|
{
|
|
ratio = (dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null) ?? GetRatio(dividendInfo);
|
|
item.weight *= ratio.Value;
|
|
useDividend = true;
|
|
}
|
|
}
|
|
payUm.SubData = data.ToJson();
|
|
useSaveUndedrlyings.Add(payUm);
|
|
var newWeight = data.Sum(O => O.weight);
|
|
ratio = newWeight / originWeight;
|
|
}
|
|
else
|
|
{
|
|
if (dict.TryGetValue(t.trade_swap.PayUnderlyingId ?? 0, out dividendInfo))
|
|
{
|
|
ratio = dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null;
|
|
useDividend = true;
|
|
}
|
|
}
|
|
if (useDividend)
|
|
{
|
|
t.trade_swap.PaySpotPrice = GetPrice(t.trade_swap.PaySpotPrice, dividendInfo, ratio);
|
|
t.StockEqvNotionalReal = t.StockEqvNotionalReal == 0 ? TradeHelper.GetStockEqvNotionalReal(t.OriginalStockEqvNotional, t.ParticipationRate, t.AnnualizeFactor) : t.StockEqvNotionalReal;
|
|
t.trade_swap.PayNotional = t.StockEqvNotionalReal / t.trade_swap.PaySpotPrice;
|
|
//设置交易数量
|
|
var underlyingManager = DataCacheProvider.GetUnderlyingDataSource().GetData(t.trade_swap.PayUnderlyingCode);
|
|
var CountRatio = underlyingManager?.CountRatio ?? 1;
|
|
t.trade_swap.PayTradeAmount = t.trade_swap.PayNotional / CountRatio;
|
|
t.DividendDate = settleDate;
|
|
originalNotional = NumberHelper.Normalize(t.OriginalStockEqvNotional / t.trade_swap.PaySpotPrice);
|
|
notional = NumberHelper.Normalize(t.StockEqvNotional / t.trade_swap.PaySpotPrice);
|
|
if (!useSaveTrades.Contains(t))
|
|
{
|
|
t.DividendDate = settleDate;
|
|
useSaveTrades.Add(t);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ((t.trade_swap.GetUnderlyingId ?? 0) > 0)
|
|
{
|
|
if (t.get_trade_swap_details?.Count > 0)
|
|
{
|
|
double? ratio = 0d;
|
|
foreach (var item in t.get_trade_swap_details)
|
|
{
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode);
|
|
if (dict.TryGetValue(um.id, out dividendInfo))
|
|
{
|
|
ratio = dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null;
|
|
var unwindNotional = item.OriginalNotional - item.Notional;
|
|
var OriginalStockEqvNotional = item.SpotPrice * item.OriginalNotional;
|
|
var StockEqvNotional = item.SpotPrice * item.Notional;
|
|
|
|
item.SpotPrice = GetPrice(item.SpotPrice, dividendInfo, ratio);
|
|
item.OriginalNotional = OriginalStockEqvNotional / item.SpotPrice;
|
|
if (t.IsUsePremiumRate.HasValue && t.IsUsePremiumRate.Value)
|
|
{
|
|
var settlePercent = (StockEqvNotional / OriginalStockEqvNotional) ?? 0;
|
|
item.Notional = (item.OriginalNotional * settlePercent) ?? 0;
|
|
}
|
|
else
|
|
{
|
|
item.Notional = (item.OriginalNotional - unwindNotional) ?? 0;
|
|
}
|
|
}
|
|
}
|
|
originalNotional = t.get_trade_swap_details.Sum(O => O.OriginalNotional ?? 0);
|
|
notional = t.get_trade_swap_details.Sum(O => O.Notional ?? 0);
|
|
if (!useSaveTrades.Contains(t))
|
|
{
|
|
t.DividendDate = settleDate;
|
|
useSaveTrades.Add(t);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
originalNotional = t.OriginalNotional ?? 1;
|
|
notional = t.Notional;
|
|
double? ratio = 0d;
|
|
var useDividend = false;
|
|
var getUm = DataCacheProvider.GetUnderlyingDataSource().GetData(t.trade_swap.GetUnderlyingId.Value);
|
|
if (getUm.IsBasket() && getUm.SubData != null)
|
|
{
|
|
var umchanges = new DbRecordChangesService<UnderlyingChanges>(this).GetValue(ConsInfoChangeType.Dividend, getUm.id, nameof(underlying_manager.SubData), settleDate);
|
|
if (umchanges != null)
|
|
{
|
|
getUm.SubData = umchanges.FieldValue;
|
|
}
|
|
else
|
|
{
|
|
useSaveUndedrlyings.Add(getUm);
|
|
}
|
|
var data = JsonHelper.Deserialize<List<BasketUnderlyingItem>>(getUm.SubData);
|
|
var originWeight = data.Sum(O => O.weight);
|
|
foreach (var item in data)
|
|
{
|
|
var tempUm = DataCacheProvider.GetUnderlyingDataSource().GetData(item.code);
|
|
if (dict.TryGetValue(tempUm?.id ?? 0, out dividendInfo))
|
|
{
|
|
ratio = (dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null) ?? GetRatio(dividendInfo);
|
|
item.weight *= ratio.Value;
|
|
useDividend = true;
|
|
}
|
|
}
|
|
getUm.SubData = data.ToJson();
|
|
var newWeight = data.Sum(O => O.weight);
|
|
ratio = newWeight / originWeight;
|
|
}
|
|
else
|
|
{
|
|
if (dict.TryGetValue(t.trade_swap.GetUnderlyingId ?? 0, out dividendInfo))
|
|
{
|
|
ratio = dividendRatioDict.ContainsKey(t.id) ? dividendRatioDict[t.id] : null;
|
|
useDividend = true;
|
|
}
|
|
}
|
|
if (useDividend)
|
|
{
|
|
t.trade_swap.GetSpotPrice = GetPrice(t.trade_swap.GetSpotPrice, dividendInfo, ratio);
|
|
t.StockEqvNotionalReal = t.StockEqvNotionalReal == 0 ? TradeHelper.GetStockEqvNotionalReal(t.OriginalStockEqvNotional, t.ParticipationRate, t.AnnualizeFactor) : t.StockEqvNotionalReal;
|
|
t.trade_swap.GetNotional = t.StockEqvNotionalReal / t.trade_swap.GetSpotPrice;
|
|
//设置交易数量
|
|
var underlyingManager = DataCacheProvider.GetUnderlyingDataSource().GetData(t.trade_swap.GetUnderlyingCode);
|
|
var CountRatio = underlyingManager?.CountRatio ?? 1;
|
|
t.trade_swap.GetTradeAmount = t.trade_swap.GetNotional / CountRatio;
|
|
t.DividendDate = settleDate;
|
|
originalNotional = NumberHelper.Normalize(t.OriginalStockEqvNotional / t.trade_swap.GetSpotPrice);
|
|
notional = NumberHelper.Normalize(t.StockEqvNotional / t.trade_swap.GetSpotPrice);
|
|
if (!useSaveTrades.Contains(t))
|
|
{
|
|
t.DividendDate = settleDate;
|
|
useSaveTrades.Add(t);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
t.OriginalNotional = originalNotional;
|
|
t.TradeOriginalAmount = originalNotional;
|
|
t.Notional = notional;
|
|
}
|
|
bodTrade.AssetId = t.AssetId;
|
|
bodTrade.ClientId = t.ClientId;
|
|
bodTrade.OptDate = DateTime.Now;
|
|
bodTrade.ParentTradeId = t.ParentTradeId;
|
|
bodTrade.TradeId = t.id;
|
|
bodTrade.TradeNumber = t.TradeNumber;
|
|
bodTrade.TradeStatus = t.TradeStatus;
|
|
bodTrade.TradeType = t.TradeType;
|
|
bodTrade.UnderlyingCode = t.UnderlyingCode;
|
|
bodTrade.UnderlyingId = t.UnderlyingId;
|
|
bodTrade.ValueDate = settleDate;
|
|
bodTrade.TradeJson = TradeHelper2.Serialize(t, settleDate);
|
|
result.Add(bodTrade);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public static List<TradeChanges> GetDividendChanges(trade trade, trade NewValue)
|
|
{
|
|
TradeChanges compar(double? originValue, double? newValue, params string[] fieldName)
|
|
{
|
|
TradeChanges tc = null;
|
|
if ((originValue == null && newValue != null) || (originValue != null && newValue == null) || originValue != newValue || (ConsGlobal.IgnoreTSV((originValue ?? 0) - (newValue ?? 0)) != 0))
|
|
{
|
|
tc = new TradeChanges
|
|
{
|
|
ChangeType = ConsInfoChangeType.Dividend,
|
|
RecordId = trade.id,
|
|
FieldName = string.Join(".", fieldName),
|
|
FieldValue = originValue?.ToString() ?? "",
|
|
NewValue = newValue?.ToString() ?? "",
|
|
OptDate = NewValue.DividendDate,
|
|
Update = DateTime.Now
|
|
};
|
|
}
|
|
return tc;
|
|
}
|
|
TradeChanges comparStr(string originValue, string newValue, params string[] fieldName)
|
|
{
|
|
TradeChanges tc = null;
|
|
if ((originValue == null && newValue != null) || (originValue != null && newValue == null) || originValue != newValue)
|
|
{
|
|
tc = new TradeChanges
|
|
{
|
|
ChangeType = ConsInfoChangeType.Dividend,
|
|
RecordId = trade.id,
|
|
FieldName = string.Join(".", fieldName),
|
|
FieldValue = originValue ?? "",
|
|
NewValue = newValue ?? "",
|
|
OptDate = NewValue.DividendDate,
|
|
Update = DateTime.Now
|
|
};
|
|
}
|
|
return tc;
|
|
}
|
|
|
|
var list = new List<TradeChanges>
|
|
{
|
|
compar(trade.SpotPrice, NewValue.SpotPrice, nameof(trade.SpotPrice)),
|
|
compar(trade.OriginalNotional, NewValue.OriginalNotional, nameof(trade.OriginalNotional)),
|
|
compar(trade.TradeOriginalAmount ?? trade.OriginalNotional, NewValue.TradeOriginalAmount, nameof(trade.TradeOriginalAmount)),
|
|
compar(trade.Notional, NewValue.Notional, nameof(trade.Notional)),
|
|
compar(trade.TradeAmount, NewValue.TradeAmount, nameof(trade.TradeAmount)),
|
|
compar(trade.TradeSinglePrice, NewValue.TradeSinglePrice, nameof(trade.TradeSinglePrice)),
|
|
compar(trade.Strike, NewValue.Strike, nameof(trade.Strike))
|
|
};
|
|
|
|
switch (trade.TradeType)
|
|
{
|
|
case "障碍期权":
|
|
list.Add(compar(trade.trade_barrier_option.BarrierPrice, NewValue.trade_barrier_option.BarrierPrice, nameof(trade.trade_barrier_option), nameof(trade.trade_barrier_option.BarrierPrice)));
|
|
list.Add(compar(trade.trade_barrier_option.UpperBarrierPrice, NewValue.trade_barrier_option.UpperBarrierPrice, nameof(trade.trade_barrier_option), nameof(trade.trade_barrier_option.UpperBarrierPrice)));
|
|
break;
|
|
case "彩虹期权":
|
|
list.Add(compar(trade.trade_rainbow_option.SpotPrice1, NewValue.trade_rainbow_option.SpotPrice1, nameof(trade.trade_rainbow_option), nameof(trade.trade_rainbow_option.SpotPrice1)));
|
|
list.Add(compar(trade.trade_rainbow_option.SpotPrice2, NewValue.trade_rainbow_option.SpotPrice2, nameof(trade.trade_rainbow_option), nameof(trade.trade_rainbow_option.SpotPrice2)));
|
|
list.Add(compar(trade.trade_rainbow_option.Strike, NewValue.trade_rainbow_option.Strike, nameof(trade.trade_rainbow_option), nameof(trade.trade_rainbow_option.Strike)));
|
|
list.Add(compar(trade.trade_rainbow_option.Strike2, NewValue.trade_rainbow_option.Strike2, nameof(trade.trade_rainbow_option), nameof(trade.trade_rainbow_option.Strike2)));
|
|
break;
|
|
case "凤凰期权":
|
|
list.Add(compar(trade.trade_autocall.KIBarrier, NewValue.trade_autocall.KIBarrier, nameof(trade.trade_autocall), nameof(trade.trade_autocall.KIBarrier)));
|
|
list.Add(compar(trade.trade_autocall.KOBarrier, NewValue.trade_autocall.KOBarrier, nameof(trade.trade_autocall), nameof(trade.trade_autocall.KOBarrier)));
|
|
list.Add(compar(trade.trade_autocall.CouponBarrier, NewValue.trade_autocall.CouponBarrier, nameof(trade.trade_autocall), nameof(trade.trade_autocall.CouponBarrier)));
|
|
list.Add(compar(trade.trade_autocall.SpreadStrike, NewValue.trade_autocall.SpreadStrike, nameof(trade.trade_autocall), nameof(trade.trade_autocall.SpreadStrike)));
|
|
list.Add(compar(trade.trade_autocall.SpreadStrike1, NewValue.trade_autocall.SpreadStrike, nameof(trade.trade_autocall), nameof(trade.trade_autocall.SpreadStrike1)));
|
|
list.Add(comparStr(trade.trade_autocall.KOObservationDates, NewValue.trade_autocall.KOObservationDates, nameof(trade.trade_autocall), nameof(trade.trade_autocall.KOObservationDates)));
|
|
break;
|
|
case "双鲨期权":
|
|
list.Add(compar(trade.trade_double_sharkfin_option.BarrierHigh, NewValue.trade_double_sharkfin_option.BarrierHigh, nameof(trade.trade_double_sharkfin_option), nameof(trade.trade_double_sharkfin_option.BarrierHigh)));
|
|
list.Add(compar(trade.trade_double_sharkfin_option.BarrierLow, NewValue.trade_double_sharkfin_option.BarrierLow, nameof(trade.trade_double_sharkfin_option), nameof(trade.trade_double_sharkfin_option.BarrierLow)));
|
|
list.Add(compar(trade.trade_double_sharkfin_option.StrikeHigh, NewValue.trade_double_sharkfin_option.StrikeHigh, nameof(trade.trade_double_sharkfin_option), nameof(trade.trade_double_sharkfin_option.StrikeHigh)));
|
|
list.Add(compar(trade.trade_double_sharkfin_option.StrikeLow, NewValue.trade_double_sharkfin_option.StrikeLow, nameof(trade.trade_double_sharkfin_option), nameof(trade.trade_double_sharkfin_option.StrikeLow)));
|
|
break;
|
|
case "区间累积期权":
|
|
list.Add(compar(trade.trade_rangeaccrual.LowerRange, NewValue.trade_rangeaccrual.LowerRange, nameof(trade.trade_rangeaccrual), nameof(trade.trade_rangeaccrual.LowerRange)));
|
|
list.Add(compar(trade.trade_rangeaccrual.UpperRange, NewValue.trade_rangeaccrual.UpperRange, nameof(trade.trade_rangeaccrual), nameof(trade.trade_rangeaccrual.UpperRange)));
|
|
break;
|
|
case "雪球期权":
|
|
list.Add(compar(trade.trade_snowball.KIBarrier, NewValue.trade_snowball.KIBarrier, nameof(trade.trade_snowball), nameof(trade.trade_snowball.KIBarrier)));
|
|
list.Add(compar(trade.trade_snowball.KOBarrier, NewValue.trade_snowball.KOBarrier, nameof(trade.trade_snowball), nameof(trade.trade_snowball.KOBarrier)));
|
|
list.Add(compar(trade.trade_snowball.SpreadStrikeAtKO, NewValue.trade_snowball.SpreadStrikeAtKO, nameof(trade.trade_snowball), nameof(trade.trade_snowball.SpreadStrikeAtKO)));
|
|
list.Add(compar(trade.trade_snowball.SpreadStrikeAtKO1, NewValue.trade_snowball.SpreadStrikeAtKO1, nameof(trade.trade_snowball), nameof(trade.trade_snowball.SpreadStrikeAtKO1)));
|
|
list.Add(compar(trade.trade_snowball.SpreadStrikeAtMaturity, NewValue.trade_snowball.SpreadStrikeAtMaturity, nameof(trade.trade_snowball), nameof(trade.trade_snowball.SpreadStrikeAtMaturity)));
|
|
list.Add(compar(trade.trade_snowball.SpreadStrikeAtMaturity1, NewValue.trade_snowball.SpreadStrikeAtMaturity1, nameof(trade.trade_snowball), nameof(trade.trade_snowball.SpreadStrikeAtMaturity1)));
|
|
list.Add(comparStr(trade.trade_snowball.KOObservationDates, NewValue.trade_snowball.KOObservationDates, nameof(trade.trade_snowball), nameof(trade.trade_snowball.KOObservationDates)));
|
|
break;
|
|
case "气囊结构":
|
|
list.Add(compar(trade.trade_airbag.Barrier, NewValue.trade_airbag.Barrier, nameof(trade.trade_airbag), nameof(trade.trade_airbag.Barrier)));
|
|
list.Add(compar(trade.trade_airbag.HighStrike, NewValue.trade_airbag.HighStrike, nameof(trade.trade_airbag), nameof(trade.trade_airbag.HighStrike)));
|
|
break;
|
|
case "收益互换":
|
|
if (trade.trade_swap != null)
|
|
{
|
|
list.Add(compar(trade.trade_swap.PaySpotPrice, NewValue.trade_swap.PaySpotPrice, nameof(trade.trade_swap), nameof(trade.trade_swap.PaySpotPrice)));
|
|
list.Add(compar(trade.trade_swap.PayNotional, NewValue.trade_swap.PayNotional, nameof(trade.trade_swap), nameof(trade.trade_swap.PayNotional)));
|
|
list.Add(compar(trade.trade_swap.PayTradeAmount, NewValue.trade_swap.PayTradeAmount, nameof(trade.trade_swap), nameof(trade.trade_swap.PayTradeAmount)));
|
|
if (trade.pay_trade_swap_details != null)
|
|
{
|
|
foreach (var item in trade.pay_trade_swap_details)
|
|
{
|
|
if (!ConsGlobal.IsValid(item.ValidState))
|
|
{
|
|
continue;
|
|
}
|
|
var newDetail = NewValue.pay_trade_swap_details.Find(O => O.id == item.id);
|
|
list.Add(compar(item.SpotPrice, newDetail.SpotPrice, $"{nameof(trade.pay_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.SpotPrice)));
|
|
list.Add(compar(item.OriginalNotional, newDetail.OriginalNotional, $"{nameof(trade.pay_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.OriginalNotional)));
|
|
list.Add(compar(item.Notional, newDetail.Notional, $"{nameof(trade.pay_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.Notional)));
|
|
}
|
|
}
|
|
|
|
list.Add(compar(trade.trade_swap.GetSpotPrice, NewValue.trade_swap.GetSpotPrice, nameof(trade.trade_swap), nameof(trade.trade_swap.GetSpotPrice)));
|
|
list.Add(compar(trade.trade_swap.GetNotional, NewValue.trade_swap.GetNotional, nameof(trade.trade_swap), nameof(trade.trade_swap.GetNotional)));
|
|
list.Add(compar(trade.trade_swap.GetTradeAmount, NewValue.trade_swap.GetTradeAmount, nameof(trade.trade_swap), nameof(trade.trade_swap.GetTradeAmount)));
|
|
if (trade.get_trade_swap_details != null)
|
|
{
|
|
foreach (var item in trade.get_trade_swap_details)
|
|
{
|
|
if (!ConsGlobal.IsValid(item.ValidState))
|
|
{
|
|
continue;
|
|
}
|
|
var newDetail = NewValue.get_trade_swap_details.Find(O => O.id == item.id);
|
|
list.Add(compar(item.SpotPrice, newDetail.SpotPrice, $"{nameof(trade.get_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.SpotPrice)));
|
|
list.Add(compar(item.OriginalNotional, newDetail.OriginalNotional, $"{nameof(trade.get_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.OriginalNotional)));
|
|
list.Add(compar(item.Notional, newDetail.Notional, $"{nameof(trade.get_trade_swap_details)}[{item.id}]", nameof(trade_swap_detail.Notional)));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case "累计期权":
|
|
list.Add(compar(trade.trade_accumulator_option.KOBarrier, NewValue.trade_accumulator_option.AccumuTradeAmount, nameof(trade.trade_accumulator_option), nameof(trade.trade_accumulator_option.KOBarrier)));
|
|
list.Add(compar(trade.trade_accumulator_option.AccumuTradeAmount, NewValue.trade_accumulator_option.AccumuTradeAmount, nameof(trade.trade_accumulator_option), nameof(trade.trade_accumulator_option.AccumuTradeAmount)));
|
|
list.Add(compar(trade.trade_accumulator_option.OriginalAccumuTradeAmount, NewValue.trade_accumulator_option.OriginalAccumuTradeAmount, nameof(trade.trade_accumulator_option), nameof(trade.trade_accumulator_option.OriginalAccumuTradeAmount)));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
list.RemoveAll(O => O == null);
|
|
|
|
return list;
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public static void SetDividendTradeData(trade trade, trade NewValue)
|
|
{
|
|
trade.SpotPrice = NewValue.SpotPrice;
|
|
trade.OriginalNotional = NewValue.OriginalNotional;
|
|
trade.OriginalStockEqvNotional = NewValue.OriginalStockEqvNotional;
|
|
trade.StockEqvNotionalReal = NewValue.StockEqvNotionalReal;
|
|
trade.StockEqvNotional = NewValue.StockEqvNotional;
|
|
trade.Notional = NewValue.Notional;
|
|
trade.TradeSinglePrice = TradeHelper.GetTradeSinglePriceByTradePrice(NewValue.TradePrice, NewValue.OriginalNotional, NewValue.PrincipalSum(), NewValue.BuySell, NewValue.TradeType, true);
|
|
trade.TradeOriginalAmount = NewValue.TradeOriginalAmount;
|
|
trade.TradeAmount = NewValue.TradeAmount;
|
|
trade.Strike = NewValue.Strike;
|
|
trade.DividendDate = NewValue.DividendDate;
|
|
|
|
switch (trade.TradeType)
|
|
{
|
|
case "亚式期权":
|
|
//获取fixings的时候,函数内部处理除权除息逻辑;
|
|
break;
|
|
case "障碍期权":
|
|
trade.trade_barrier_option.BarrierPrice = NewValue.trade_barrier_option.BarrierPrice;
|
|
trade.trade_barrier_option.UpperBarrierPrice = NewValue.trade_barrier_option.UpperBarrierPrice;
|
|
break;
|
|
case "彩虹期权":
|
|
trade.trade_rainbow_option.SpotPrice1 = NewValue.trade_rainbow_option.SpotPrice1;
|
|
trade.trade_rainbow_option.SpotPrice2 = NewValue.trade_rainbow_option.SpotPrice2;
|
|
trade.trade_rainbow_option.Strike = NewValue.trade_rainbow_option.Strike;
|
|
trade.trade_rainbow_option.Strike2 = NewValue.trade_rainbow_option.Strike2;
|
|
break;
|
|
case "凤凰期权":
|
|
trade.trade_autocall.KIBarrier = NewValue.trade_autocall.KIBarrier;
|
|
trade.trade_autocall.KOBarrier = NewValue.trade_autocall.KOBarrier;
|
|
trade.trade_autocall.CouponBarrier = NewValue.trade_autocall.CouponBarrier;
|
|
trade.trade_autocall.SpreadStrike = NewValue.trade_autocall.SpreadStrike;
|
|
trade.trade_autocall.SpreadStrike1 = NewValue.trade_autocall.SpreadStrike1;
|
|
trade.trade_autocall.KOObservationDates = NewValue.trade_autocall.KOObservationDates;
|
|
break;
|
|
case "双鲨期权":
|
|
trade.trade_double_sharkfin_option.BarrierHigh = NewValue.trade_double_sharkfin_option.BarrierHigh;
|
|
trade.trade_double_sharkfin_option.BarrierLow = NewValue.trade_double_sharkfin_option.BarrierLow;
|
|
trade.trade_double_sharkfin_option.StrikeHigh = NewValue.trade_double_sharkfin_option.StrikeHigh;
|
|
trade.trade_double_sharkfin_option.StrikeLow = NewValue.trade_double_sharkfin_option.StrikeLow;
|
|
break;
|
|
case "区间累积期权":
|
|
trade.trade_rangeaccrual.LowerRange = NewValue.trade_rangeaccrual.LowerRange;
|
|
trade.trade_rangeaccrual.UpperRange = NewValue.trade_rangeaccrual.UpperRange;
|
|
break;
|
|
case "雪球期权":
|
|
trade.trade_snowball.KIBarrier = NewValue.trade_snowball.KIBarrier;
|
|
trade.trade_snowball.KOBarrier = NewValue.trade_snowball.KOBarrier;
|
|
trade.trade_snowball.SpreadStrikeAtKO = NewValue.trade_snowball.SpreadStrikeAtKO;
|
|
trade.trade_snowball.SpreadStrikeAtKO1 = NewValue.trade_snowball.SpreadStrikeAtKO1;
|
|
trade.trade_snowball.SpreadStrikeAtMaturity = NewValue.trade_snowball.SpreadStrikeAtMaturity;
|
|
trade.trade_snowball.SpreadStrikeAtMaturity1 = NewValue.trade_snowball.SpreadStrikeAtMaturity1;
|
|
trade.trade_snowball.KOObservationDates = NewValue.trade_snowball.KOObservationDates;
|
|
break;
|
|
case "气囊结构":
|
|
trade.trade_airbag.Barrier = NewValue.trade_airbag.Barrier;
|
|
trade.trade_airbag.HighStrike = NewValue.trade_airbag.HighStrike;
|
|
break;
|
|
case "收益互换":
|
|
if (trade.trade_swap != null)
|
|
{
|
|
trade.trade_swap.PaySpotPrice = NewValue.trade_swap.PaySpotPrice;
|
|
trade.trade_swap.PayNotional = NewValue.trade_swap.PayNotional;
|
|
trade.trade_swap.PayTradeAmount = NewValue.trade_swap.PayTradeAmount;
|
|
if (trade.pay_trade_swap_details != null)
|
|
{
|
|
foreach (var item in trade.pay_trade_swap_details)
|
|
{
|
|
if (!ConsGlobal.IsValid(item.ValidState))
|
|
{
|
|
continue;
|
|
}
|
|
var newDetail = NewValue.pay_trade_swap_details.Find(O => O.id == item.id);
|
|
item.SpotPrice = newDetail.SpotPrice;
|
|
item.OriginalNotional = newDetail.OriginalNotional;
|
|
item.Notional = newDetail.Notional;
|
|
}
|
|
}
|
|
|
|
trade.trade_swap.GetSpotPrice = NewValue.trade_swap.GetSpotPrice;
|
|
trade.trade_swap.GetNotional = NewValue.trade_swap.GetNotional;
|
|
trade.trade_swap.GetTradeAmount = NewValue.trade_swap.GetTradeAmount;
|
|
if (trade.get_trade_swap_details != null)
|
|
{
|
|
foreach (var item in trade.get_trade_swap_details)
|
|
{
|
|
if (!ConsGlobal.IsValid(item.ValidState))
|
|
{
|
|
continue;
|
|
}
|
|
var newDetail = NewValue.get_trade_swap_details.Find(O => O.id == item.id);
|
|
item.SpotPrice = newDetail.SpotPrice;
|
|
item.OriginalNotional = newDetail.OriginalNotional;
|
|
item.Notional = newDetail.Notional;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case "累计期权":
|
|
trade.trade_accumulator_option.KOBarrier = NewValue.trade_accumulator_option.KOBarrier;
|
|
trade.trade_accumulator_option.AccumuTradeAmount = NewValue.trade_accumulator_option.AccumuTradeAmount;
|
|
trade.trade_accumulator_option.OriginalAccumuTradeAmount = NewValue.trade_accumulator_option.OriginalAccumuTradeAmount;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取除权价
|
|
/// </summary>
|
|
/// <param name="closePrice">除权日收盘价</param>
|
|
/// <param name="info">除权除息配置</param>
|
|
/// <param name="overrideDividendRatio">除权除息系数</param>
|
|
/// <returns></returns>
|
|
public double? GetPrice(double? closePrice, ex_dividend_info info, double? overrideDividendRatio = null)
|
|
{
|
|
if (!closePrice.HasValue) { return closePrice; }
|
|
return GetPrice(closePrice.Value, info, overrideDividendRatio);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取除权价
|
|
/// </summary>
|
|
/// <param name="pirce">除权日收盘价</param>
|
|
/// <param name="info">除权除息配置</param>
|
|
/// <returns></returns>
|
|
public double GetPrice(double price, ex_dividend_info info, double? overrideDividendRatio = null)
|
|
{
|
|
if (price == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
var ratio = overrideDividendRatio != null ? overrideDividendRatio.Value : GetRatio(info);
|
|
double? result = price / ratio;
|
|
return Math.Round(result ?? 0, 4, MidpointRounding.AwayFromZero);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取除权除息系数
|
|
/// </summary>
|
|
/// <param name="info"></param>
|
|
/// <returns></returns>
|
|
public double GetRatio(ex_dividend_info info)
|
|
{
|
|
var dividendRate = valuedateBLL.SystemDate.DividendRate / 100;
|
|
var closePrice = new EodPriceProvider(info.ExDividendDate.Value).GetPrice(info.UnderlyingCode, SettlementTypeEnum.ClosePrice);
|
|
var cDivdPrice = (closePrice * 10.0 - (info.GiveCashAmount * (1 - dividendRate)) + info.RationedSharesAmount * info.RationedSharesPrice) / (10 + info.GiveShareAmount + info.RationedSharesAmount);
|
|
return closePrice / cDivdPrice;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取除权后持仓量
|
|
/// </summary>
|
|
/// <param name="amount">持仓数量</param>
|
|
/// <param name="info">除权除息配置</param>
|
|
/// <returns></returns>
|
|
public double? GetPositionAmount(double? amount, ex_dividend_info info)
|
|
{
|
|
if (!amount.HasValue) { return amount; }
|
|
return GetPositionAmount(amount.Value, info);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取除权后持仓量
|
|
/// </summary>
|
|
/// <param name="amount">持仓数量</param>
|
|
/// <param name="info">除权除息配置</param>
|
|
/// <returns></returns>
|
|
public double GetPositionAmount(double amount, ex_dividend_info info)
|
|
{
|
|
double? result = amount * (1 + info.GiveShareAmount / 10.0);
|
|
return Math.Round(result ?? 0, 12);
|
|
}
|
|
|
|
public IQueryable<ex_dividend_info> GetExDividendQuery(DateTime valueDate)
|
|
{
|
|
return DbContext.ex_dividend_info.Where(O => O.ValidStatus && O.ExDividendDate == valueDate);
|
|
}
|
|
|
|
public IQueryable<ex_dividend_info> GetExDividendQuery(DateTime dateStart, DateTime dateEnd)
|
|
{
|
|
return DbContext.ex_dividend_info.Where(O => O.ValidStatus && O.ExDividendDate >= dateStart && O.ExDividendDate <= dateEnd);
|
|
}
|
|
|
|
public IEnumerable<ex_dividend_info> GetExDividends(DateTime valueDate, params int[] underlyingIds)
|
|
{
|
|
var query = DbContext.ex_dividend_info.Where(O => O.ValidStatus && O.ExDividendDate == valueDate);
|
|
if (underlyingIds != null && underlyingIds.Any())
|
|
{
|
|
query = query.Where(n => underlyingIds.Contains(n.UnderlyingId));
|
|
}
|
|
return query.ToArray();
|
|
}
|
|
|
|
public IQueryable<ex_dividend_info> GetExDividendInfos(string underlyingCode)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(underlyingCode))
|
|
{
|
|
throw new ArgumentNullException(nameof(underlyingCode));
|
|
}
|
|
|
|
return
|
|
from di in DbContext.ex_dividend_info
|
|
join un in DbContext.underlying_manager
|
|
on di.UnderlyingId equals un.id
|
|
where di.ValidStatus && un.UnderlyingCode == underlyingCode
|
|
select di;
|
|
}
|
|
|
|
public void ImportDividendInfos(Stream stream)
|
|
{
|
|
var dt = new ExcelHelper().ExcelToDataTable(stream, null, true);
|
|
if (!dt.Columns.Contains("股票代码") || !dt.Columns.Contains("股权登记日"))
|
|
{
|
|
throw new ServiceException("请使用正确的模板上传");
|
|
}
|
|
var dict = new Dictionary<string, ex_dividend_info>();
|
|
for (var i = 0; i < dt.Rows.Count; i++)
|
|
{
|
|
var info = new ex_dividend_info
|
|
{
|
|
UnderlyingCode = dt.Rows[i]["股票代码"]?.ToString(),
|
|
ExDividendDate = DateTime.TryParse(getColValueFromTable(dt.Rows[i], "股权登记日"), out var date) ? date : DateTime.MinValue,
|
|
GiveCashAmount = double.TryParse(getColValueFromTable(dt.Rows[i], "派息金额"), out var value) ? value : 0,
|
|
GiveShareAmount = double.TryParse(getColValueFromTable(dt.Rows[i], "送股股数"), out value) ? value : 0,
|
|
RationedSharesAmount = double.TryParse(getColValueFromTable(dt.Rows[i], "配股股数"), out value) ? value : 0,
|
|
RationedSharesPrice = double.TryParse(getColValueFromTable(dt.Rows[i], "配股股价"), out value) ? value : 0,
|
|
OptId = OptUser.UserId,
|
|
OptName = OptUser.UserName,
|
|
OptDate = DateTime.Now
|
|
};
|
|
if (string.IsNullOrWhiteSpace(info.UnderlyingCode) && info.ExDividendDate < DateTime.Now.AddYears(10))
|
|
{
|
|
continue;
|
|
}
|
|
if (string.IsNullOrWhiteSpace(info.UnderlyingCode))
|
|
{
|
|
throw new ServiceException($"第{i + 1}行股票代码不应为空");
|
|
}
|
|
if (info.ExDividendDate < DateTime.Now.AddYears(-10))
|
|
{
|
|
throw new ServiceException($"第{i + 1}行股权登记日不正确");
|
|
}
|
|
dict[$"{info.ExDividendDate}{info.UnderlyingCode}"] = info;
|
|
}
|
|
if (!AddDividendInfos(dict.Values, out var errMsg))
|
|
{
|
|
throw new ServiceException(errMsg);
|
|
}
|
|
}
|
|
|
|
private string getColValueFromTable(DataRow dr, string colName)
|
|
{
|
|
if (dr.Table.Columns.Contains(colName))
|
|
{
|
|
return dr[colName].ToString();
|
|
}
|
|
return "";
|
|
}
|
|
|
|
public bool AddDividendInfos(IEnumerable<ex_dividend_info> infos, out string errMsg)
|
|
{
|
|
try
|
|
{
|
|
var keys = infos.Select(O => $"{O.ExDividendDate?.ToString("yyyy-MM-dd")}{O.UnderlyingCode}");
|
|
var ids = infos.Select(O => O.id).ToHashSet();
|
|
|
|
var data = from dividendDb in DbContext.ex_dividend_info.Where(O => keys.Contains(O.ExDividendDate + O.UnderlyingCode) && O.ValidStatus)
|
|
where !ids.Contains(dividendDb.id)
|
|
select dividendDb;
|
|
if (data.Any())
|
|
{
|
|
var dd = data.Select(O => O.UnderlyingCode + "_" + O.ExDividendDate).ToArray();
|
|
errMsg = string.Join(",", dd) + "已存在除息信息,请修改原数据";
|
|
return false;
|
|
}
|
|
|
|
var basketList =
|
|
DataCacheProvider.GetUnderlyingDataSource()
|
|
.AsQueryable().Where(O => O.IsBasket() && O.SubData != null)
|
|
.Select(O => new { O.UnderlyingCode, O.SubData });
|
|
IEnumerable<eod_stock_price> priceList = null;
|
|
foreach (var item in infos)
|
|
{
|
|
var underlying = underlying_managerBLL.GetByCode(item.UnderlyingCode);
|
|
if (underlying == null)
|
|
{
|
|
errMsg = $"{item.UnderlyingCode} 标的信息不存在";
|
|
return false;
|
|
}
|
|
item.UnderlyingId = underlying.id;
|
|
item.GiveCashAmount = item.GiveCashAmount.FormatValue(6);
|
|
item.RationedSharesAmount = item.RationedSharesAmount.FormatValue(6);
|
|
item.RationedSharesPrice = item.RationedSharesPrice.FormatValue(6);
|
|
item.GiveShareAmount = item.GiveShareAmount.FormatValue(6);
|
|
item.ValidStatus = true;
|
|
item.OptId = OptUser.UserId;
|
|
item.OptName = OptUser.UserName;
|
|
item.OptDate = DateTime.Now;
|
|
var dividend = item.id > 0 ? DbContext.ex_dividend_info.Where(O => O.id == item.id).FirstOrDefault() : null;
|
|
if (dividend == null)
|
|
{ DbContext.ex_dividend_info.Add(item); }
|
|
else
|
|
{
|
|
if (checkDividendInfoExecuteStatus(dividend))
|
|
{
|
|
errMsg = $"{dividend.UnderlyingCode} {dividend.ExDividendDate?.ToString("yyyy-MM-dd")}除权信息保存失败,该信息已被执行,不允许修改!";
|
|
return false;
|
|
}
|
|
dividend.UnderlyingCode = item.UnderlyingCode;
|
|
dividend.UnderlyingId = item.UnderlyingId;
|
|
dividend.ExDividendDate = item.ExDividendDate;
|
|
dividend.GiveCashAmount = item.GiveCashAmount;
|
|
dividend.RationedSharesAmount = item.RationedSharesAmount;
|
|
dividend.RationedSharesPrice = item.RationedSharesPrice;
|
|
dividend.GiveShareAmount = item.GiveShareAmount;
|
|
dividend.ValidStatus = item.ValidStatus;
|
|
dividend.OptId = item.OptId;
|
|
dividend.OptName = item.OptName;
|
|
dividend.OptDate = item.OptDate;
|
|
}
|
|
if (!basketList.Any())
|
|
{
|
|
continue;
|
|
}
|
|
var codes = basketList.Where(O => O.SubData.Contains(item.UnderlyingCode)).Select(O => O.UnderlyingCode);
|
|
if (!codes.Any())
|
|
{
|
|
continue;
|
|
}
|
|
var removePriceList = DbContext.eod_stock_price.Where(O => codes.Contains(O.UnderlyingCode) && O.ValueDate > item.ExDividendDate);
|
|
if (!removePriceList.Any())
|
|
{
|
|
continue;
|
|
}
|
|
DbContext.eod_stock_price.RemoveRange(removePriceList);
|
|
}
|
|
if (priceList != null)
|
|
{
|
|
DbContext.eod_stock_price.RemoveRange(priceList);
|
|
}
|
|
DbContext.SaveChanges();
|
|
errMsg = "";
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
errMsg = "保存失败";
|
|
LogFactory.GetLogger<DividendService>().Error(ex);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查除权除息记录有没有被执行
|
|
/// </summary>
|
|
/// <param name="info"></param>
|
|
/// <returns></returns>
|
|
public bool checkDividendInfoExecuteStatus(ex_dividend_info info)
|
|
{
|
|
var eodStatus = DbContext.eodStatus.Where(O => O.ValueDate == info.ExDividendDate && O.OptDate > info.OptDate).Any();
|
|
if (eodStatus)
|
|
{
|
|
//查询标的对应交易是否执行过收盘操作;
|
|
var tradeQuery = from t in DbContext.trade.Where(O => O.UnderlyingCode == info.UnderlyingCode && O.TradeDate <= info.ExDividendDate && O.ExerciseDate >= info.ExDividendDate && O.DividendDate >= O.TradeDate)
|
|
join et in DbContext.eod_trade.Where(O => ConsTrade.LiveTradeStatusList.Contains(O.TradeStatus))
|
|
on new { t.id, ValueDate = t.TradeDate.Value } equals new { id = et.TradeId, et.ValueDate }
|
|
select et.id;
|
|
if (tradeQuery.Any())
|
|
{
|
|
return true;
|
|
}
|
|
//查询篮子标的对应交易是否执行过收盘操作;
|
|
var umList = DataCacheProvider.GetUnderlyingDataSource().AsQueryable(O => O.IsBasket() && O.SubData != null && O.SubData.Contains(info.UnderlyingCode)).Select(O => O.UnderlyingCode).ToArray();
|
|
tradeQuery = from t in DbContext.trade.Where(O => umList.Contains(O.UnderlyingCode) && O.TradeDate <= info.ExDividendDate && O.ExerciseDate >= info.ExDividendDate && O.DividendDate >= O.TradeDate)
|
|
join et in DbContext.eod_trade.Where(O => ConsTrade.LiveTradeStatusList.Contains(O.TradeStatus))
|
|
on new { t.id, ValueDate = t.TradeDate.Value } equals new { id = et.TradeId, et.ValueDate }
|
|
select et.id;
|
|
if (tradeQuery.Any())
|
|
{
|
|
return true;
|
|
}
|
|
//查询多标的对应交易是否执行过收盘操作;
|
|
tradeQuery = from ts in DbContext.trade_swap_detail.Where(O => O.UnderlyingCode == info.UnderlyingCode)
|
|
join t in DbContext.trade.Where(O => O.TradeDate <= info.ExDividendDate && O.ExerciseDate >= info.ExDividendDate && O.DividendDate >= O.TradeDate)
|
|
on ts.TradeId equals t.id
|
|
join et in DbContext.eod_trade.Where(O => ConsTrade.LiveTradeStatusList.Contains(O.TradeStatus))
|
|
on new { t.id, ValueDate = t.TradeDate.Value } equals new { id = et.TradeId, et.ValueDate }
|
|
select et.id;
|
|
if (tradeQuery.Any())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public List<DividendTrade> QueryDividendTrade(DividendTradeReq req)
|
|
{
|
|
TradeChanges changes = null;
|
|
var result = new List<DividendTrade>();
|
|
var predicate = PredicateBuilder.Create<trade>(O => O.ValidState != "InValid"
|
|
&& ConsTrade.TradeStatusAfterConfirmed.Contains(O.TradeStatus)
|
|
&& O.TradeType != "结构化交易");
|
|
if (!string.IsNullOrWhiteSpace(req.TradeNumber))
|
|
{
|
|
predicate = predicate.And(O => O.TradeNumber == req.TradeNumber);
|
|
}
|
|
if (req.ClientIds != null && req.ClientIds.Any(O => O > 0))
|
|
{
|
|
predicate = predicate.And(O => req.ClientIds.Contains(O.ClientId));
|
|
}
|
|
if (req.AssetUnitIds != null && req.AssetUnitIds.Any(O => O > 0))
|
|
{
|
|
predicate = predicate.And(O => req.AssetUnitIds.Contains(O.AssetId));
|
|
}
|
|
if (req.TradeTypes != null && req.TradeTypes.Any(O => !string.IsNullOrWhiteSpace(O)))
|
|
{
|
|
predicate = predicate.And(O => req.TradeTypes.Contains(O.TradeType) || req.TradeTypes.Contains(O.StructureType));
|
|
}
|
|
if (req.UnderlyingIds != null && req.UnderlyingIds.Any(O => O > 0))
|
|
{
|
|
predicate = predicate.And(O => req.UnderlyingIds.Contains(O.UnderlyingId));
|
|
}
|
|
if (req.TraderIds != null && req.TraderIds.Any(O => O > 0))
|
|
{
|
|
predicate = predicate.And(O => req.TraderIds.Contains(O.TraderId));
|
|
}
|
|
if (req.TradeDateStart > DateTime.MinValue)
|
|
{
|
|
predicate = predicate.And(O => req.TradeDateStart <= O.TradeDate);
|
|
}
|
|
if (req.TradeDateEnd > DateTime.MinValue)
|
|
{
|
|
predicate = predicate.And(O => req.TradeDateEnd >= O.TradeDate);
|
|
}
|
|
if (req.ExerciseDateStart > DateTime.MinValue)
|
|
{
|
|
predicate = predicate.And(O => req.ExerciseDateStart <= O.ExerciseDate);
|
|
}
|
|
if (req.ExerciseDateEnd > DateTime.MinValue)
|
|
{
|
|
predicate = predicate.And(O => req.ExerciseDateEnd >= O.ExerciseDate);
|
|
}
|
|
var query = DbContext.trade.Where(predicate);
|
|
var tradeInfos = (from diInfo in GetExDividendQuery(req.DividendDate, req.DividendDateEnd.Value)
|
|
join t in query
|
|
on diInfo.UnderlyingCode equals t.UnderlyingCode
|
|
where
|
|
t.TradeDate <= diInfo.ExDividendDate &&
|
|
t.ValidState != "InValid" &&
|
|
(ConsTrade.PositionTradeStatusList.Contains(t.TradeStatus) ||
|
|
(ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus) &&
|
|
((t.UnWindDate == null && t.ExerciseDate > diInfo.ExDividendDate) ||
|
|
(t.UnWindDate != null && t.UnWindDate > diInfo.ExDividendDate))))
|
|
select new { diInfo, t })//单标的
|
|
.Concat(from diInfo in GetExDividendQuery(req.DividendDate, req.DividendDateEnd.Value)
|
|
join ts in DbContext.trade_swap_detail
|
|
on diInfo.UnderlyingCode equals ts.UnderlyingCode
|
|
join t in query
|
|
on ts.TradeId equals t.id
|
|
where
|
|
t.TradeDate <= diInfo.ExDividendDate &&
|
|
t.ValidState != "InValid" &&
|
|
(ConsTrade.PositionTradeStatusList.Contains(t.TradeStatus) ||
|
|
(ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus) &&
|
|
((t.UnWindDate == null && t.ExerciseDate > diInfo.ExDividendDate) ||
|
|
(t.UnWindDate != null && t.UnWindDate > diInfo.ExDividendDate))))
|
|
select new { diInfo, t })//多标的
|
|
.ToList();
|
|
|
|
//篮子标的
|
|
var dividendDict = GetExDividendQuery(req.DividendDate, req.DividendDateEnd.Value).ToDictionary(K => K.UnderlyingCode, V => V);
|
|
var umList = DbContext.underlying_manager.Where(O => O.CommodityCode == "篮子标的" && O.SubData != null).ToList();
|
|
var codeDict = new Dictionary<string, ex_dividend_info>();
|
|
foreach (var item in dividendDict)
|
|
{
|
|
var ums = umList.Where(O => O.SubData.Contains(item.Key)).ToList();
|
|
ums.ForEach(O => codeDict[O.UnderlyingCode.ToLower()] = item.Value);
|
|
}
|
|
var tempTrade = query.Where(O => codeDict.Keys.Contains(O.UnderlyingCode));
|
|
foreach (var t in tempTrade)
|
|
{
|
|
var code = t.UnderlyingCode.ToLower();
|
|
var diInfo = codeDict.ContainsKey(code) ? codeDict[code] : null;
|
|
if (diInfo == null)
|
|
{
|
|
continue;
|
|
}
|
|
if (t.TradeDate <= diInfo.ExDividendDate && ((t.UnWindDate == null && t.ExerciseDate > diInfo.ExDividendDate) || (t.UnWindDate != null && t.UnWindDate > diInfo.ExDividendDate)))
|
|
{
|
|
tradeInfos.Add(new { diInfo, t });
|
|
}
|
|
}
|
|
|
|
var ids = tradeInfos.Select(O => O.t.id).ToArray();
|
|
var subTrades = tradeInfos.Select(O => O.t).ToList();
|
|
tradeBLL.SetFieldsByTradeType(subTrades);
|
|
var changeService = new DbRecordChangesService<TradeChanges>(this);
|
|
var tradeChangeDict = changeService.GetValue(ConsInfoChangeType.Dividend, ids, req.DividendDate).GroupBy(O => O.RecordId).ToDictionary(K => K.Key, V => V.ToList());
|
|
var ratioDict = changeService.GetValue(
|
|
ConsInfoChangeType.UserChange,
|
|
ids,
|
|
nameof(trade.DividendRatio),
|
|
req.DividendDate).ToDictionary(K => K.RecordId, V =>
|
|
{
|
|
return double.TryParse(V.NewValue, out var temp) ? (double?)temp : null;
|
|
});
|
|
foreach (var item in tradeInfos)
|
|
{
|
|
var info = new DividendTrade
|
|
{
|
|
TradeId = item.t.id,
|
|
EncryptId = item.t.EncryptId,
|
|
TradeNumber = item.t.TradeNumber,
|
|
ExDividendDate = item.diInfo.ExDividendDate.Value,
|
|
DividendStatus = tradeChangeDict.ContainsKey(item.t.id),
|
|
TradeStatus = item.t.TradeStatus,
|
|
ClientName = item.t.ClientName,
|
|
TradeType = item.t.StructureType ?? item.t.TradeType,
|
|
TradeDate = item.t.TradeDate.Value,
|
|
ExerciseDate = item.t.ExerciseDate.Value,
|
|
UnderlyingCode = item.t.UnderlyingCode,
|
|
|
|
DividendRatio = ratioDict.ContainsKey(item.t.id) ? ratioDict[item.t.id].Value : double.NaN,
|
|
|
|
trade = item.t
|
|
};
|
|
|
|
var tradeFullInfo = subTrades.Where(O => O.id == item.t.id).FirstOrDefault();
|
|
if (info.DividendStatus)
|
|
{
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == nameof(trade.OriginalStockEqvNotional)).FirstOrDefault();
|
|
info.StockEqvNotional = TryParseDouble(changes?.NewValue, item.t.OriginalStockEqvNotional ?? double.NaN);
|
|
info.StockEqvNotional_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == nameof(trade.SpotPrice)).FirstOrDefault();
|
|
info.SpotPrice = TryParseDouble(changes?.NewValue, info.SpotPrice);
|
|
info.SpotPrice_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == nameof(trade.TradeOriginalAmount)).FirstOrDefault();
|
|
info.TradeOriginalAmount = TryParseDouble(changes?.NewValue, info.TradeOriginalAmount);
|
|
info.TradeOriginalAmount_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
if (item.t.IsMoneynessOptionData)
|
|
{
|
|
var spotPrice = info.SpotPrice_After;
|
|
|
|
info.Strike = info.SpotPrice * (item.t.Strike ?? 1);
|
|
info.Strike_After = spotPrice * (item.t.Strike ?? 1);
|
|
|
|
switch (item.t.TradeType)
|
|
{
|
|
case "障碍期权":
|
|
info.Barrier = info.SpotPrice * (tradeFullInfo.trade_barrier_option.BarrierPrice ?? 1);
|
|
info.Strike = info.SpotPrice;
|
|
//info.Strike_After = spotPrice * (tradeFullInfo.trade_barrier_option.BarrierPrice ?? 1);
|
|
//info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_barrier_option.UpperBarrierPrice ?? 1);
|
|
//info.StrikeHigh_After = spotPrice * (tradeFullInfo.trade_barrier_option.UpperBarrierPrice ?? 1);
|
|
break;
|
|
//case "彩虹期权":
|
|
// trade.trade_rainbow_option.SpotPrice1 = NewValue.trade_rainbow_option.SpotPrice1;
|
|
// trade.trade_rainbow_option.SpotPrice2 = NewValue.trade_rainbow_option.SpotPrice2;
|
|
// trade.trade_rainbow_option.Strike = NewValue.trade_rainbow_option.Strike;
|
|
// trade.trade_rainbow_option.Strike2 = NewValue.trade_rainbow_option.Strike2;
|
|
// break;
|
|
case "凤凰期权":
|
|
info.KIBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.KIBarrier;
|
|
info.KIBarrier_After = spotPrice * tradeFullInfo.trade_autocall.KIBarrier;
|
|
info.KOBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.KOBarrier;
|
|
info.KOBarrier_After = spotPrice * tradeFullInfo.trade_autocall.KOBarrier;
|
|
info.CouponBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.CouponBarrier;
|
|
info.CouponBarrier_After = spotPrice * tradeFullInfo.trade_autocall.CouponBarrier;
|
|
info.Strike = info.SpotPrice * (tradeFullInfo.trade_autocall.SpreadStrike ?? 1);
|
|
info.Strike_After = spotPrice * (tradeFullInfo.trade_autocall.SpreadStrike ?? 1);
|
|
info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_autocall.SpreadStrike1 ?? 1);
|
|
info.StrikeHigh_After = spotPrice * (tradeFullInfo.trade_autocall.SpreadStrike1 ?? 1);
|
|
break;
|
|
case "双鲨期权":
|
|
info.BarrierHigh = info.SpotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierHigh;
|
|
info.BarrierHigh_After = spotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierHigh;
|
|
info.Barrier = info.SpotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierLow;
|
|
info.Barrier_After = spotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierLow;
|
|
info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeHigh ?? 1);
|
|
info.StrikeHigh_After = spotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeHigh ?? 1);
|
|
info.Strike = info.SpotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeLow ?? 1);
|
|
info.Strike_After = spotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeLow ?? 1);
|
|
break;
|
|
case "区间累积期权":
|
|
info.LowerRange = info.SpotPrice * tradeFullInfo.trade_rangeaccrual.LowerRange;
|
|
info.LowerRange_After = spotPrice * tradeFullInfo.trade_rangeaccrual.LowerRange;
|
|
info.UpperRange = info.SpotPrice * tradeFullInfo.trade_rangeaccrual.UpperRange;
|
|
info.UpperRange_After = spotPrice * tradeFullInfo.trade_rangeaccrual.UpperRange;
|
|
break;
|
|
case "雪球期权":
|
|
info.KIBarrier = info.SpotPrice * tradeFullInfo.trade_snowball.KIBarrier;
|
|
info.KIBarrier_After = spotPrice * tradeFullInfo.trade_snowball.KIBarrier;
|
|
info.KOBarrier = info.SpotPrice * tradeFullInfo.trade_snowball.KOBarrier;
|
|
info.KOBarrier_After = spotPrice * tradeFullInfo.trade_snowball.KOBarrier;
|
|
info.SpreadStrikeAtKO = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO;
|
|
info.SpreadStrikeAtKO_After = spotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO;
|
|
info.SpreadStrikeAtKO1 = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO1;
|
|
info.SpreadStrikeAtKO1_After = spotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO1;
|
|
info.SpreadStrikeAtMaturity = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity;
|
|
info.SpreadStrikeAtMaturity_After = spotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity;
|
|
info.SpreadStrikeAtMaturity1 = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity1;
|
|
info.SpreadStrikeAtMaturity1_After = spotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity1;
|
|
break;
|
|
case "气囊结构":
|
|
info.Barrier = info.SpotPrice * tradeFullInfo.trade_airbag.Barrier;
|
|
info.Barrier_After = spotPrice * tradeFullInfo.trade_airbag.Barrier;
|
|
info.StrikeHigh = info.SpotPrice * tradeFullInfo.trade_airbag.HighStrike;
|
|
info.StrikeHigh_After = spotPrice * tradeFullInfo.trade_airbag.HighStrike;
|
|
break;
|
|
case "收益互换":
|
|
info.PayUnderlyingCode = tradeFullInfo.trade_swap.PayUnderlyingCode;
|
|
info.GetUnderlyingCode = tradeFullInfo.trade_swap.GetUnderlyingCode;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == nameof(trade.Strike)).FirstOrDefault();
|
|
info.Strike = TryParseDouble(changes?.NewValue, info.Strike);
|
|
info.Strike_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
var fileName = "";
|
|
switch (item.t.TradeType)
|
|
{
|
|
case "障碍期权":
|
|
fileName = nameof(trade.trade_barrier_option) + "." + nameof(trade_barrier_option.BarrierPrice);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.Strike = TryParseDouble(changes?.NewValue, info.Strike);
|
|
info.Strike_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_barrier_option) + "." + nameof(trade_barrier_option.UpperBarrierPrice);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.StrikeHigh = TryParseDouble(changes?.NewValue, info.StrikeHigh);
|
|
info.StrikeHigh_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
break;
|
|
//case "彩虹期权":
|
|
// trade.trade_rainbow_option.SpotPrice1 = NewValue.trade_rainbow_option.SpotPrice1;
|
|
// trade.trade_rainbow_option.SpotPrice2 = NewValue.trade_rainbow_option.SpotPrice2;
|
|
// trade.trade_rainbow_option.Strike = NewValue.trade_rainbow_option.Strike;
|
|
// trade.trade_rainbow_option.Strike2 = NewValue.trade_rainbow_option.Strike2;
|
|
// break;
|
|
case "凤凰期权":
|
|
fileName = nameof(trade.trade_autocall) + "." + nameof(trade_autocall.KIBarrier);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.KIBarrier = TryParseDouble(changes?.NewValue, info.KIBarrier);
|
|
info.KIBarrier_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_autocall) + "." + nameof(trade_autocall.KOBarrier);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.KOBarrier = TryParseDouble(changes?.NewValue, info.KOBarrier);
|
|
info.KOBarrier_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_autocall) + "." + nameof(trade_autocall.CouponBarrier);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.CouponBarrier = TryParseDouble(changes?.NewValue, info.CouponBarrier);
|
|
info.CouponBarrier_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_autocall) + "." + nameof(trade_autocall.SpreadStrike);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.Strike = TryParseDouble(changes?.NewValue, info.Strike);
|
|
info.Strike_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_autocall) + "." + nameof(trade_autocall.SpreadStrike1);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.StrikeHigh = TryParseDouble(changes?.NewValue, info.StrikeHigh);
|
|
info.StrikeHigh_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
break;
|
|
case "双鲨期权":
|
|
fileName = nameof(trade.trade_double_sharkfin_option) + "." + nameof(trade_double_sharkfin_option.BarrierHigh);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.BarrierHigh = TryParseDouble(changes?.NewValue, info.BarrierHigh);
|
|
info.BarrierHigh_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_double_sharkfin_option) + "." + nameof(trade_double_sharkfin_option.BarrierLow);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.Barrier = TryParseDouble(changes?.NewValue, info.Barrier);
|
|
info.Barrier_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_double_sharkfin_option) + "." + nameof(trade_double_sharkfin_option.StrikeHigh);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.StrikeHigh = TryParseDouble(changes?.NewValue, info.StrikeHigh);
|
|
info.StrikeHigh_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_double_sharkfin_option) + "." + nameof(trade_double_sharkfin_option.StrikeLow);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.Strike = TryParseDouble(changes?.NewValue, info.Strike);
|
|
info.Strike_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
break;
|
|
case "区间累积期权":
|
|
fileName = nameof(trade.trade_rangeaccrual) + "." + nameof(trade_rangeaccrual.LowerRange);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.LowerRange = TryParseDouble(changes?.NewValue, info.LowerRange);
|
|
info.LowerRange_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_rangeaccrual) + "." + nameof(trade_rangeaccrual.UpperRange);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.UpperRange = TryParseDouble(changes?.NewValue, info.UpperRange);
|
|
info.UpperRange_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
break;
|
|
case "雪球期权":
|
|
fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.KIBarrier);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.KIBarrier = TryParseDouble(changes?.NewValue, info.KIBarrier);
|
|
info.KIBarrier_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.KOBarrier);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.KOBarrier = TryParseDouble(changes?.NewValue, info.KOBarrier);
|
|
info.KOBarrier_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.SpreadStrikeAtKO);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.SpreadStrikeAtKO = TryParseDouble(changes?.NewValue, info.SpreadStrikeAtKO ?? double.NaN);
|
|
info.SpreadStrikeAtKO_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.SpreadStrikeAtKO1);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.SpreadStrikeAtKO1 = TryParseDouble(changes?.NewValue, info.SpreadStrikeAtKO1 ?? double.NaN);
|
|
info.SpreadStrikeAtKO1_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.SpreadStrikeAtMaturity);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.SpreadStrikeAtMaturity = TryParseDouble(changes?.NewValue, info.SpreadStrikeAtMaturity ?? double.NaN);
|
|
info.SpreadStrikeAtMaturity_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_snowball) + "." + nameof(trade_snowball.SpreadStrikeAtMaturity1);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.SpreadStrikeAtMaturity1 = TryParseDouble(changes?.NewValue, info.SpreadStrikeAtMaturity1 ?? double.NaN);
|
|
info.SpreadStrikeAtMaturity1_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
break;
|
|
case "气囊结构":
|
|
fileName = nameof(trade.trade_airbag) + "." + nameof(trade_airbag.Barrier);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.Barrier = TryParseDouble(changes?.NewValue, info.Barrier);
|
|
info.Barrier_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_airbag) + "." + nameof(trade_airbag.HighStrike);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.StrikeHigh = TryParseDouble(changes?.NewValue, info.StrikeHigh);
|
|
info.StrikeHigh_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
break;
|
|
case "收益互换":
|
|
info.PayUnderlyingCode = tradeFullInfo.trade_swap.PayUnderlyingCode;
|
|
info.GetUnderlyingCode = tradeFullInfo.trade_swap.GetUnderlyingCode;
|
|
|
|
fileName = nameof(trade.trade_swap) + "." + nameof(trade_swap.PaySpotPrice);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.PaySpotPrice = TryParseDouble(changes?.NewValue, info.PaySpotPrice);
|
|
info.PaySpotPrice_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
|
|
fileName = nameof(trade.trade_swap) + "." + nameof(trade_swap.GetSpotPrice);
|
|
changes = tradeChangeDict[item.t.id].Where(O => O.FieldName == fileName).FirstOrDefault();
|
|
info.GetSpotPrice = TryParseDouble(changes?.NewValue, info.GetSpotPrice);
|
|
info.GetSpotPrice_After = TryParseDouble(changes?.FieldValue, double.NaN);
|
|
break;
|
|
case "累计期权":
|
|
throw new NotImplementedException("QueryDividendTrade中未实现累计期权逻辑");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
info.StockEqvNotional = item.t.OriginalStockEqvNotional ?? double.NaN;
|
|
info.StockEqvNotional_After = double.NaN;
|
|
|
|
info.SpotPrice = item.t.SpotPrice ?? double.NaN;
|
|
info.SpotPrice_After = double.NaN;
|
|
|
|
info.TradeOriginalAmount = item.t.TradeOriginalAmount ?? item.t.OriginalNotional ?? 0;
|
|
info.TradeOriginalAmount_After = double.NaN;
|
|
|
|
if (item.t.IsMoneynessOptionData)
|
|
{
|
|
info.Strike = info.SpotPrice * (item.t.Strike ?? 1);
|
|
info.Strike_After = double.NaN;
|
|
|
|
switch (item.t.TradeType)
|
|
{
|
|
case "障碍期权":
|
|
info.Strike = info.SpotPrice * (tradeFullInfo.trade_barrier_option.BarrierPrice ?? 1);
|
|
info.Strike_After = double.NaN;
|
|
info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_barrier_option.UpperBarrierPrice ?? 1);
|
|
info.StrikeHigh_After = double.NaN;
|
|
break;
|
|
//case "彩虹期权":
|
|
// trade.trade_rainbow_option.SpotPrice1 = NewValue.trade_rainbow_option.SpotPrice1;
|
|
// trade.trade_rainbow_option.SpotPrice2 = NewValue.trade_rainbow_option.SpotPrice2;
|
|
// trade.trade_rainbow_option.Strike = NewValue.trade_rainbow_option.Strike;
|
|
// trade.trade_rainbow_option.Strike2 = NewValue.trade_rainbow_option.Strike2;
|
|
// break;
|
|
case "凤凰期权":
|
|
info.KIBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.KIBarrier;
|
|
info.KIBarrier_After = double.NaN;
|
|
info.KOBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.KOBarrier;
|
|
info.KOBarrier_After = double.NaN;
|
|
info.CouponBarrier = info.SpotPrice * tradeFullInfo.trade_autocall.CouponBarrier;
|
|
info.CouponBarrier_After = double.NaN;
|
|
info.Strike = info.SpotPrice * (tradeFullInfo.trade_autocall.SpreadStrike ?? 1);
|
|
info.Strike_After = double.NaN;
|
|
info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_autocall.SpreadStrike1 ?? 1);
|
|
info.StrikeHigh_After = double.NaN;
|
|
break;
|
|
case "双鲨期权":
|
|
info.BarrierHigh = info.SpotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierHigh;
|
|
info.BarrierHigh_After = double.NaN;
|
|
info.Barrier = info.SpotPrice * tradeFullInfo.trade_double_sharkfin_option.BarrierLow;
|
|
info.Barrier_After = double.NaN;
|
|
info.StrikeHigh = info.SpotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeHigh ?? 1);
|
|
info.StrikeHigh_After = double.NaN;
|
|
info.Strike = info.SpotPrice * (tradeFullInfo.trade_double_sharkfin_option.StrikeLow ?? 1);
|
|
info.Strike_After = double.NaN;
|
|
break;
|
|
case "区间累积期权":
|
|
info.LowerRange = info.SpotPrice * tradeFullInfo.trade_rangeaccrual.LowerRange;
|
|
info.LowerRange_After = double.NaN;
|
|
info.UpperRange = info.SpotPrice * tradeFullInfo.trade_rangeaccrual.UpperRange;
|
|
info.UpperRange_After = double.NaN;
|
|
break;
|
|
case "雪球期权":
|
|
info.KIBarrier = info.SpotPrice * tradeFullInfo.trade_snowball.KIBarrier;
|
|
info.KIBarrier_After = double.NaN;
|
|
info.KOBarrier = info.SpotPrice * tradeFullInfo.trade_snowball.KOBarrier;
|
|
info.KOBarrier_After = double.NaN;
|
|
info.SpreadStrikeAtKO = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO;
|
|
info.SpreadStrikeAtKO_After = double.NaN;
|
|
info.SpreadStrikeAtKO1 = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtKO1;
|
|
info.SpreadStrikeAtKO1_After = double.NaN;
|
|
info.SpreadStrikeAtMaturity = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity;
|
|
info.SpreadStrikeAtMaturity_After = double.NaN;
|
|
info.SpreadStrikeAtMaturity1 = info.SpotPrice * tradeFullInfo.trade_snowball.SpreadStrikeAtMaturity1;
|
|
info.SpreadStrikeAtMaturity1_After = double.NaN;
|
|
break;
|
|
case "气囊结构":
|
|
info.Barrier = info.SpotPrice * tradeFullInfo.trade_airbag.Barrier;
|
|
info.Barrier_After = double.NaN;
|
|
info.StrikeHigh = info.SpotPrice * tradeFullInfo.trade_airbag.HighStrike;
|
|
info.StrikeHigh_After = double.NaN;
|
|
break;
|
|
case "收益互换":
|
|
info.PayUnderlyingCode = tradeFullInfo.trade_swap.PayUnderlyingCode;
|
|
info.GetUnderlyingCode = tradeFullInfo.trade_swap.GetUnderlyingCode;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
info.Strike = item.t.Strike ?? double.NaN;
|
|
info.Strike_After = double.NaN;
|
|
switch (item.t.TradeType)
|
|
{
|
|
case "障碍期权":
|
|
info.Barrier = item.t.trade_barrier_option.BarrierPrice ?? 1;
|
|
info.Barrier_After = double.NaN;
|
|
|
|
info.BarrierHigh = item.t.trade_barrier_option.UpperBarrierPrice ?? 1;
|
|
info.BarrierHigh_After = double.NaN;
|
|
break;
|
|
//case "彩虹期权":
|
|
// trade.trade_rainbow_option.SpotPrice1 = NewValue.trade_rainbow_option.SpotPrice1;
|
|
// trade.trade_rainbow_option.SpotPrice2 = NewValue.trade_rainbow_option.SpotPrice2;
|
|
// trade.trade_rainbow_option.Strike = NewValue.trade_rainbow_option.Strike;
|
|
// trade.trade_rainbow_option.Strike2 = NewValue.trade_rainbow_option.Strike2;
|
|
// break;
|
|
case "凤凰期权":
|
|
info.KIBarrier = item.t.trade_autocall.KIBarrier;
|
|
info.KIBarrier_After = double.NaN;
|
|
|
|
info.KOBarrier = item.t.trade_autocall.KOBarrier;
|
|
info.KOBarrier_After = double.NaN;
|
|
|
|
info.CouponBarrier = item.t.trade_autocall.CouponBarrier;
|
|
info.CouponBarrier_After = double.NaN;
|
|
|
|
info.Strike = item.t.trade_autocall.SpreadStrike ?? 1;
|
|
info.Strike_After = double.NaN;
|
|
|
|
info.StrikeHigh = item.t.trade_autocall.SpreadStrike1 ?? 1;
|
|
info.StrikeHigh_After = double.NaN;
|
|
break;
|
|
case "双鲨期权":
|
|
info.BarrierHigh = item.t.trade_double_sharkfin_option.BarrierHigh;
|
|
info.BarrierHigh_After = double.NaN;
|
|
|
|
info.Barrier = item.t.trade_double_sharkfin_option.BarrierLow;
|
|
info.Barrier_After = double.NaN;
|
|
|
|
info.StrikeHigh = item.t.trade_double_sharkfin_option.StrikeHigh ?? 0;
|
|
info.StrikeHigh_After = double.NaN;
|
|
|
|
info.Strike = item.t.trade_double_sharkfin_option.StrikeLow ?? 0;
|
|
info.Strike_After = double.NaN;
|
|
break;
|
|
case "区间累积期权":
|
|
info.LowerRange = item.t.trade_rangeaccrual.LowerRange;
|
|
info.LowerRange_After = double.NaN;
|
|
info.UpperRange = item.t.trade_rangeaccrual.UpperRange;
|
|
info.UpperRange_After = double.NaN;
|
|
break;
|
|
case "雪球期权":
|
|
info.KIBarrier = item.t.trade_snowball.KIBarrier;
|
|
info.KIBarrier_After = double.NaN;
|
|
|
|
info.KOBarrier = item.t.trade_snowball.KOBarrier;
|
|
info.KOBarrier_After = double.NaN;
|
|
info.SpreadStrikeAtKO = info.SpotPrice * item.t.trade_snowball.SpreadStrikeAtKO;
|
|
info.SpreadStrikeAtKO_After = double.NaN;
|
|
info.SpreadStrikeAtKO1 = info.SpotPrice * item.t.trade_snowball.SpreadStrikeAtKO1;
|
|
info.SpreadStrikeAtKO1_After = double.NaN;
|
|
info.SpreadStrikeAtMaturity = info.SpotPrice * item.t.trade_snowball.SpreadStrikeAtMaturity;
|
|
info.SpreadStrikeAtMaturity_After = double.NaN;
|
|
info.SpreadStrikeAtMaturity1 = info.SpotPrice * item.t.trade_snowball.SpreadStrikeAtMaturity1;
|
|
info.SpreadStrikeAtMaturity1_After = double.NaN;
|
|
break;
|
|
case "气囊结构":
|
|
info.Barrier = item.t.trade_airbag.Barrier;
|
|
info.Barrier_After = double.NaN;
|
|
|
|
info.StrikeHigh = item.t.trade_airbag.HighStrike;
|
|
info.StrikeHigh_After = double.NaN;
|
|
break;
|
|
case "收益互换":
|
|
info.PayUnderlyingCode = tradeFullInfo.trade_swap.PayUnderlyingCode;
|
|
info.GetUnderlyingCode = tradeFullInfo.trade_swap.GetUnderlyingCode;
|
|
|
|
info.PaySpotPrice = item.t.trade_swap.PaySpotPrice ?? double.NaN;
|
|
info.PaySpotPrice_After = double.NaN;
|
|
|
|
info.GetSpotPrice = item.t.trade_swap.GetSpotPrice ?? double.NaN;
|
|
info.GetSpotPrice_After = double.NaN;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
info.TradeOriginalAmountV = CalculationModule.TradeCalcHelper.GetTradeAmountV(item.t, info.TradeOriginalAmount, 1);
|
|
info.TradeOriginalAmountV_After = CalculationModule.TradeCalcHelper.GetTradeAmountV(item.t, info.TradeOriginalAmount_After, 1);
|
|
|
|
result.Add(info);
|
|
}
|
|
if (req.DividendStatus != null)
|
|
{
|
|
result = result.Where(O => O.DividendStatus == req.DividendStatus.Value).ToList();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private double TryParseDouble(string str, double defaultValue)
|
|
{
|
|
return double.TryParse(str, out var result) ? result : defaultValue;
|
|
}
|
|
|
|
public byte[] ExportDividendTrade(DividendTradeReq req)
|
|
{
|
|
var ret = QueryDividendTrade(req);
|
|
|
|
var dc = new List<ExcelHelper.DataColumnModel>
|
|
{
|
|
new ExcelHelper.DataColumnModel("交易编号", "TradeNumber"),
|
|
new ExcelHelper.DataColumnModel("股权登记日", "ExDividendDate", dateFormatter),
|
|
new ExcelHelper.DataColumnModel("除权除息状态", "DividendStatus", (cv, obj) =>
|
|
{
|
|
var status = (bool)cv;
|
|
return status ? "已除权" : "未除权";
|
|
}),
|
|
new ExcelHelper.DataColumnModel("交易状态", "TradeStatus"),
|
|
new ExcelHelper.DataColumnModel("交易对手方", "ClientName"),
|
|
new ExcelHelper.DataColumnModel("结构类型", "TradeType"),
|
|
new ExcelHelper.DataColumnModel("名义本金", "StockEqvNotional", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.StockEqvNotional, trade.StockEqvNotional_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("成交日期", "TradeDate", dateFormatter),
|
|
new ExcelHelper.DataColumnModel("到期日期", "ExerciseDate", dateFormatter),
|
|
new ExcelHelper.DataColumnModel("标的代码", "UnderlyingCode"),
|
|
new ExcelHelper.DataColumnModel("除权除息系数", "DividendRatio", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.DividendRatio, double.NaN, 6);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("期初标的价格", "SpotPrice", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.SpotPrice, trade.SpotPrice_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("执行价格", "Strike", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.Strike, trade.Strike_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("成交数量", "TradeOriginalAmount", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
var amountv = CalculationModule.TradeCalcHelper.GetTradeAmountV(trade.trade,trade.TradeOriginalAmount,1);
|
|
var amountv_after = CalculationModule.TradeCalcHelper.GetTradeAmountV(trade.trade,trade.TradeOriginalAmount_After,1);
|
|
result = priceFormatter(amountv, amountv_after, OtcFormatFlag.notional);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("有效成交数量", "TradeOriginalAmount", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.TradeOriginalAmount, trade.TradeOriginalAmount_After, OtcFormatFlag.notional);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("高行权价", "StrikeHigh", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.StrikeHigh, trade.StrikeHigh_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("障碍价格", "Barrier", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.Barrier, trade.Barrier_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("高障碍价格", "BarrierHigh", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.BarrierHigh, trade.BarrierHigh_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("敲入障碍价格", "KIBarrier", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.KIBarrier, trade.KIBarrier_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("敲出障碍价格", "KOBarrier", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.KOBarrier, trade.KOBarrier_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("票息障碍价格", "CouponBarrier", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.CouponBarrier, trade.CouponBarrier_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("互换标的代码(收取方)", "GetUnderlyingCode"),
|
|
new ExcelHelper.DataColumnModel("互换标的价格(收取方)", "GetSpotPrice", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.GetSpotPrice, trade.GetSpotPrice_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("互换标的代码(支付方)", "PayUnderlyingCode"),
|
|
new ExcelHelper.DataColumnModel("互换标的价格(支付方)", "PaySpotPrice", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.PaySpotPrice, trade.PaySpotPrice_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("区间下限", "LowerRange", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.LowerRange, trade.LowerRange_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("区间上限", "UpperRange", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.UpperRange, trade.UpperRange_After, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("敲出期权行权价1", "SpreadStrikeAtKO1", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.SpreadStrikeAtKO1 ?? double.NaN, trade.SpreadStrikeAtKO1_After ?? double.NaN, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("敲出期权行权价2", "SpreadStrikeAtKO", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.SpreadStrikeAtKO ?? double.NaN, trade.SpreadStrikeAtKO_After ?? double.NaN, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("敲入期权行权价1", "SpreadStrikeAtMaturity1", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.SpreadStrikeAtMaturity1 ?? double.NaN, trade.SpreadStrikeAtMaturity1_After ?? double.NaN, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
}),
|
|
new ExcelHelper.DataColumnModel("封顶/封底行权价", "SpreadStrikeAtMaturity", (cv, obj) =>
|
|
{
|
|
var result = "";
|
|
if (obj is DividendTrade trade)
|
|
{
|
|
result = priceFormatter(trade.SpreadStrikeAtMaturity ?? double.NaN, trade.SpreadStrikeAtMaturity_After ?? double.NaN, OtcFormatFlag.umprice);
|
|
}
|
|
return result;
|
|
})
|
|
};
|
|
new ExcelHelper().ListToExcel<DividendTrade>(dc.ToArray(), ret, "Sheet1", true, out var buffer);
|
|
return buffer;
|
|
}
|
|
|
|
private string dateFormatter(dynamic cv, object obj)
|
|
{
|
|
var result = "";
|
|
if (cv is DateTime dt)
|
|
{
|
|
result = dt.ToString("yyyy-MM-dd");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private string priceFormatter(double p1, double p2, int precision)
|
|
{
|
|
var result = "";
|
|
if (!double.IsNaN(p1) && p1 != 0)
|
|
{
|
|
result = OtcFormatExtensions.OtcFormatFlex(p1, minDecimals: precision, maxDecimals: precision);
|
|
}
|
|
if (!double.IsNaN(p2) && p2 != 0)
|
|
{
|
|
result += $"({OtcFormatExtensions.OtcFormatFlex(p2, minDecimals: precision, maxDecimals: precision)})";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private string priceFormatter(double p1, double p2, OtcFormatFlag formatFlag)
|
|
{
|
|
var result = "";
|
|
if (!double.IsNaN(p1) && p1 != 0)
|
|
{
|
|
result = OtcFormatExtensions.OtcFormat(p1, formatFlag);
|
|
}
|
|
if (!double.IsNaN(p2) && p2 != 0)
|
|
{
|
|
result += $"({OtcFormatExtensions.OtcFormat(p2, formatFlag)})";
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
}
|