Files
zszq-trs/YLErpDAL/Modules/ClientModule/ClientPositionService.cs
T
2024-05-09 14:06:26 +08:00

713 lines
35 KiB
C#

using System.Data;
using YLErp.BLL;
using YLErp.DBModels.Enums;
using YLErp.DBModels.Helpers;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.DataProviderModule;
using YLErp.Modules.EodModule;
using YLErp.Modules.TradeModule;
namespace YLErp.Modules.ClientModule
{
/// <summary>
/// 客户持仓服务
/// </summary>
public class ClientPositionService : YLBaseService
{
public ClientPositionService(OptUserInfo userInfo) : base(userInfo)
{
}
public ClientPositionService(YLBaseService baseService) : base(baseService)
{
}
/// <summary>
/// 获取客户持仓(返回分页数据)
/// </summary>
public IPagedList<ClientPositionModel> GetAllPositionsV1(ClientPositionQueryModel queryModel)
{
return InnerGetAllPositionsV1(queryModel);
}
private IPagedList<ClientPositionModel> InnerGetAllPositionsV1(ClientPositionQueryModel queryModel, ApiVersion apiVersion = ApiVersion.v1)
{
if (queryModel.ValueDate == null)
{
queryModel.ValueDate = valuedateBLL.ValueDate;
}
//日终结算数据
if (queryModel.ValueDate <= EodDataHelper.GetLastSettleDate(valuedateBLL.ValueDate))
{
var query = CreateEodPositionQuery(queryModel);
var pagedList = query.ToPagedList(queryModel);
ProcessClientPositionModel(apiVersion, pagedList, queryModel.ValueDate.Value, true);
LoadTradeMeta(pagedList);
return pagedList;
}
else //日内实时数据
{
var query = CreateIntradayPositionQuery(queryModel);
var pagedList = query.ToPagedList(queryModel);
ProcessClientPositionModel(apiVersion, pagedList, queryModel.ValueDate.Value, false);
//读取交易的期权结构信息
LoadTradeExtend(pagedList);
LoadTradeMeta(pagedList);
return pagedList;
}
}
/// <summary>
/// 获取客户持仓V2(返回分页数据)
/// </summary>
public IPagedList<ClientPositionModel> GetAllPositionsV2(ClientPositionQueryModel queryModel)
{
return InnerGetAllPositionsV2(queryModel);
}
private IPagedList<ClientPositionModel> InnerGetAllPositionsV2(ClientPositionQueryModel queryModel, ApiVersion apiVersion = ApiVersion.v2)
{
queryModel.AllStatusIncluded = true;
var pagedList = GetAllPositionsV1(queryModel);
//获取平仓价和平仓标的价
//平仓价和平仓标的价只有交易确认后才有
var tradeIds = pagedList.Where(n => n.TradeStatus >= EnumTradeStatus.confirmed).Select(n => n.TradeId).ToArray();
var tcDic = new Dictionary<int, TradeCashData>(tradeIds.Length);
for (var i = 0; i < tradeIds.Length; i += 1000)
{
var subTradeIds = tradeIds.Skip(i).Take(1000);
var query = from tc in DbContext.trade_cash
where subTradeIds.Contains(tc.TradeId)
&& tc.Action != ClientCashInCashOut.系统操作_期权费
&& tc.ValidState != "InValid" && !tc.IsDeleted
group tc by tc.TradeId into g
select new TradeCashData
{
tradeId = g.Key,
UnwindNotional = g.Sum(n => n.UnwindNotional ?? 0),
UnwindAmount = g.Sum(n => n.Amount),
FinalPrice = g.Sum(n => (n.FinalPrice ?? 0) * (n.UnwindNotional ?? 0)),
UnwindDate = g.Max(n => n.ValueDate)
};
foreach (var item in query)
{
tcDic.Add(item.tradeId, item);
}
}
//获取对冲波动率
//所有交易状态的对冲波动率都需要
tradeIds = pagedList.Select(n => n.TradeId).ToArray();
var dic2 = new TradeHisDataService(this).GetLatestHedgeVol(tradeIds);
//赋值
foreach (var item in pagedList)
{
if (tcDic.TryGetValue(item.TradeId, out var data) && data.UnwindNotional > 0)
{
//把平仓总额转为正向值(这样平仓单价和界面输入时的符号一致)
var amount = data.UnwindAmount * TradeCalcHelper.GetBuySellSign(item.BuySell);
item.UnwindPrice = amount / data.UnwindNotional;
item.FinalPrice = data.FinalPrice / data.UnwindNotional;
item.UnwindDate = data.UnwindDate;
}
else
{
item.UnwindPrice = 0;
item.FinalPrice = 0;
}
if (dic2.TryGetValue(item.TradeId, out var hedgeVol))
{
item.HedgeVol = hedgeVol;
}
}
return pagedList;
}
/// <summary>
/// 获取客户持仓V3(返回分页数据)
/// </summary>
public IPagedList<ClientPositionModel> GetAllPositionsV3(ClientPositionQueryModel queryModel)
{
if ("v2".Equals(queryModel.DataVersion, StringComparison.OrdinalIgnoreCase))
{
return InnerGetAllPositionsV2(queryModel, ApiVersion.v3);
}
return InnerGetAllPositionsV1(queryModel, ApiVersion.v3);
}
/// <summary>
/// 创建客户日内持仓查询语句
/// </summary>
/// <param name="clientId">客户ID,为0表示所有客户</param>
private IQueryable<ClientPositionModel> CreateIntradayPositionQuery(ClientPositionQueryModel queryModel)
{
var clientId = queryModel.ClientId;
var clientNumber = queryModel.ClientNumber.TrimToNull();
var tradeStatus = queryModel.TradeStatus;
if (clientId < 1 && !string.IsNullOrEmpty(clientNumber))
{
var cid = DataCacheProvider.GetClientDataSource().AsQueryable()
.Where(n => clientNumber.Equals(n.Number, StringComparison.OrdinalIgnoreCase))
.Select(n => (int?)n.id).FirstOrDefault();
if (!cid.HasValue)
{
return Array.Empty<ClientPositionModel>().AsQueryable();
}
clientId = cid.Value;
}
var ValueDate = valuedateBLL.ValueDate;
var predicate = PredicateBuilder.Create<trade>(n => n.ClientId > 0
&& n.ValidState != ConsGlobal.InValid && (n.TradeType != "结构化交易" || n.IsGroup == 1));
if (clientId > 0)
{
predicate = PredicateBuilder.Create<trade>(n => n.ClientId == clientId).And(predicate);
}
if (queryModel.AllStatusIncluded)
{
if (tradeStatus != null && tradeStatus.Any(n => n > 0))
{
var status = tradeStatus.Select(n => TradeHelper.GetTradeStatus(n)).ToHashSet();
predicate = predicate.And(n => status.Contains(n.TradeStatus));
}
}
else
{
var suspensionUnderlyingIdList = DbContext.underlying_manager.Where(t => t.UnderlyingStatus == underlying_manager.Status_Suspension).Select(t => t.id).ToList();
predicate = predicate.And(n => ConsTrade.NeedMarginTradeStatusList.Contains(n.TradeStatus)
&& (n.ExerciseDate >= ValueDate || suspensionUnderlyingIdList.Contains(n.UnderlyingId)));
}
var riskQuery = from tr in DbContext.realtime_trade_risk where tr.ValueDate == ValueDate && tr.VolType == "持仓" select tr;
var posiQuery = from tr in DbContext.intraday_trade_position where tr.ValueDate == ValueDate select new { tr.TradeId, tr.Margin };
var snowballQuery = DbContext.trade_snowball.AsNoTracking();
var asianQuery = DbContext.trade_asian_option.AsNoTracking();
var barrierQuery = DbContext.trade_barrier_option.AsNoTracking();
var binaryOptionQuery = DbContext.trade_binary_option.AsNoTracking();
var rainbowOptionQuery = DbContext.trade_rainbow_option.AsNoTracking();
var spreadOptionQuery = DbContext.trade_spread_option.AsNoTracking();
var doubleSharkfinOptionQuery = DbContext.trade_double_sharkfin_option.AsNoTracking();
var rangeaccrualOptionQuery = DbContext.trade_rangeaccrual.AsNoTracking();
var underlyingEnhanceOptionQuery = DbContext.trade_underlying_enhance.AsNoTracking();
var airbagOptionQuery = DbContext.trade_airbag.AsNoTracking();
var autocallOptionQuery = DbContext.trade_autocall.AsNoTracking();
var query = from trade in DbContext.trade.Where(predicate)
join assetbook in DbContext.assetunit on trade.AssetId equals assetbook.id
join risk in riskQuery on trade.id equals risk.TradeId into risks
from risk in risks.DefaultIfEmpty()
join epos in DbContext.eod_trade_position on new { valueDate = ValueDate, id = trade.TraderId } equals new { valueDate = epos.ValueDate, id = epos.TradeId } into positions
from epos in positions.DefaultIfEmpty()
join posi in posiQuery on trade.id equals posi.TradeId into posis
from posi in posis.DefaultIfEmpty()
join asian in asianQuery on new { TradeId = trade.id, trade.TradeType } equals new { asian.TradeId, TradeType = "亚式期权" } into asian_t
from asian in asian_t.DefaultIfEmpty()
join barrier in barrierQuery on new { TradeId = trade.id, trade.TradeType } equals new { barrier.TradeId, TradeType = "障碍期权" } into barrier_t
from barrier in barrier_t.DefaultIfEmpty()
join snowball in snowballQuery on new { TradeId = trade.id, trade.TradeType } equals new { snowball.TradeId, TradeType = "雪球期权" } into snowball_t
from snowball in snowball_t.DefaultIfEmpty()
join binary in binaryOptionQuery on new { TradeId = trade.id, trade.TradeType } equals new { binary.TradeId, TradeType = "二元期权" } into binary_t
from binary in binary_t.DefaultIfEmpty()
join rainbow in rainbowOptionQuery on new { TradeId = trade.id, trade.TradeType } equals new { rainbow.TradeId, TradeType = "彩虹期权" } into rainbow_t
from rainbow in rainbow_t.DefaultIfEmpty()
join spread in spreadOptionQuery on new { TradeId = trade.id, trade.TradeType } equals new { spread.TradeId, TradeType = "价差期权" } into spread_t
from spread in spread_t.DefaultIfEmpty()
join doublesharkfin in doubleSharkfinOptionQuery on new { TradeId = trade.id, trade.TradeType } equals new { doublesharkfin.TradeId, TradeType = "双鲨期权" } into doublesharkfin_t
from doublesharkfin in doublesharkfin_t.DefaultIfEmpty()
join rangeaccrual in rangeaccrualOptionQuery on new { TradeId = trade.id, trade.TradeType } equals new { rangeaccrual.TradeId, TradeType = "区间累积期权" } into rangeaccrual_t
from rangeaccrual in rangeaccrual_t.DefaultIfEmpty()
join underlyingEnhance in underlyingEnhanceOptionQuery on new { TradeId = trade.id, trade.TradeType } equals new { underlyingEnhance.TradeId, TradeType = "收益增强结构" } into underlyingEnhance_t
from underlyingEnhance in underlyingEnhance_t.DefaultIfEmpty()
join airbag in airbagOptionQuery on new { TradeId = trade.id, trade.TradeType } equals new { airbag.TradeId, TradeType = "气囊结构" } into airbag_t
from airbag in airbag_t.DefaultIfEmpty()
join autocall in autocallOptionQuery on new { TradeId = trade.id, trade.TradeType } equals new { autocall.TradeId, TradeType = "凤凰期权" } into autocall_t
from autocall in autocall_t.DefaultIfEmpty()
orderby trade.id descending
select new ClientPositionModel
{
ClientId = trade.ClientId,
TradeNumber = trade.TradeNumber,
UnderlyingCode = trade.UnderlyingCode,
BuySell = trade.BuySell,//交易员角度提供数据
RoundedPv = risk == null ? 0 : (double?)risk.RoundedPv.Value,
RoundedPnl = risk == null ? 0 : (double?)risk.RoundedPositionPnl.Value,
ExerciseDate = trade.ExerciseDate,
InitialSpotPrice = trade.SpotPrice ?? 0,
Strike = trade.Strike ?? 0,
OriginalStockEqvNotional = trade.OriginalStockEqvNotional ?? 0,
TradeAmount = trade.TradeAmount,
TradeDate = trade.TradeDate,
ExerciseMode = trade.ExerciseMode,
CallPut = trade.OptionType,
TradeType = trade.TradeType,
StructureType = trade.StructureType,
TradeOpenVolatility = trade.TradeOpenVolatility ?? 0,
OriginalNotional = trade.OriginalNotional ?? 0,
TradePrice = trade.TradePrice ?? 0,
TradeSinglePrice = trade.TradeSinglePrice ?? 0,
PosiSettlePrice = risk == null ? null : (double?)risk.UnderlyingPrice,
Vol = risk.Vol ?? 0,
Delta = risk.Delta ?? 0,
Gamma = risk.Gamma ?? 0,
Theta = risk.Theta ?? 0,
Vega = risk.Vega ?? 0,
Rho = risk.Rho ?? 0,
Pv = risk.Pv ?? 0,
Notional = trade.Notional,
InstrumentType = trade.UnderlyingInstrumentType,
TradeId = trade.id,
ParticipationRate = trade.ParticipationRate ?? 1,
PrincipalSum = (trade.OriginalPrincipalSum * trade.StockEqvNotional / trade.OriginalStockEqvNotional) ?? 0,
AnnualizeFactor = trade.AnnualizeFactor ?? 1,
AssetBookName = assetbook.Name,
DeltaLots = 0,
GammaLots = 0,
CurrentPrice = 0,
Comments = trade.Comments,
TradeStatusProxy = trade.TradeStatus,
TradeCloseVolatility = trade.TradeCloseVolatility ?? 0,
ParentTradeId = trade.IsGroup == 2 ? trade.ParentTradeId : 0,
//下面这行在数据库字段定义为bit null的情况下会报FormatException
//IsUsePremiumRate = trade.IsUsePremiumRate ?? false,
IsUsePremiumRate = trade.IsUsePremiumRate == true,
IsUseTotalPremium = trade.IsTradePricePayType,
IsMoneynessOption = trade.IsMoneynessOption == "是",
AsianOption = asian,
BarrierOption = barrier,
SnowballOption = snowball,
BinaryOption = binary,
DoubleSharkfinOption = doublesharkfin,
RangeaccrualOption = rangeaccrual,
UnderlyingEnhanceOption = underlyingEnhance,
AirbagOption = airbag,
AutocallOption = autocall,
Margin = posi != null ? (double?)posi.Margin : default,
KeepMargin = epos != null ? epos.Margin : default,
InitMargin = trade.InitialMargin ?? 0
};
return query;
}
/// <summary>
/// 创建客户日终持仓查询语句
/// </summary>
/// <param name="clientId">客户ID,为0表示所有客户</param>
private IQueryable<ClientPositionModel> CreateEodPositionQuery(ClientPositionQueryModel queryModel)
{
var clientId = queryModel.ClientId;
var clientNumber = queryModel.ClientNumber.TrimToNull();
var tradeStatus = queryModel.TradeStatus;
if (clientId < 1 && !string.IsNullOrEmpty(clientNumber))
{
var cid = DataCacheProvider.GetClientDataSource().AsQueryable()
.Where(n => clientNumber.Equals(n.Number, StringComparison.OrdinalIgnoreCase))
.Select(n => (int?)n.id).FirstOrDefault();
if (!cid.HasValue)
{
return Array.Empty<ClientPositionModel>().AsQueryable();
}
clientId = cid.Value;
}
var valueDate = queryModel.ValueDate.Value;
var predicate = PredicateBuilder.Create<trade>(n => n.ClientId > 0
&& n.ValidState != ConsGlobal.InValid && (n.TradeType != "结构化交易" || n.IsGroup == 1));
if (clientId > 0)
{
predicate = PredicateBuilder.Create<trade>(n => n.ClientId == clientId).And(predicate);
}
var riskQuery = DbContext.eod_trade_risk.Where(tr => tr.ValueDate == valueDate);
var posiQuery = DbContext.eod_trade_position.Where(tr => tr.ValueDate == valueDate);
var query = from et in DbContext.eod_trade
join trade in DbContext.trade.Where(predicate) on et.TradeId equals trade.id
join assetbook in DbContext.assetunit on trade.AssetId equals assetbook.id
join risk in riskQuery on trade.id equals risk.TradeId into risks
from risk in risks.DefaultIfEmpty()
join posi in posiQuery on trade.id equals posi.TradeId into posis
from posi in posis.DefaultIfEmpty()
where et.ValueDate == valueDate
orderby trade.id descending
select new ClientPositionModelEod
{
ClientId = trade.ClientId,
TradeNumber = trade.TradeNumber,
UnderlyingCode = trade.UnderlyingCode,
BuySell = trade.BuySell,//交易员角度提供数据
RoundedPv = posi.RoundedPv,
RoundedPnl = posi.RoundedPositionPnL,
ExerciseDate = trade.ExerciseDate,
InitialSpotPrice = trade.SpotPrice ?? 0,
Strike = trade.Strike ?? 0,
OriginalStockEqvNotional = trade.OriginalStockEqvNotional ?? 0,
TradeAmount = posi != null ? posi.Amount : trade.TradeAmount,
Notional = posi != null ? posi.Amount : trade.Notional,
TradeDate = trade.TradeDate,
ExerciseMode = trade.ExerciseMode,
CallPut = trade.OptionType,
TradeType = trade.TradeType,
StructureType = trade.StructureType,
TradeOpenVolatility = trade.TradeOpenVolatility ?? 0,
OriginalNotional = trade.OriginalNotional ?? 0,
TradePrice = trade.TradePrice ?? 0,
TradeSinglePrice = trade.TradeSinglePrice ?? 0,
InstrumentType = trade.UnderlyingInstrumentType,
PosiSettlePrice = posi.UnderlyingPrice,
Vol = risk.Vol,
Delta = risk.Delta,
Gamma = risk.Gamma,
Theta = risk.Theta,
Vega = risk.Vega,
Rho = risk.Rho,
Pv = risk.Pv,
TradeId = trade.id,
ParticipationRate = trade.ParticipationRate ?? 1,
PrincipalSum = (trade.OriginalPrincipalSum * trade.StockEqvNotional / trade.OriginalStockEqvNotional) ?? 0,
AnnualizeFactor = trade.AnnualizeFactor ?? 1,
AssetBookName = assetbook.Name,
DeltaLots = 0,
GammaLots = 0,
CurrentPrice = 0,
Comments = trade.Comments,
TradeStatusProxy = trade.TradeStatus,
TradeCloseVolatility = trade.TradeCloseVolatility ?? 0,
ParentTradeId = trade.IsGroup == 2 ? trade.ParentTradeId : 0,
//下面这行在数据库字段定义为bit null的情况下会报FormatException
//IsUsePremiumRate = trade.IsUsePremiumRate ?? false,
IsUsePremiumRate = trade.IsUsePremiumRate == true,
IsUseTotalPremium = trade.IsTradePricePayType,
IsMoneynessOption = trade.IsMoneynessOption == "是",
Margin = posi.Margin,
InitMargin = trade.InitialMargin ?? 0,
TradeJson = et.TradeJson
};
return query;
}
/// <summary>
///
/// </summary>
private void ProcessClientPositionModel(ApiVersion apiVersion, IEnumerable<ClientPositionModel> clientPositionModels, DateTime valueDate, bool isEodPosition)
{
(string tradeType, Action<ClientPositionModel> setNull)[] setNullArr = null;
var eodPriceProvider = new Lazy<EodPriceProvider>(() => new EodPriceProvider(valueDate));
foreach (var item in clientPositionModels)
{
var um = UnderlyingDataProvider.GetUnderlying(item.UnderlyingCode);
if (um != null)
{
if (item.UnderlyingPrice == null)
{
item.UnderlyingPrice = um.Price ?? 0;
}
item.UnderlyingName = um.UnderlyingName;
//成交数量
item.TradeOriginalAmount = item.OriginalNotional / um.CountRatio;
if (um.IsSynthetic())
{
var synthetic = UnderlyingDataProvider.GetSyntheticUnderlying(um.UnderlyingCode);
if (synthetic != null)
{
item.Synthetic = synthetic.GetSyntheticPriceModel();
}
}
}
else
{
item.TradeOriginalAmount = item.OriginalNotional;
}
if (apiVersion < ApiVersion.v3)
{
item.RoundedPv = -item.RoundedPv;
item.RoundedPnl = -item.RoundedPnl;
var pv = PS.Config.IsPVRounded ? item.RoundedPv : item.Pv;
//传入的pv是客户角度但是TradeHelper.GetTradeSinglePriceByTradePrice用的是交易员角度所以需要pv再取反
//RoundedPv用的是客户方向,pv用的是交易员方向,所以CurrentPrice的方向受到了IsPVRounded配置影响,这其实是个bug,但是国君希望原来的数据逻辑不动,所以保留
item.CurrentPrice = TradeHelper.GetTradeSinglePriceByTradePrice(-pv, item.Notional, !PS.Config.ErpElement.IsPVIncludePrincipal ? 0 : item.PrincipalSum, item.BuySell, item.TradeType, false);
}
else
{
var pv = PS.Config.IsPVRounded ? item.RoundedPv : item.Pv;
item.CurrentPrice = TradeHelper.GetTradeSinglePriceByTradePrice(pv, item.Notional, !PS.Config.ErpElement.IsPVIncludePrincipal ? 0 : item.PrincipalSum, item.BuySell, item.TradeType, false);
}
//delta手数&gamma手数
if (item.Delta == null || double.IsNaN(item.Delta.Value))
{
item.Delta = 0;
}
if (item.Gamma == null || double.IsNaN(item.Gamma.Value))
{
item.Gamma = 0;
}
var contractSize = um?.ContractSize ?? (ConsGlobal.InstrumentType.IsStock(item.InstrumentType) ? 100 : 1);
item.DeltaLots = item.Delta.Value / contractSize;
item.GammaLots = item.Gamma.Value / contractSize;
item.ClientNumber = DataCacheProvider.GetClientDataSource().GetData(item.ClientId)?.Number;
if (isEodPosition)
{
var eodPosi = (ClientPositionModelEod)item;
var td = TradeHelper2.Deserialize(eodPosi.TradeJson);
if (td != null)
{
item.AsianOption = td.trade_asian_option;
item.BarrierOption = td.trade_barrier_option;
item.SnowballOption = td.trade_snowball;
item.BinaryOption = td.trade_binary_option;
item.DoubleSharkfinOption = td.trade_double_sharkfin_option;
item.RangeaccrualOption = td.trade_rangeaccrual;
item.UnderlyingEnhanceOption = td.trade_underlying_enhance;
item.AirbagOption = td.trade_airbag;
item.AutocallOption = td.trade_autocall;
item.AccumulatorOption = td.trade_accumulator_option;
item.Forward = td.trade_forward;
item.Swap = td.trade_swap;
item.CashFlow = td.trade_cashflow;
item.CustomOption = td.trade_custom;
}
item.UnderlyingPrice = eodPriceProvider.Value.GetPrice(item.UnderlyingCode, td?.SettlementType ?? SettlementTypeEnum.ClosePrice);
if (item.Synthetic?.SuList != null)
{
foreach (var su in item.Synthetic.SuList)
{
su.Price = eodPriceProvider.Value.GetPrice(su.UnderlyingCode, td?.SettlementType ?? SettlementTypeEnum.ClosePrice);
}
item.Synthetic.Price = item.Synthetic.SuList.Sum(n => n.Coefficient * n.Price) + item.Synthetic.Constant;
}
if (um != null)
{
item.TradeAmount = item.Notional / um.CountRatio;
}
}
else
{
if (item.TradeStatus >= EnumTradeStatus.closed)
{
item.CurrentPrice = 0;
item.Pv = item.RoundedPv = item.RoundedPnl = 0;
item.Delta = item.Gamma = 0;
item.DeltaLots = item.GammaLots = 0;
item.TradeAmount = item.Notional = 0;
}
if (item.Synthetic?.SuList != null)
{
foreach (var su in item.Synthetic.SuList)
{
su.Price = UnderlyingDataProvider.GetUnderlying(su.UnderlyingCode)?.Price ?? 0;
}
item.Synthetic.Price = item.Synthetic.SuList.Sum(n => n.Coefficient * n.Price) + item.Synthetic.Constant;
}
}
if (item.UnderlyingPrice == null)
{
item.UnderlyingPrice = 0;
}
if (item.PosiSettlePrice == null)
{
item.PosiSettlePrice = item.UnderlyingPrice;
}
setNullValues(item);
}
void setNullValues(ClientPositionModel model)
{
if (setNullArr == null)
{
setNullArr = new (string tradeType, Action<ClientPositionModel> setNull)[] {
("亚式期权", m=> m.AsianOption = null ),
("障碍期权", m=> m.BarrierOption = null),
("二元期权", m=> m.BinaryOption = null ),
("双鲨期权", m=> m.DoubleSharkfinOption = null ),
("雪球期权", m=> m.SnowballOption = null ),
("凤凰期权", m=> m.AutocallOption = null ),
("累计期权", m=> m.AccumulatorOption = null ),
("区间累积期权", m=> m.RangeaccrualOption = null ),
("收益增强结构", m=> m.UnderlyingEnhanceOption = null ),
("气囊结构", m=> m.AirbagOption = null ),
("远期", m=> m.Forward = null ),
("收益互换", m=> m.Swap = null ),
("现金流", m=> m.CashFlow = null ),
("自定义交易", m=> m.CustomOption = null ),
};
}
foreach (var item in setNullArr)
{
if (model.TradeType == "结构化交易")
{
if (item.tradeType != model.StructureType)
{
item.setNull(model);
}
}
else if (item.tradeType != model.TradeType)
{
item.setNull(model);
}
}
}
}
private void LoadTradeExtend(IEnumerable<ClientPositionModel> clientPositionModels)
{
var forwardTradeIds = clientPositionModels.Where(b => b.TradeType == "远期").Select(b => b.TradeId).ToList();
var forwardOptions = DbContext.trade_forward.Where(b => forwardTradeIds.Contains(b.TradeId))?.ToDictionary(b => b.TradeId, b => b);
var swapTradeIds = clientPositionModels.Where(b => b.TradeType == "收益互换").Select(b => b.TradeId).ToList();
var swapOptions = DbContext.trade_swap.Where(b => swapTradeIds.Contains(b.TradeId))?.ToDictionary(b => b.TradeId, b => b);
var cashTradeIds = clientPositionModels.Where(b => b.TradeType == "现金流交易").Select(b => b.TradeId).ToList();
var cashOptions = DbContext.trade_cashflow.Where(b => swapTradeIds.Contains(b.TradeId))?.ToDictionary(b => b.TradeId, b => b);
var accumulatorTradeIds = clientPositionModels.Where(b => b.TradeType == "累计期权").Select(b => b.TradeId).ToList();
var accumulatorOptions = DbContext.trade_accumulator_option.Where(b => swapTradeIds.Contains(b.TradeId))?.ToDictionary(b => b.TradeId, b => b);
var customTradeIds = clientPositionModels.Where(b => b.TradeType == "自定义交易").Select(b => b.TradeId).ToList();
var customOptions = DbContext.trade_custom.Where(b => swapTradeIds.Contains(b.TradeId))?.ToDictionary(b => b.TradeId, b => b);
foreach (var model in clientPositionModels)
{
switch (model.TradeType)
{
case "远期":
if (forwardOptions != null && forwardOptions.TryGetValue(model.TradeId, out var forward))
{
model.Forward = forward;
}
break;
case "收益互换":
if (swapOptions != null && swapOptions.TryGetValue(model.TradeId, out var swap))
{
model.Swap = swap;
}
break;
case "现金流交易":
if (cashOptions != null && cashOptions.TryGetValue(model.TradeId, out var cash))
{
model.CashFlow = cash;
}
break;
case "累计期权":
if (accumulatorOptions != null && accumulatorOptions.TryGetValue(model.TradeId, out var accumulator))
{
model.AccumulatorOption = accumulator;
}
break;
case "自定义交易":
if (customOptions != null && customOptions.TryGetValue(model.TradeId, out var custom))
{
model.CustomOption = custom;
}
break;
}
}
}
private void LoadTradeMeta(IEnumerable<ClientPositionModel> clientPositionModels)
{
var tradeIds = clientPositionModels.Select(b => b.TradeId).ToList();
var metaDics = DbContext.TradeMeta.Where(b => tradeIds.Contains(b.TradeId))
.Select(n => new { n.TradeId, n.MetaKey, n.MetaValue })
.ToArray().GroupBy(n => n.TradeId)
.ToDictionary(n => n.Key, n => n.ToDictionary(m => m.MetaKey, m => m.MetaValue));
foreach (var posi in clientPositionModels)
{
if (metaDics.TryGetValue(posi.TradeId, out var mdic))
{
posi.MetaDic = mdic;
}
}
}
/// <summary>
/// v3全部统一成交易员方向,原来的v1和v2既有交易员方向也有客户方向,太烧脑
/// </summary>
enum ApiVersion { v1, v2, v3 }
class TradeCashData
{
public int tradeId { get; set; }
public double UnwindNotional { get; set; }
public double UnwindAmount { get; set; }
public double FinalPrice { get; set; }
public DateTime UnwindDate { get; set; }
}
class ClientPositionModelEod : ClientPositionModel
{
internal string TradeJson { get; set; }
}
}
}