上次失败根因: EodClientBalanceCalc:134 是 EF Core LINQ 表达式,
HashSet.Contains 无法翻译成 SQL, 导致场景3/4 全红。
修正: MarginModes 新增 ForLinq(List<int>) 供 EF Core 翻译用。
- SwapEodPositionService 2处纯函数(非LINQ): 用 MarginModes.Contains
- EodClientBalanceCalc LINQ表达式: 用 MarginModes.ForLinq.Contains
- RealTimeClientBanlanceService(已ToList,内存集合): 用 MarginModes.Contains
ConsTrade.InterestMarginModels 产品代码引用: 4处 → 0(只剩定义+注释)。
保证金mode判断 {初始预付金,追加预付金} 现在统一由 MarginModes 提供。
验证: sln编译0错误, 全量485测试7失败(基线一致,零回归)。
1382 lines
88 KiB
C#
1382 lines
88 KiB
C#
using DocumentFormat.OpenXml.Drawing.Charts;
|
|
using Newtonsoft.Json;
|
|
using NPOI.SS.Formula.Functions;
|
|
using NPOI.SS.UserModel;
|
|
using Org.BouncyCastle.Asn1.Ocsp;
|
|
using YieldChain.Helpers;
|
|
using YLErp.BLL;
|
|
using YLErp.BLL.MarginCalculation;
|
|
using YLErp.Configuration;
|
|
using YLErp.DBModels;
|
|
using YLErp.DBModels.Enums;
|
|
using YLErp.Helpers;
|
|
using YLErp.Model;
|
|
using YLErp.Model.Enum;
|
|
using YLErp.Models;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.EodModule.QueryModule;
|
|
using YLErp.Modules.SwapModule.Margin;
|
|
using YLErp.Modules.TradeRiskCalcModule;
|
|
|
|
namespace YLErp.Modules.EodModule.SettlementModule
|
|
{
|
|
/// <summary>
|
|
/// 客户结算
|
|
/// </summary>
|
|
public class EodClientBalanceCalc : EodSettleServiceBaseV2
|
|
{
|
|
public EodClientBalanceCalc(EodSettlementContextV2 context) : base(context)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 客户结算
|
|
/// </summary>
|
|
public bool ClientBalanceCalc()
|
|
{
|
|
var balanceDate = _context.SettleDate;
|
|
var reqClientIds = _context.Request.ClientIds;
|
|
|
|
var clientDb = DbContextFactory.GetClientDbContext(OptUser);
|
|
|
|
var currencyCodes = _context.CurrencyCodes;
|
|
var currencyProvider = _context.EodCurrencyProvider;
|
|
//预付金可取上浮比率
|
|
var marginRatio = Math.Round((decimal)(_context.SystemValue.MarginRatio ?? 0.15), 2, MidpointRounding.AwayFromZero);
|
|
var marginMaxRatio = marginRatio + 0.02m;
|
|
var preBalanceDate = _context.PreSettleDate;
|
|
var preClientbalancedailys = DbContext.ClientBalanceDaily.Where(t => t.BalanceDate == preBalanceDate).ToList();
|
|
if (reqClientIds != null && reqClientIds.Any())
|
|
{
|
|
preClientbalancedailys = preClientbalancedailys.Where(t => reqClientIds.Contains(t.ClientId)).ToList();
|
|
}
|
|
|
|
//获取所有客户信息
|
|
var clients = clientDb.client.Where(t => t.ProcessStatus != "未提交").ToList();
|
|
if (reqClientIds != null && reqClientIds.Any())
|
|
{
|
|
clients = clients.Where(t => reqClientIds.Contains(t.id)).ToList();
|
|
}
|
|
var allClientIds = clients.Select(t => t.id).ToList();
|
|
|
|
#region 客户结算相关数据初始化 eod_trade_position client_span eod_trade eodPrice
|
|
//获取所有客户授信
|
|
var creditList = DbContext.credit.Where(t => t.ProcessStatus == "已审批" && (!t.CreditDeadLine.HasValue || t.CreditDeadLine >= balanceDate) && (!t.CreditStartDate.HasValue || t.CreditStartDate <= balanceDate)).ToList();
|
|
if (reqClientIds != null && reqClientIds.Any())
|
|
{
|
|
creditList = creditList.Where(t => reqClientIds.Contains(t.ClientId ?? 0)).ToList();
|
|
}
|
|
//获取所有资信等级
|
|
var creditRatingList = clientDb.credit_rating.Where(t => t.ValidState != "InValid").ToList();
|
|
|
|
//出入金记录 获取上个结算日到当前结算日之间的所有已结算和已确认的出入金(包含周末的出入金)
|
|
var newValuedate = balanceDate.AddDays(1);
|
|
var lastBalanceDateAddOne = preBalanceDate.AddDays(1);
|
|
|
|
var entryexits = from cash in DbContext.ClientCashInCashOut.Where(t => t.ValidState != "InValid" && (t.HappenDate >= lastBalanceDateAddOne && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认)))
|
|
join trade in DbContext.trade on cash.TradeId equals trade.id into trade
|
|
from td in trade.DefaultIfEmpty()
|
|
where td.TradeType != "收益互换" && td.ValidState != ConsGlobal.InValid
|
|
select cash;
|
|
if (reqClientIds != null && reqClientIds.Any())
|
|
{
|
|
entryexits = entryexits.Where(t => reqClientIds.Contains(t.ClientId ?? 0));
|
|
}
|
|
|
|
var entryexits_swapAll = from cash in DbContext.ClientCashInCashOut.Where(t => t.ValidState != "InValid" && (t.HappenDate >= lastBalanceDateAddOne && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认)))
|
|
join trade in DbContext.trade.Where(x => x.TradeType == "收益互换") on cash.TradeId equals trade.id
|
|
select cash;
|
|
if (reqClientIds != null && reqClientIds.Any())
|
|
{
|
|
entryexits_swapAll = entryexits_swapAll.Where(t => reqClientIds.Contains(t.ClientId ?? 0));
|
|
}
|
|
var entryexits_swap = entryexits_swapAll.Where(t => t.HappenDate < newValuedate);
|
|
var entryexits_swapFuture = entryexits_swapAll.Where(t => t.HappenDate >= newValuedate);
|
|
//获取客户所有现存(抵押状态)抵押品信息
|
|
var clientProductList = (from product in DbContext.clientcashincashout_product
|
|
join variety in DbContext.variety on product.VarietyId equals variety.id into varietyTemp
|
|
from variety in varietyTemp.DefaultIfEmpty()
|
|
join um in DbContext.underlying_manager on product.UnderlyingId equals um.id into umTemp
|
|
from um in umTemp.DefaultIfEmpty()
|
|
where (product.Status == Clientcashincashout_productStatusEnum.抵押.ToString() && product.OptStatus == ClientCashInCashOut.已确认
|
|
|| product.Status == Clientcashincashout_productStatusEnum.赎回.ToString() && product.OptStatus != ClientCashInCashOut.已确认
|
|
|| product.Status == Clientcashincashout_productStatusEnum.赎回.ToString() && product.OptStatus == ClientCashInCashOut.已确认 && product.BackDate >= newValuedate)
|
|
&& allClientIds.Contains(product.ClientId) && product.HappenDate < newValuedate
|
|
select new { product, variety, um }).ToList();
|
|
|
|
if (reqClientIds != null && reqClientIds.Any())
|
|
{
|
|
clientProductList = clientProductList.Where(t => reqClientIds.Contains(t.product.ClientId)).ToList();
|
|
}
|
|
|
|
//获取所有用户当日Eod_Risk
|
|
var eodRiskList = DbContext.eod_trade_risk.Where(t => t.ValueDate == balanceDate).ToList();
|
|
if (reqClientIds != null && reqClientIds.Any())
|
|
{
|
|
eodRiskList = eodRiskList.Where(t => reqClientIds.Contains(t.ClientId)).ToList();
|
|
}
|
|
//获取客户导入的所有持仓信息 -- 收益互换(国君)
|
|
var EodPositionSwapMannual = DbContext.eod_trade_position_swap_mannual.Where(x => x.ValueDate == balanceDate).ToList();
|
|
if (reqClientIds != null && reqClientIds.Any())
|
|
{
|
|
EodPositionSwapMannual = EodPositionSwapMannual.Where(t => reqClientIds.Contains(t.ClientId)).ToList();
|
|
}
|
|
// 互换合约估值信息
|
|
var eodSwapQuery = from eod in DbContext.eod_swap.Where(x => x.ValueDate <= balanceDate && x.ValueDate >= preBalanceDate)
|
|
join t in DbContext.trade.Where(x => x.TradeType == "收益互换" && x.ValidState != ConsGlobal.InValid && ConsTrade.TradeStatusAfterConfirmed.Contains(x.TradeStatus) && x.TradeDate <= balanceDate) on eod.SwapTradeId equals t.id
|
|
select eod;
|
|
// 互换合约估值持仓信息
|
|
var eodSwapPosiQuery = from eod in DbContext.eod_swap_position.Where(x => x.ValueDate <= balanceDate && x.ValueDate >= preBalanceDate)
|
|
join t in DbContext.trade.Where(x => x.TradeType == "收益互换" && x.ValidState != ConsGlobal.InValid && ConsTrade.TradeStatusAfterConfirmed.Contains(x.TradeStatus) && x.TradeDate <= balanceDate) on eod.SwapTradeId equals t.id
|
|
select eod;
|
|
var positionList = DbContext.trade.Where(t => (ConsTrade.TradeStatusAfterConfirmed.Contains(t.TradeStatus)||t.UnWindDate> balanceDate) && t.ValidState != "InValid"&&t.TradeType=="收益互换");
|
|
var marignQuery = from t in positionList
|
|
join s in DbContext.eod_swap_position on t.id equals s.SwapTradeId
|
|
where MarginModes.ForLinq.Contains(s.InterestMode) && !s.Invalid && s.HappenDate <= balanceDate &&s.ValueDate==balanceDate
|
|
select new
|
|
{
|
|
ClientId = t.ClientId,
|
|
StructureType = t.StructureType,
|
|
marin = s.InterestPrincipalFix * (s.InterestDirection == 1 ? -1m : 1m)
|
|
};
|
|
// 互换平仓信息
|
|
var clientEventFlowQuery = from eod in DbContext.swap_flow_event.Where(x => x.EventDate <= balanceDate && x.EventDate > preBalanceDate && x.DataState == (int)SwapFlowDateStateEnum.完成 && x.EventType == (int)SwapFlowEventTypeEnum.平仓)
|
|
join t in DbContext.trade.Where(x => x.TradeType == "收益互换" && x.ValidState != ConsGlobal.InValid && ConsTrade.TradeStatusAfterConfirmed.Contains(x.TradeStatus) && x.TradeDate <= balanceDate) on eod.SwapTradeId equals t.id
|
|
select eod;
|
|
var clientEventFlows = clientEventFlowQuery.ToList();
|
|
var eodSwaps = eodSwapQuery.ToList();
|
|
var eodSwapPosis = eodSwapPosiQuery.ToList();
|
|
if (reqClientIds != null && reqClientIds.Any())
|
|
{
|
|
eodSwaps = eodSwaps.Where(t => reqClientIds.Contains(t.ClientId)).ToList();
|
|
eodSwapPosis= eodSwapPosis.Where(t => reqClientIds.Contains(t.ClientId)).ToList();
|
|
marignQuery = marignQuery.Where(t => reqClientIds.Contains(t.ClientId));
|
|
clientEventFlows.Where(t => reqClientIds.Contains(t.ClientId??0));
|
|
}
|
|
var swapIds = eodSwaps.Select(s => s.SwapTradeId);
|
|
var todaySwapTrades = DbContext.trade.Where(t => swapIds.Contains(t.id)).ToList();
|
|
// var swapMargins = DbContext.trade_initial_margin.Where(t => swapIds.Contains(t.TradeId)).ToList();
|
|
var underlyDataSource = DataCacheProvider.GetUnderlyingDataSource();
|
|
var varietyDataSource = DataCacheProvider.GetVarietyDataSource();
|
|
//客户预付金
|
|
var clientSpanList = DbContext.client_span.Where(t => t.ValueDate == balanceDate).ToList();
|
|
if (reqClientIds != null && reqClientIds.Any())
|
|
{
|
|
clientSpanList = clientSpanList.Where(t => reqClientIds.Contains(t.ClientId)).ToList();
|
|
}
|
|
//clientbalance
|
|
var newClientBalanceDaily = new List<ClientBalanceDaily>();
|
|
|
|
//获取客户所有交易信息(所及为客户所有确认交易,以及当日平仓或者当日执行的交易)
|
|
var trades = _context.OtcTrades.ToList();
|
|
|
|
//如果前一天是假日,要显示包含假日的交易
|
|
var preday = balanceDate.AddDays(-1);
|
|
//获取上一个交易日的下一天(例如收盘日是周一,上一个交易日就是周五,他的下一天就是周六,获取的是周六)
|
|
var nonHolidayAddOne = valuedateBLL.GetNonHolidayDefore(preday).AddDays(1);
|
|
var finishedTradeCash = DbContext.trade_cash
|
|
.Where(tc => (tc.ValueDate >= nonHolidayAddOne && tc.ValueDate <= balanceDate && tc.HappenedDate == null || tc.HappenedDate >= nonHolidayAddOne && tc.HappenedDate <= balanceDate)
|
|
&& tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted
|
|
&& (tc.Action == ClientCashInCashOut.系统操作_平仓费 || tc.Action == ClientCashInCashOut.系统操作_行权费 || tc.Action == ClientCashInCashOut.系统操作_互换 || tc.Action == ClientCashInCashOut.系统操作_票息 || tc.Action == ClientCashInCashOut.人工操作_其他));
|
|
var finishedTradeNotionalPercentDic = finishedTradeCash
|
|
.AsEnumerable()
|
|
.GroupBy(tc => tc.TradeId)
|
|
.ToDictionary(g => g.Key,
|
|
g => g.Sum(tc => tc.UnwindPercentRate ?? 0));
|
|
var keys = finishedTradeNotionalPercentDic.Select(d => d.Key).ToArray();
|
|
|
|
var dayeods = _context.GetEodPriceProvider();
|
|
|
|
//期权交易行权平仓产生的资金流水
|
|
//var tradeCashList = db.trade_cash.Where(t => allTradeIds.Contains(t.TradeId)).ToList();
|
|
|
|
//获取冻结资金信息
|
|
var clientFrozenFunds = new ClientFrozenFundsService(this).GetDatas(balanceDate, allClientIds);
|
|
|
|
#endregion
|
|
|
|
#region 循环客户信息计算客户资金信息
|
|
|
|
foreach (var client in clients)
|
|
{
|
|
_context.CancellationToken.ThrowIfCancellationRequested();
|
|
|
|
#region 变量初始化
|
|
List<ClientCashInCashOut> clientEntryexits;
|
|
List<ClientCashInCashOut> clientEntryexits_swap;
|
|
FundObject fundObject = new FundObject();
|
|
|
|
foreach (var currencyCode in currencyCodes)
|
|
{
|
|
fundObject.InFund.Add(currencyCode, 0);
|
|
fundObject.VmInFund.Add(currencyCode, 0);
|
|
fundObject.OutFund.Add(currencyCode, 0);
|
|
fundObject.VmOutFund.Add(currencyCode, 0);
|
|
fundObject.NetFund.Add(currencyCode, 0);
|
|
fundObject.InFundOther.Add(currencyCode, 0);
|
|
fundObject.OutFundOther.Add(currencyCode, 0);
|
|
fundObject.OtherFund.Add(currencyCode, 0);
|
|
fundObject.TodayRemainFund.Add(currencyCode, 0);
|
|
fundObject.LastDayRemainFund.Add(currencyCode, 0);
|
|
}
|
|
//入金
|
|
var inFund = 0.0;
|
|
var vmInFund = 0.0;
|
|
//出金
|
|
var outFund = 0.0;
|
|
var vmOutFund = 0.0;
|
|
//其他收入
|
|
var inFundOther = 0.0;
|
|
//其他支出
|
|
var outFundOther = 0.0;
|
|
//当日浮动盈亏
|
|
var CurrPnl = 0.0;
|
|
//当日浮动盈亏
|
|
var PositionPnl = 0.0;
|
|
var RoundedPositionPnl = 0.0;
|
|
//期权空头浮动盈利=∑max(期权空头持仓*(期权合约成本价-期权合约现价), 0) 从客户角度看的
|
|
var ClientSellPositionPnl = 0.0;
|
|
//当日总盈亏
|
|
var TotalPnl = 0.0;
|
|
//当日盈亏
|
|
double DailyPnl = 0;
|
|
//今日可用资金
|
|
var CurrAvailAmount = 0.0;
|
|
//今日可用资金
|
|
var LastDayAvailAmount = 0.0;
|
|
//当日资金变动
|
|
var CurrChangeAmount = 0.0;
|
|
//资信等级
|
|
//credit_rating creditRating = null;
|
|
//授信额度
|
|
var lineOfCredit = 0.0;
|
|
//用户持仓价值
|
|
double? clientPv;
|
|
double? roundedClientPv;
|
|
//用户卖出部分持仓价值
|
|
double? clientSellPv;
|
|
//客户持仓交易预付金总和,客户买入为正,客户卖出为负
|
|
double? PrepaymentAmount;
|
|
//期权费收支
|
|
var OptionPremium = 0.0;
|
|
//期权费收支
|
|
var OptionPremiumSwap = 0.0;
|
|
//结算收支(平仓行权)
|
|
var SettlementBalance = 0.0;
|
|
//平仓收支
|
|
var UnwindBalance = 0.0;
|
|
//行权收支
|
|
var ExerciseBalance = 0.0;
|
|
//实现盈亏
|
|
var WinLoss = 0.0;
|
|
//持仓期权费净额(客户角度卖出为负,买入为正)
|
|
var PositionPremiumNetCash = 0.0;
|
|
//权利金冻结(当日该客户所有持仓的卖出期权权利金)
|
|
var SellTradePrice = 0.0;
|
|
// 期初持仓交易净额
|
|
var LastDayPositionPremiumNetCash = 0.0;
|
|
//潜在行权盈余
|
|
var PotentialSurpluses = 0.0;
|
|
//权利金应付应收 总额
|
|
//var FrozenAndCopeWithExpirePremium = 0.0;
|
|
//净资金流入,其他资金,票息,互换收益,预付金余额,冻结权利金(未到期支付),冻结资金
|
|
double NetFund = 0.0, OtherFund = 0.0, Coupon = 0.0, SwapBalance = 0.0, MarginBalance, FrozenPremium, FrozenBalance = 0.0;
|
|
//应付到期权利金,应付存续权利金,应收存续权力金,了结权利金
|
|
double CopeWithExpirePremium, CopeWithLastPremium, ReceivablePremium, EndPremium = 0.0;
|
|
//未了结名义成交金额
|
|
var TotalNominal = 0.0;
|
|
//应付预付金,可提取预付金,Delta预付金,互换应付预付金
|
|
double PayableMargin = 0d, AdvisableMargin = 0d, DeltaMargin = 0d, SwapPayableMargin = 0.0;
|
|
//互换容忍预付金额 互换追保金额
|
|
double SwapUnPayableMargin = 0.0, SwapMargin = 0.0;
|
|
//双向预付金
|
|
var TwoSideMargin = 0.0;
|
|
var OtherSideMargin = 0.0;
|
|
var MySideMargin = 0.0;
|
|
//额外追保
|
|
var AdditionalMargin = 0.0;
|
|
//追保金额
|
|
var Margin = 0.0;
|
|
//昨日抵押品价值
|
|
var LastGuaranteesTotalAmount = 0.0;
|
|
//持仓名义本金规模
|
|
var AvailableStockEqvNotional = 0.0;
|
|
//潜在风险暴露
|
|
var PFE = 0d;
|
|
//互换存续预付金
|
|
var SwapMarinAmount = 0d;
|
|
//交易费用
|
|
var tradeFee= 0d;
|
|
//利息盈亏
|
|
var interestPnl= 0d;
|
|
//
|
|
ClientBalanceDaily clientbalancedaily = null;
|
|
#endregion
|
|
|
|
#region 客户授信 资信等级 客户昨日现金 clientbalancedaily对象初始化
|
|
//获取客户授信
|
|
var credits = creditList?.Where(t => t.ClientId == client.id);
|
|
if (credits.Any())
|
|
{
|
|
//设置的全部授信
|
|
lineOfCredit = credits.Sum(t => t.Credit ?? 0);
|
|
}
|
|
else
|
|
{
|
|
lineOfCredit = 0.0;
|
|
}
|
|
//资信等级授信额度
|
|
//creditRating = creditRatingList != null ? creditRatingList.FirstOrDefault(t => t.id == client.CreditRatingId) : null;
|
|
//if (creditRating != null)
|
|
//{
|
|
// lineOfCredit += creditRating.CreditLine ?? 0.0;
|
|
//}
|
|
|
|
clientbalancedaily = new ClientBalanceDaily()
|
|
{
|
|
ClientId = client.id,
|
|
ClientName = client.Name,
|
|
ClientNumber = client.Number,
|
|
BalanceDate = balanceDate
|
|
};
|
|
|
|
//获取用户最后结算日可用资金
|
|
var clientbalancedailyPre = preClientbalancedailys.FirstOrDefault(t => t.ClientId == client.id);
|
|
if (clientbalancedailyPre != null)
|
|
{
|
|
if (!string.IsNullOrEmpty(clientbalancedailyPre.FundJson))
|
|
{
|
|
clientbalancedailyPre.FundObject = JsonConvert.DeserializeObject<FundObject>(clientbalancedailyPre.FundJson);
|
|
|
|
if (clientbalancedailyPre.FundObject.InFund.Count() == 1 && clientbalancedailyPre.FundObject.InFund.ContainsKey(string.Empty) && currencyCodes.FirstOrDefault() != string.Empty)
|
|
{
|
|
if (string.IsNullOrEmpty(client.SettlementCurrency))
|
|
{
|
|
throw new Exception("客户:" + client.Name + "未配置结算币种");
|
|
}
|
|
clientbalancedailyPre.FundObject.InFund.Add(client.SettlementCurrency, clientbalancedailyPre.InFund ?? 0);
|
|
clientbalancedailyPre.FundObject.VmInFund.Add(client.SettlementCurrency, clientbalancedailyPre.vm_in_fund ?? 0);
|
|
clientbalancedailyPre.FundObject.InFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.InFundSum ?? 0);
|
|
clientbalancedailyPre.FundObject.VmInFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.vm_in_fund_sum ?? 0);
|
|
clientbalancedailyPre.FundObject.OutFund.Add(client.SettlementCurrency, clientbalancedailyPre.OutFund ?? 0);
|
|
clientbalancedailyPre.FundObject.VmOutFund.Add(client.SettlementCurrency, clientbalancedailyPre.vm_out_fund ?? 0);
|
|
clientbalancedailyPre.FundObject.OutFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.OutFundSum ?? 0);
|
|
clientbalancedailyPre.FundObject.VmOutFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.vm_out_fund_sum ?? 0);
|
|
clientbalancedailyPre.FundObject.NetFund.Add(client.SettlementCurrency, clientbalancedailyPre.NetFund ?? 0);
|
|
clientbalancedailyPre.FundObject.NetFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.NetFundSum ?? 0);
|
|
clientbalancedailyPre.FundObject.OtherFund.Add(client.SettlementCurrency, clientbalancedailyPre.OtherFund ?? 0);
|
|
clientbalancedailyPre.FundObject.OtherFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.OtherFundSum ?? 0);
|
|
clientbalancedailyPre.FundObject.TodayRemainFund.Add(client.SettlementCurrency, clientbalancedailyPre.ToDayRemainFund ?? 0);
|
|
}
|
|
|
|
foreach (var currencyCode in currencyCodes)
|
|
{
|
|
if (clientbalancedailyPre.FundObject.TodayRemainFund.ContainsKey(currencyCode))
|
|
{
|
|
fundObject.LastDayRemainFund[currencyCode] = clientbalancedailyPre.FundObject.TodayRemainFund[currencyCode];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
clientbalancedailyPre.FundObject = new FundObject();
|
|
if (currencyCodes.Count() == 1 && currencyCodes.FirstOrDefault() == string.Empty)
|
|
{
|
|
clientbalancedailyPre.FundObject.InFund.Add(string.Empty, clientbalancedailyPre.InFund ?? 0);
|
|
clientbalancedailyPre.FundObject.VmInFund.Add(string.Empty, clientbalancedailyPre.vm_in_fund ?? 0);
|
|
clientbalancedailyPre.FundObject.InFundSum.Add(string.Empty, clientbalancedailyPre.InFundSum ?? 0);
|
|
clientbalancedailyPre.FundObject.VmInFundSum.Add(string.Empty, clientbalancedailyPre.vm_in_fund_sum ?? 0);
|
|
clientbalancedailyPre.FundObject.OutFund.Add(string.Empty, clientbalancedailyPre.OutFund ?? 0);
|
|
clientbalancedailyPre.FundObject.VmOutFund.Add(string.Empty, clientbalancedailyPre.vm_out_fund ?? 0);
|
|
clientbalancedailyPre.FundObject.OutFundSum.Add(string.Empty, clientbalancedailyPre.OutFundSum ?? 0);
|
|
clientbalancedailyPre.FundObject.VmOutFundSum.Add(string.Empty, clientbalancedailyPre.vm_out_fund_sum ?? 0);
|
|
clientbalancedailyPre.FundObject.NetFund.Add(string.Empty, clientbalancedailyPre.NetFund ?? 0);
|
|
clientbalancedailyPre.FundObject.NetFundSum.Add(string.Empty, clientbalancedailyPre.NetFundSum ?? 0);
|
|
clientbalancedailyPre.FundObject.OtherFund.Add(string.Empty, clientbalancedailyPre.OtherFund ?? 0);
|
|
clientbalancedailyPre.FundObject.OtherFundSum.Add(string.Empty, clientbalancedailyPre.OtherFundSum ?? 0);
|
|
fundObject.LastDayRemainFund[string.Empty] = clientbalancedailyPre.ToDayRemainFund ?? 0;
|
|
}
|
|
else
|
|
{
|
|
clientbalancedailyPre.FundObject.InFund.Add(client.SettlementCurrency, clientbalancedailyPre.InFund ?? 0);
|
|
clientbalancedailyPre.FundObject.VmInFund.Add(client.SettlementCurrency, clientbalancedailyPre.vm_in_fund ?? 0);
|
|
clientbalancedailyPre.FundObject.InFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.InFundSum ?? 0);
|
|
clientbalancedailyPre.FundObject.VmInFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.vm_in_fund_sum ?? 0);
|
|
clientbalancedailyPre.FundObject.OutFund.Add(client.SettlementCurrency, clientbalancedailyPre.OutFund ?? 0);
|
|
clientbalancedailyPre.FundObject.VmOutFund.Add(client.SettlementCurrency, clientbalancedailyPre.vm_out_fund ?? 0);
|
|
clientbalancedailyPre.FundObject.OutFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.OutFundSum ?? 0);
|
|
clientbalancedailyPre.FundObject.VmOutFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.vm_out_fund_sum ?? 0);
|
|
clientbalancedailyPre.FundObject.NetFund.Add(client.SettlementCurrency, clientbalancedailyPre.NetFund ?? 0);
|
|
clientbalancedailyPre.FundObject.NetFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.NetFundSum ?? 0);
|
|
clientbalancedailyPre.FundObject.OtherFund.Add(client.SettlementCurrency, clientbalancedailyPre.OtherFund ?? 0);
|
|
clientbalancedailyPre.FundObject.OtherFundSum.Add(client.SettlementCurrency, clientbalancedailyPre.OtherFundSum ?? 0);
|
|
fundObject.LastDayRemainFund[client.SettlementCurrency] = clientbalancedailyPre.ToDayRemainFund ?? 0;
|
|
}
|
|
}
|
|
LastDayPositionPremiumNetCash = clientbalancedailyPre.PositionPremiumNetCash ?? 0.0;
|
|
LastGuaranteesTotalAmount = clientbalancedailyPre.TodayRemianFundProduct ?? 0.0;
|
|
}
|
|
|
|
AvailableStockEqvNotional =
|
|
credits.Sum(t => t.StockEqvNotional) -
|
|
trades.Where(O => ConsTrade.PositionTradeStatusList.Contains(O.TradeStatus) && O.ClientId == client.id)
|
|
.Sum(O => (double?)O.StockEqvNotionalReal) ?? 0.0;
|
|
#endregion
|
|
|
|
#region 出金 入金 当日可用资金计算
|
|
//获取客户所有出入金列表
|
|
clientEntryexits = entryexits.Where(t => t.ClientId == client.id).ToList();
|
|
var tradeCashGroupIds = clientEntryexits.Where(y => y.IsGroup == 1).Select(y => y.TradeCashId).ToArray();
|
|
var tradeCashGroups = DbContext.trade_cash.Where(x => tradeCashGroupIds.Contains(x.id));
|
|
if (clientEntryexits != null)
|
|
{
|
|
clientEntryexits.ForEach(clientEntryexit =>
|
|
{
|
|
if (null == clientEntryexit.Direction)
|
|
{
|
|
throw new Exception("客户:" + client.Name + "有一条出入记录存在出入金方向存在问题!");
|
|
}
|
|
|
|
if (currencyCodes.Count()==1)
|
|
{
|
|
clientEntryexit.CurrencyCode = "";
|
|
}
|
|
//之前单币种环境改为多币种环境后历史数据为""和配置的币种匹配不上
|
|
if (currencyCodes.Count() >= 1 && string.IsNullOrWhiteSpace(clientEntryexit.CurrencyCode))
|
|
{
|
|
if (currencyCodes.Contains("CNY"))
|
|
{
|
|
clientEntryexit.CurrencyCode = "CNY";
|
|
}
|
|
else if (currencyCodes.Contains("RMB"))
|
|
{
|
|
clientEntryexit.CurrencyCode = "RMB";
|
|
}
|
|
}
|
|
|
|
if (clientEntryexit.Direction.Equals("入金"))
|
|
{
|
|
// 根据 cash_type 判断资金进入哪个部分
|
|
if (clientEntryexit.cash_type == CashTypeEnum.初保账户.ToString())
|
|
{
|
|
AddToFund(fundObject.InFund, clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
// 更新 NetFund
|
|
AddToFund(fundObject.NetFund, clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
}
|
|
else
|
|
{
|
|
AddToFund(fundObject.VmInFund, clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
}
|
|
|
|
|
|
}
|
|
else if (clientEntryexit.Direction.Equals("出金"))
|
|
{
|
|
// 根据 cash_type 判断资金退出到哪个部分
|
|
if (clientEntryexit.cash_type == CashTypeEnum.初保账户.ToString())
|
|
{
|
|
AddToFund(fundObject.OutFund, clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
// 更新 NetFund
|
|
AddToFund(fundObject.NetFund, clientEntryexit.CurrencyCode, -(clientEntryexit.Money ?? 0));
|
|
}
|
|
else
|
|
{
|
|
AddToFund(fundObject.VmOutFund, clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
}
|
|
|
|
|
|
}
|
|
else if (clientEntryexit.Direction.Equals("其他收入"))
|
|
{
|
|
if (fundObject.InFundOther.ContainsKey(clientEntryexit.CurrencyCode))
|
|
{
|
|
fundObject.InFundOther[clientEntryexit.CurrencyCode] += clientEntryexit.Money ?? 0;
|
|
}
|
|
else
|
|
{
|
|
fundObject.InFundOther.Add(clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
}
|
|
|
|
if (fundObject.OtherFund.ContainsKey(clientEntryexit.CurrencyCode))
|
|
{
|
|
fundObject.OtherFund[clientEntryexit.CurrencyCode] += clientEntryexit.Money ?? 0;
|
|
}
|
|
else
|
|
{
|
|
fundObject.OtherFund.Add(clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
}
|
|
}
|
|
else if (clientEntryexit.Direction.Equals("其他支出"))
|
|
{
|
|
if (fundObject.OutFundOther.ContainsKey(clientEntryexit.CurrencyCode))
|
|
{
|
|
fundObject.OutFundOther[clientEntryexit.CurrencyCode] += clientEntryexit.Money ?? 0;
|
|
}
|
|
else
|
|
{
|
|
fundObject.OutFundOther.Add(clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
}
|
|
|
|
if (fundObject.OtherFund.ContainsKey(clientEntryexit.CurrencyCode))
|
|
{
|
|
fundObject.OtherFund[clientEntryexit.CurrencyCode] += clientEntryexit.Money ?? 0;
|
|
}
|
|
else
|
|
{
|
|
fundObject.OtherFund.Add(clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
}
|
|
}
|
|
else if (clientEntryexit.Direction.Equals("划转")) {
|
|
if (clientEntryexit.TransferOutAccount == "初保账户")
|
|
{
|
|
AddToFund(fundObject.InFund, clientEntryexit.CurrencyCode, -clientEntryexit.Money ?? 0);
|
|
// 更新 NetFund
|
|
AddToFund(fundObject.NetFund, clientEntryexit.CurrencyCode, -clientEntryexit.Money ?? 0);
|
|
if (clientEntryexit.TransferInAccount == "追保账户")
|
|
{
|
|
AddToFund(fundObject.VmInFund, clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
}
|
|
else
|
|
{
|
|
WinLoss += clientEntryexit.Money ?? 0;
|
|
CurrChangeAmount += clientEntryexit.Money ?? 0;
|
|
}
|
|
}
|
|
else if (clientEntryexit.TransferOutAccount == "追保账户")
|
|
{
|
|
AddToFund(fundObject.VmInFund, clientEntryexit.CurrencyCode, -clientEntryexit.Money ?? 0);
|
|
if (clientEntryexit.TransferInAccount == "初保账户")
|
|
{
|
|
AddToFund(fundObject.InFund, clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
// 更新 NetFund
|
|
AddToFund(fundObject.NetFund, clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
}
|
|
else
|
|
{
|
|
WinLoss += clientEntryexit.Money ?? 0;
|
|
CurrChangeAmount += clientEntryexit.Money ?? 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WinLoss -= clientEntryexit.Money ?? 0;
|
|
CurrChangeAmount -= clientEntryexit.Money ?? 0;
|
|
if (clientEntryexit.TransferInAccount == "初保账户")
|
|
{
|
|
AddToFund(fundObject.InFund, clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
// 更新 NetFund
|
|
AddToFund(fundObject.NetFund, clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
}
|
|
else
|
|
{
|
|
AddToFund(fundObject.VmInFund, clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ClientCashInCashOut.系统操作_期权费.Equals(clientEntryexit.Action))
|
|
{
|
|
//CurrPnl += clientEntryexit.Money ?? 0.0;
|
|
CurrChangeAmount += clientEntryexit.Money ?? 0.0;
|
|
OptionPremium += clientEntryexit.Money ?? 0.0;
|
|
}
|
|
//黑箱了结资金按照主交易来进行归类
|
|
else if ((ClientCashInCashOut.系统操作_行权费.Equals(clientEntryexit.Action) || ClientCashInCashOut.系统操作_平仓费.Equals(clientEntryexit.Action)) && clientEntryexit.IsGroup != 2)
|
|
{
|
|
var money = clientEntryexit.Money ?? 0;
|
|
//如果是黑箱主交易了结资金(主交易Money没有赋值),取对应tradeCash数据
|
|
if (money == 0 && clientEntryexit.IsGroup == 1)
|
|
{
|
|
var tradeCash = tradeCashGroups.FirstOrDefault(x => x.id == clientEntryexit.TradeCashId);
|
|
money = -(tradeCash?.Amount ?? 0);
|
|
}
|
|
|
|
//CurrPnl += money;
|
|
CurrChangeAmount += money;
|
|
SettlementBalance += money;
|
|
if (ClientCashInCashOut.系统操作_平仓费.Equals(clientEntryexit.Action))
|
|
{
|
|
UnwindBalance += money;
|
|
}
|
|
else
|
|
{
|
|
ExerciseBalance += money;
|
|
}
|
|
}
|
|
//黑箱了结资金按照主交易来进行归类
|
|
else if (ClientCashInCashOut.系统操作_票息.Equals(clientEntryexit.Action) && clientEntryexit.IsGroup != 2)
|
|
{
|
|
var money = clientEntryexit.Money ?? 0;
|
|
//如果是黑箱主交易了结资金(主交易Money没有赋值),取对应tradeCash数据
|
|
if (money == 0 && clientEntryexit.IsGroup == 1)
|
|
{
|
|
var tradeCash = tradeCashGroups.FirstOrDefault(x => x.id == clientEntryexit.TradeCashId);
|
|
money = -(tradeCash?.Amount ?? 0);
|
|
}
|
|
|
|
CurrChangeAmount += money;
|
|
Coupon += money;
|
|
}
|
|
}
|
|
if (ClientCashInCashOut.已确认.Equals(clientEntryexit.State))
|
|
{
|
|
clientEntryexit.SettleDate = balanceDate;
|
|
clientEntryexit.State = ClientCashInCashOut.已结算;
|
|
}
|
|
});
|
|
}
|
|
|
|
clientEntryexits_swap = entryexits_swap.Where(t => t.ClientId == client.id).ToList();
|
|
if (clientEntryexits_swap != null)
|
|
{
|
|
clientEntryexits_swap.ForEach(clientEntryexit =>
|
|
{
|
|
if (null == clientEntryexit.Direction)
|
|
{
|
|
throw new Exception("客户:" + client.Name + "有一条出入记录存在出入金方向存在问题!");
|
|
}
|
|
|
|
if (currencyCodes.Count() == 1)
|
|
{
|
|
clientEntryexit.CurrencyCode = "";
|
|
}
|
|
//之前单币种环境改为多币种环境后历史数据为""和配置的币种匹配不上
|
|
if (currencyCodes.Count() >= 1 && string.IsNullOrWhiteSpace(clientEntryexit.CurrencyCode))
|
|
{
|
|
if (currencyCodes.Contains("CNY"))
|
|
{
|
|
clientEntryexit.CurrencyCode = "CNY";
|
|
}
|
|
else if (currencyCodes.Contains("RMB"))
|
|
{
|
|
clientEntryexit.CurrencyCode = "RMB";
|
|
}
|
|
}
|
|
|
|
if (ClientCashInCashOut.系统操作_期权费.Equals(clientEntryexit.Action) || ClientCashInCashOut.系统操作_应付预付金.Equals(clientEntryexit.Action) || ClientCashInCashOut.系统操作_预付金返息.Equals(clientEntryexit.Action))
|
|
{
|
|
CurrChangeAmount += clientEntryexit.Money ?? 0.0;
|
|
OptionPremiumSwap += clientEntryexit.Money ?? 0.0;
|
|
}
|
|
else if (ClientCashInCashOut.系统操作_平仓费.Equals(clientEntryexit.Action))
|
|
{
|
|
CurrChangeAmount += clientEntryexit.Money ?? 0.0;
|
|
SwapBalance += clientEntryexit.Money ?? 0.0;
|
|
WinLoss += clientEntryexit.Money ?? 0.0;
|
|
}
|
|
else if (ClientCashInCashOut.系统操作_互换.Equals(clientEntryexit.Action))
|
|
{
|
|
CurrChangeAmount += clientEntryexit.Money ?? 0.0;
|
|
SwapBalance += clientEntryexit.Money ?? 0.0;
|
|
WinLoss += clientEntryexit.Money ?? 0.0;
|
|
}
|
|
|
|
if (ClientCashInCashOut.已确认.Equals(clientEntryexit.State))
|
|
{
|
|
clientEntryexit.SettleDate = balanceDate;
|
|
clientEntryexit.State = ClientCashInCashOut.已结算;
|
|
}
|
|
|
|
});
|
|
}
|
|
foreach (var item in currencyCodes)
|
|
{
|
|
if (fundObject.TodayRemainFund.ContainsKey(item))
|
|
{
|
|
fundObject.TodayRemainFund[item] = (fundObject.LastDayRemainFund.ContainsKey(item) ? fundObject.LastDayRemainFund[item] : 0) + (fundObject.NetFund.ContainsKey(item) ? fundObject.NetFund[item] : 0) + (fundObject.VmInFund.ContainsKey(item) ? fundObject.VmInFund[item] : 0) - (fundObject.VmOutFund.ContainsKey(item) ? fundObject.VmOutFund[item] : 0);
|
|
}
|
|
else
|
|
{
|
|
fundObject.TodayRemainFund.Add(item, (fundObject.LastDayRemainFund.ContainsKey(item) ? fundObject.LastDayRemainFund[item] : 0) + (fundObject.NetFund.ContainsKey(item) ? fundObject.NetFund[item] : 0) + (fundObject.VmInFund.ContainsKey(item) ? fundObject.VmInFund[item] : 0) - (fundObject.VmOutFund.ContainsKey(item) ? fundObject.VmOutFund[item] : 0));
|
|
}
|
|
|
|
if ((client.SettlementCurrency ?? "CNY") == item || item == "")
|
|
{
|
|
fundObject.TodayRemainFund[item] += CurrChangeAmount;
|
|
}
|
|
|
|
var rateObj = new eod_currency_rate
|
|
{
|
|
Rate = 1,
|
|
SellRate = 1,
|
|
BuyRate = 1,
|
|
ForeignCurrency = item,
|
|
LocalCurrency = client.SettlementCurrency,
|
|
};
|
|
|
|
if (PS.Config.ErpElement.SupportMultiCurrency)
|
|
{
|
|
currencyProvider.TryGetCurrencyRate(item, client.SettlementCurrency, out rateObj);
|
|
if (rateObj == null)
|
|
{
|
|
_context.RaiseError("结算客户资金", $"[{client.Name}]找不到汇率:{item}{client.SettlementCurrency}");
|
|
}
|
|
}
|
|
|
|
CurrAvailAmount += fundObject.TodayRemainFund[item] * rateObj.Rate;
|
|
LastDayAvailAmount += fundObject.LastDayRemainFund[item] * rateObj.Rate;
|
|
inFund += fundObject.InFund[item] * rateObj.Rate;
|
|
vmInFund += fundObject.VmInFund[item] * rateObj.Rate;
|
|
outFund += fundObject.OutFund[item] * rateObj.Rate;
|
|
vmOutFund += fundObject.VmOutFund[item] * rateObj.Rate;
|
|
NetFund += fundObject.NetFund[item] * rateObj.Rate;
|
|
inFundOther += fundObject.InFundOther[item] * rateObj.Rate;
|
|
outFundOther += fundObject.OutFundOther[item] * rateObj.Rate;
|
|
OtherFund += fundObject.OtherFund[item] * rateObj.Rate;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 抵押品
|
|
//抵押品资金价值
|
|
var tempClientProductList = clientProductList.Where(a => a.product.ClientId == client.id).ToList();
|
|
var GuaranteesTotalAmount = 0.0;
|
|
if (tempClientProductList.Any())
|
|
{
|
|
tempClientProductList.ForEach(t =>
|
|
{
|
|
if (t.um == null)
|
|
{
|
|
throw new Exception($"抵押品,出入金单号[{t.product.Number}]标的ID[{t.product.UnderlyingId}]未找到对应标的基本信息!");
|
|
}
|
|
if (t.variety == null)
|
|
{
|
|
throw new Exception($"抵押品,出入金单号[{t.product.Number}]品种ID[{t.product.VarietyId}]未找到对应品种基本信息!");
|
|
}
|
|
if (dayeods.TryGetPrice(t.um.UnderlyingCode, SettlementTypeEnum.ClosePrice, out var price))
|
|
{
|
|
GuaranteesTotalAmount += (t.product.ProductAmount ?? 0) * (t.product.Rate ?? 0.0) * price;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception($"抵押品,出入金单号[{t.product.Number}]标的[{t.um.UnderlyingCode}]在{balanceDate:yyyy-MM-dd}收盘价不存在!");
|
|
}
|
|
});
|
|
}
|
|
#endregion
|
|
|
|
#region 当日冻结权利金 当日应收权利金 潜在行权盈余 持仓市值 持仓Pnl
|
|
//持仓交易
|
|
var positionTrades = trades.Where(t => t.TradeStatus.Equals(ConsTrade.确认成交) && t.ClientId == client.id && t.TradeType != "收益互换").ToList();
|
|
var clientEodSwaps = eodSwaps.Where(t => t.ClientId == client.id && t.ValueDate == balanceDate).ToList();
|
|
var clientEodSwapPosis= eodSwapPosis.Where(t => t.ClientId == client.id && t.ValueDate == balanceDate).ToList();
|
|
//var tradeIds = clientTrades.Where(t => t.ClientId == client.id).Select(t => t.id).ToList();
|
|
//获取所有持仓交易ids
|
|
var positionTradeIds = positionTrades == null || positionTrades.Count == 0 ? new List<int>() : positionTrades.Select(t => t.id).ToList();
|
|
//获取客户冻结资金
|
|
var clientFrozenFund = clientFrozenFunds[client.id];
|
|
//当前持仓并且未到支付日的卖出交易(客户为买入,渠道为卖出)则为冻结的权利金
|
|
//FrozenPremium = positionTrade == null || positionTrade.Count == 0 ? 0.0 : (positionTrade.Where(t => t.PremiumPayDate > balanceDate && t.BuySell == "卖出").Sum(t => t.TradePrice ?? 0.0));
|
|
FrozenPremium = clientFrozenFund.FrozenPayableOptionMoney;
|
|
//应收存续权利金
|
|
//ReceivablePremium = positionTrade == null || positionTrade.Count == 0 ? 0.0 : (positionTrade.Where(t => t.PremiumPayDate > balanceDate && t.BuySell == "买入").Sum(t => t.TradePrice ?? 0.0));
|
|
ReceivablePremium = clientFrozenFund.FrozenReceivableOptionMoney;
|
|
//冻结预付金(绝对值)
|
|
var FrozenMarginMoney = clientFrozenFund.FrozenMarginMoney;
|
|
//冻结资金=冻结权利金+到期停牌股票名义金额×6.5%*30/365(默认收取一个月资金利息,多追少补) //todo 此处需要增加股票停复牌信息,同时检查到期交易不能默认执行到期
|
|
//FrozenBalance = FrozenPremium;
|
|
//应付到期权利金
|
|
CopeWithExpirePremium = OptionPremium + OptionPremiumSwap;
|
|
//应付存续权利金
|
|
CopeWithLastPremium = FrozenPremium;
|
|
|
|
//未了结名义成交金额 todo //持仓的买入 以及卖出是否都统计
|
|
TotalNominal = positionTrades == null || positionTrades.Count == 0 ? 0 : positionTrades.Sum(t => t.UnderlyingInstrumentType == "Stock" ? t.StockEqvNotional : (t.Notional * (t.SpotPrice ?? 0.0)));
|
|
TotalNominal += Convert.ToDouble(clientEodSwaps.Sum(x => x.NotionalValue));
|
|
//计算潜在客户行权盈余 max{名义成交金额*(标的当日结算价-标的初始价格)/行权价格, 0}
|
|
foreach (var t in positionTrades)
|
|
{
|
|
if (t.TradeType != "现金流交易" && t.TradeType != "自定义交易")
|
|
{
|
|
var spotPrice = t.SpotPrice ?? t.SpotPrice ?? 0.0;
|
|
var nominal = t.UnderlyingInstrumentType == "Stock" ? t.StockEqvNotional : (t.Notional * spotPrice);
|
|
if (!dayeods.TryGetPrice(t.UnderlyingCode, t.SettlementType, out var nowPrice))
|
|
{
|
|
throw new Exception($"找不到收盘价({t.UnderlyingCode}),无法结算!");
|
|
}
|
|
var Strike = t.IsMoneynessOptionData ? ((t.Strike ?? 0) * t.SpotPrice ?? 0) : t.Strike ?? 0;
|
|
//如果期初价格未0则已份额计算潜在行权盈余
|
|
if (spotPrice == 0)
|
|
{
|
|
PotentialSurpluses += Math.Max(Strike == 0 ? 0 : (t.Notional * (nowPrice - Strike) * ("Call".Equals(t.CallPut) ? 1 : -1)), 0) * TradeCalcHelper.GetSign(t.BuySell) * -1;
|
|
}
|
|
else
|
|
{
|
|
PotentialSurpluses += Math.Max(Strike == 0 ? 0 : (nominal * (nowPrice - Strike) / spotPrice * ("Call".Equals(t.CallPut) ? 1 : -1)), 0) * TradeCalcHelper.GetSign(t.BuySell) * -1;
|
|
}
|
|
}
|
|
if (t.BuySell == "买入" && t.TradeType != "现金流交易")
|
|
{
|
|
var um = underlyDataSource.GetData(t.UnderlyingCode);
|
|
//deltaS/S
|
|
var rate = um.DeltaS_S;
|
|
if (!rate.IsNormalize())
|
|
{
|
|
var variety = varietyDataSource.GetData(um.CommodityCode);
|
|
if (ConsGlobal.InstrumentType.IsStockIndex(um.UnderlyingInstrumentType) || ConsGlobal.InstrumentType.IsStockIF(um.UnderlyingInstrumentType))
|
|
{
|
|
rate = variety.UpLimitValue;
|
|
}
|
|
else
|
|
{
|
|
rate = variety.Margin ?? 0;
|
|
}
|
|
}
|
|
var risk = eodRiskList.Where(O => O.TradeId == t.id).FirstOrDefault();
|
|
var pfe1 = t.StockEqvNotional == 0 ? (t.Notional * t.SpotPrice ?? 0) : t.StockEqvNotional;
|
|
var pfe2 = Math.Abs(risk.DeltaCash) * rate.Value + 0.5 * 100 * rate.Value * rate.Value * Math.Abs(Math.Min(risk.GammaCash, 0));
|
|
PFE += Math.Min(pfe1, pfe2);
|
|
}
|
|
}
|
|
|
|
|
|
PositionPremiumNetCash = positionTrades.Sum(t => -TradeCalcHelper.GetSign(t.BuySell) * ((t.TradePrice ?? 0) * (t.OriginalNotional != null && t.OriginalNotional != 0 ? t.Notional / t.OriginalNotional.Value : 1)));
|
|
|
|
//现金流交易没有份额的概念
|
|
SellTradePrice = positionTrades.Where(x => x.BuySell == "买入").Sum(
|
|
t => t.OriginalNotional.HasValue && t.OriginalNotional > 0 ? (t.TradePrice ?? 0) * t.Notional / t.OriginalNotional.Value : (t.TradePrice ?? 0));
|
|
|
|
//客户持仓交易预付金总和,客户买入为正,客户卖出为负
|
|
PrepaymentAmount = positionTrades.Sum(x => x.StockEqvNotional * (x.trade_snowball?.PrepaymentRatio ?? 0) * (x.BuySell == "卖出" ? 1 : -1));
|
|
|
|
var todayFinishedTrades = DbContext.trade.Where(t => keys.Contains(t.id) && t.IsGroup != 1 && t.ClientId == client.id)
|
|
.Select(x => new { x.id, x.TradeType, x.BuySell, x.TradePrice }).ToList();
|
|
var clientSwapIds = clientEodSwaps.Select(s => s.SwapTradeId).Distinct();
|
|
var todaySwapFinishedTrades = todaySwapTrades.Where(t => clientSwapIds.Contains(t.id) && ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus));
|
|
var todayFinishedTradeCash = from tc in finishedTradeCash
|
|
join td in DbContext.trade on tc.TradeId equals td.id
|
|
where td.IsGroup != 1 && td.ClientId == client.id
|
|
group tc by td.id into g
|
|
select new
|
|
{
|
|
tradeId = g.Key,
|
|
amountSum = g.Sum(n => n.Amount)
|
|
};
|
|
var todaySwapFinishedTradeIds = todaySwapFinishedTrades.Select(s => s.id).ToList();
|
|
var todaySwapFinishedCash = clientEntryexits_swap.Where(x => todaySwapFinishedTradeIds.Contains(x.TradeId ?? 0)).ToList();
|
|
var list = todayFinishedTradeCash.ToList();
|
|
//了结开仓费用
|
|
EndPremium = todayFinishedTrades.Sum(t => t.TradeType != "远期" ? -TradeCalcHelper.GetSign(t.BuySell) * (t.TradePrice ?? 0) * finishedTradeNotionalPercentDic[t.id] : (t.TradePrice ?? 0) * finishedTradeNotionalPercentDic[t.id]) * -1;
|
|
EndPremium = EndPremium + todaySwapFinishedCash.Sum(s => s.Money ?? 0);
|
|
var eodPnlSum = new EodPnlGridSum();
|
|
#region 收益互换V2
|
|
var clientEodSwapsLast = clientEodSwaps.ToList();
|
|
var clientEodSwapPositionLast = clientEodSwapPosis.ToList();
|
|
foreach (var item in clientEodSwapsLast)
|
|
{
|
|
var lastEodSwap = eodSwaps.FirstOrDefault(t => t.SwapTradeId == item.SwapTradeId && t.ValueDate == preBalanceDate);
|
|
item.PostionValue=Math.Round(item.PostionValue, ConsGlobal.MoneyRound,MidpointRounding.AwayFromZero);
|
|
PotentialSurpluses += Convert.ToDouble(item.PostionValue) * (-1);
|
|
// WinLoss += Convert.ToDouble(item.TdRealizedPnL) * (-1);
|
|
var lastPv = lastEodSwap != null ? Convert.ToDouble(lastEodSwap.PostionValue) * (-1) : 0;
|
|
eodPnlSum.LastPvSum = eodPnlSum.LastPvSum.HasValue ? eodPnlSum.LastPvSum + lastPv : lastPv;
|
|
var pnl = item.PostionValue;
|
|
eodPnlSum.PvSum = Convert.ToDouble(item.PostionValue) * (-1);
|
|
eodPnlSum.SellPvSum = Convert.ToDouble(item.MarketValueShort) * (-1);
|
|
eodPnlSum.RoundedPvSum = Math.Round(Convert.ToDouble(item.PostionValue), 2) * (-1);
|
|
eodPnlSum.DailyPnLSum = Convert.ToDouble(item.TdRealizedPnL) * (-1);
|
|
PositionPnl += Convert.ToDouble(pnl) * (-1);
|
|
RoundedPositionPnl += Math.Round(Convert.ToDouble(pnl), 2) * (-1);
|
|
TotalPnl += Convert.ToDouble(item.RealizedPnL) * (-1);
|
|
ClientSellPositionPnl += Math.Max(-Convert.ToDouble(item.MarketValueShort), 0);
|
|
var lastPnl = lastEodSwap != null ? lastEodSwap.PostionValue : 0;
|
|
DailyPnl += Convert.ToDouble(pnl - lastPnl + item.TdRealizedPnL) * (-1);
|
|
//PayableMargin += Convert.ToDouble(item.InitMarginLoss + item.InitMarginGain+ item.PostionMarginLoss + item.PostionMarginGain);
|
|
}
|
|
var clientEventFlowList = clientEventFlows.Where(x=>x.ClientId== client.id);
|
|
foreach (var item in clientEventFlowList.GroupBy(x => x.SwapTradeId))
|
|
{
|
|
var eventPosis = item.Where(t => t.PayDirection > 0).ToList();
|
|
var eventInterests = item.Where(t => t.PayDirection == 0).ToList();
|
|
interestPnl += Convert.ToDouble(eventInterests.Sum(s => s.InterestClosePnL)) * (-1);
|
|
|
|
tradeFee += Convert.ToDouble(eventPosis.Sum(s => s.TradingFee + s.TradingFeePending)) * (-1);
|
|
}
|
|
var clientmarignQuery = marignQuery.Where(x => x.ClientId == client.id&&x.StructureType!="多空组合");
|
|
SwapMarinAmount = Convert.ToDouble(clientmarignQuery.Sum(s => s.marin));
|
|
#endregion
|
|
//合计持仓浮动盈亏
|
|
CurrPnl = eodPnlSum.DailyPnLSum ?? 0;
|
|
|
|
clientPv = eodPnlSum.PvSum;
|
|
roundedClientPv = eodPnlSum.RoundedPvSum;
|
|
clientSellPv = eodPnlSum.SellPvSum;
|
|
#endregion
|
|
|
|
#region 应缴预付金 预付金余额 可取预付金 追保额度
|
|
//获取tradespan 追保金额 = (当日资金余额 - 维持预付金) + 授信额度
|
|
var clientSpan = clientSpanList == null || clientSpanList.Count == 0 ? null : clientSpanList.FirstOrDefault(t => t.ClientId == client.id && t.ValueDate == balanceDate && t.SpanType == ClientSpan.SpanType_Eod);
|
|
if (clientSpan != null)
|
|
{
|
|
PayableMargin += clientSpan.WorstCastClientPayable ?? 0d;
|
|
DeltaMargin = clientSpan.DeltaMargin ?? 0d;
|
|
SwapPayableMargin = clientSpan.SwapWorstCastClientPayable ?? 0d;
|
|
SwapUnPayableMargin = clientSpan.SwapUnMargin ?? 0d;
|
|
TwoSideMargin = clientSpan.TwoSideMargin ?? 0d;
|
|
OtherSideMargin = clientSpan.OtherSideMargin ?? 0d;
|
|
MySideMargin = clientSpan.MySideMargin ?? 0d;
|
|
AdditionalMargin = (clientSpan.AdditionalWorstCastClientPayable) ?? 0d;
|
|
}
|
|
//var todaySwapMargins = clientEntryexits_swap.Where(x=>x.Action== ClientCashInCashOut.系统操作_应付预付金).ToList().Sum(s=>s.Money)??0;
|
|
//var swapFrozenBalance = entryexits_swapFuture.Where(x => x.Action == ClientCashInCashOut.系统操作_应付预付金 || x.Action == ClientCashInCashOut.系统操作_期权费).ToList().Sum(s => s.Money) ?? 0;
|
|
//PayableMargin += todaySwapMargins;
|
|
//SwapPayableMargin += todaySwapMargins;
|
|
//冻结资金
|
|
//FrozenMarginMoney += swapFrozenBalance;
|
|
FrozenBalance = ReceivablePremium - FrozenPremium - (clientFrozenFund.OutFunds + clientFrozenFund.RedeemFunds) - FrozenMarginMoney;
|
|
|
|
//预付金余额
|
|
MarginBalance = CurrAvailAmount + GuaranteesTotalAmount + FrozenBalance;
|
|
|
|
if (PS.Config.Is申万)
|
|
{
|
|
//期权空头浮动盈亏
|
|
MarginBalance -= ClientSellPositionPnl;
|
|
|
|
//空头持仓市值
|
|
MarginBalance -= Math.Abs(clientSellPv ?? 0);
|
|
}
|
|
else
|
|
{
|
|
//判断潜在行权盈余是否计入预付金余额
|
|
if ((valuedateBLL.SystemDate.IsPotentialSurplusUseMargin ?? 0) == 1)
|
|
{
|
|
MarginBalance += PotentialSurpluses;
|
|
}
|
|
}
|
|
//可取预付金为预付金余额 - 应缴预付金(上浮2%) 20220207新增减去互换预付金容忍额
|
|
AdvisableMargin = Math.Max(MarginBalance + (PayableMargin - SwapUnPayableMargin) * (double)(marginMaxRatio / marginRatio), 0);
|
|
|
|
//计算追保金额 维持预付金带方向 所以计算追保金额是 为相加
|
|
var IsTradeCredit = (client.IsTradeCredit ?? 0) == 1;
|
|
|
|
// 场外预付金资金占用后剩余资金
|
|
var marginBalanceSurplus = 0d;
|
|
//是否期权费授信
|
|
if (IsTradeCredit)
|
|
{
|
|
//授信是否可用于互换
|
|
if (client.creditCanApplySwap)
|
|
{
|
|
//期权费授信可以支付权利金 则预付金余额未0时 资金从
|
|
Margin = Math.Min(MarginBalance + lineOfCredit + (PayableMargin - SwapUnPayableMargin), 0);
|
|
}
|
|
else
|
|
{
|
|
//互换最大可用资金
|
|
marginBalanceSurplus = Math.Max(Math.Min(Math.Max(MarginBalance - OptionPremiumSwap + lineOfCredit + (PayableMargin - SwapPayableMargin), 0), Math.Max(MarginBalance - OptionPremiumSwap, 0)), 0);
|
|
|
|
//收益互换追保金额 剩余可支付互换资金 - (互换占用预付金 - 互换容忍预付金额度)
|
|
SwapMargin = Math.Min(marginBalanceSurplus + OptionPremiumSwap + (SwapPayableMargin - SwapUnPayableMargin), 0);
|
|
|
|
//计算期权追保
|
|
Margin = Math.Min(MarginBalance - OptionPremiumSwap + lineOfCredit + (PayableMargin - SwapPayableMargin), 0) + SwapMargin;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//授信是否可用于互换
|
|
if (client.creditCanApplySwap)
|
|
{
|
|
//期权费授信不可以支付权力金时
|
|
Margin = Math.Min(Math.Max(MarginBalance, 0) + lineOfCredit + (PayableMargin - SwapUnPayableMargin), 0) + Math.Min(MarginBalance, 0);
|
|
}
|
|
else
|
|
{
|
|
//互换最大可用资金
|
|
marginBalanceSurplus = Math.Max(Math.Min(Math.Max(Math.Max(MarginBalance - OptionPremiumSwap, 0) + lineOfCredit + (PayableMargin - SwapUnPayableMargin), 0), Math.Max(MarginBalance - OptionPremiumSwap, 0)), 0);
|
|
|
|
//收益互换追保金额 剩余可支付互换资金 - (互换占用预付金 - 互换容忍预付金额度)
|
|
SwapMargin = Math.Min(marginBalanceSurplus + OptionPremiumSwap + (SwapPayableMargin - SwapUnPayableMargin), 0) + Math.Min(marginBalanceSurplus + OptionPremiumSwap, 0);
|
|
|
|
//计算期权追保
|
|
Margin = Math.Min(Math.Max(MarginBalance - OptionPremiumSwap, 0) + lineOfCredit + (PayableMargin - SwapUnPayableMargin), 0) + Math.Min(MarginBalance - OptionPremiumSwap, 0) + SwapMargin;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
|
|
#region ClientBalacedaily ClientBalace对象赋值
|
|
if (client.BoundSide == BoundSideEnum.南向 && clientSpan != null)
|
|
{
|
|
var credit = DbContext.credit.FirstOrDefault(x => x.CreditStartDate <= balanceDate && x.CreditDeadLine >= balanceDate && x.ClientId == client.id && x.ProcessStatus == "已审批");
|
|
var PFECredit = credit != null ? credit.PFECredit : 0;
|
|
clientSpan.PFEUsed = Math.Max(Math.Min((clientSpan.PFEUsed ?? 0) - CurrAvailAmount, PFECredit ?? 0), 0);
|
|
}
|
|
clientbalancedaily.ToDayRemainFund = CurrAvailAmount;
|
|
clientbalancedaily.LastDayRemainFund = LastDayAvailAmount;
|
|
clientbalancedaily.PositionPremiumNetCash = PositionPremiumNetCash;
|
|
clientbalancedaily.SellTradePrice = SellTradePrice;
|
|
clientbalancedaily.LastDayPositionPremiumNetCash = LastDayPositionPremiumNetCash;
|
|
clientbalancedaily.WinLoss = WinLoss;
|
|
clientbalancedaily.EndPremium = EndPremium;
|
|
clientbalancedaily.InFundOther = inFundOther;
|
|
clientbalancedaily.OutFundOther = outFundOther;
|
|
clientbalancedaily.BalanceDate = balanceDate;
|
|
clientbalancedaily.DayGainLoss = CurrPnl;
|
|
clientbalancedaily.PositionPnl = PositionPnl;
|
|
clientbalancedaily.RoundedPositionPnl = RoundedPositionPnl;
|
|
clientbalancedaily.ClientSellPositionPnl = ClientSellPositionPnl;
|
|
clientbalancedaily.TotalPnl = TotalPnl;
|
|
clientbalancedaily.DailyPnl = DailyPnl;
|
|
clientbalancedaily.OptionPremium = OptionPremium;
|
|
clientbalancedaily.OptionPremiumSwap = OptionPremiumSwap;
|
|
clientbalancedaily.SettlementBalance = SettlementBalance;
|
|
clientbalancedaily.UnwindBalance = UnwindBalance;
|
|
clientbalancedaily.Coupon = Coupon;
|
|
clientbalancedaily.SwapBalance = SwapBalance;
|
|
clientbalancedaily.ExerciseBalance = ExerciseBalance;
|
|
clientbalancedaily.AdvisableMargin = AdvisableMargin;
|
|
clientbalancedaily.TotalNominal = TotalNominal;
|
|
clientbalancedaily.trade_fee = tradeFee;
|
|
clientbalancedaily.interest_pnl = interestPnl;
|
|
clientbalancedaily.Pv = clientPv ?? 0;
|
|
clientbalancedaily.RoundedPv = roundedClientPv ?? 0;
|
|
clientbalancedaily.SellPv = clientSellPv ?? 0;
|
|
clientbalancedaily.PrepaymentAmount = PrepaymentAmount;
|
|
clientbalancedaily.CopeWithLastPremium = CopeWithLastPremium;
|
|
clientbalancedaily.CopeWithExpirePremium = CopeWithExpirePremium;
|
|
clientbalancedaily.FrozenBalance = FrozenBalance;
|
|
clientbalancedaily.FrozenPremium = FrozenPremium;
|
|
clientbalancedaily.FrozenOutFund = clientFrozenFund.OutFunds;
|
|
clientbalancedaily.FrozenRedeemFunds = clientFrozenFund.RedeemFunds;
|
|
clientbalancedaily.MarginBalance = MarginBalance;
|
|
clientbalancedaily.InFund = inFund;
|
|
clientbalancedaily.vm_in_fund = vmInFund;
|
|
clientbalancedaily.OutFund = outFund;
|
|
clientbalancedaily.vm_out_fund = vmOutFund;
|
|
clientbalancedaily.NetFund = NetFund;
|
|
clientbalancedaily.OtherFund = OtherFund;
|
|
clientbalancedaily.IsTradeCredit = IsTradeCredit;
|
|
clientbalancedaily.Credit = lineOfCredit;
|
|
clientbalancedaily.CashDeposit = PayableMargin;
|
|
clientbalancedaily.PayableMargin = PayableMargin;
|
|
clientbalancedaily.DeltaMargin = DeltaMargin;
|
|
clientbalancedaily.SwapPayableMargin = SwapPayableMargin;
|
|
clientbalancedaily.SwapUnPayableMargin = SwapUnPayableMargin;
|
|
clientbalancedaily.TwoSideMargin = TwoSideMargin;
|
|
clientbalancedaily.OtherSideMargin = OtherSideMargin;
|
|
clientbalancedaily.MySideMargin = MySideMargin;
|
|
clientbalancedaily.IsPayableMarginManual = clientSpan?.ModifiedFlag;
|
|
clientbalancedaily.FrozenMarginMoney = FrozenMarginMoney;
|
|
clientbalancedaily.Margin = Margin;
|
|
clientbalancedaily.TodayRemianFundProduct = GuaranteesTotalAmount;
|
|
clientbalancedaily.CashInCashOutProductChange = GuaranteesTotalAmount - LastGuaranteesTotalAmount;
|
|
clientbalancedaily.PotentialSurpluses = PotentialSurpluses;
|
|
clientbalancedaily.OptId = UserId;
|
|
clientbalancedaily.OptName = UserName;
|
|
clientbalancedaily.OptDate = DateTime.Now;
|
|
clientbalancedaily.AdditionalMargin = AdditionalMargin;
|
|
clientbalancedaily.AvailableStockEqvNotional = AvailableStockEqvNotional;
|
|
clientbalancedaily.PFE = PFE;
|
|
clientbalancedaily.EAD = Math.Max(PFE - (clientbalancedaily.Pv ?? 0) - (clientbalancedaily.ToDayRemainFund ?? 0), 0);
|
|
var clientAmount = clientbalancedaily.ToDayRemainFund + clientbalancedaily.Credit + clientbalancedaily.TodayRemianFundProduct;
|
|
var clientSwapMarinAmount = clientAmount + SwapMarinAmount;
|
|
var MaintenanceLine = clientSwapMarinAmount == 0 ? 0 : (clientAmount + clientbalancedaily.PayableMargin) / clientSwapMarinAmount;
|
|
clientbalancedaily.MaintenanceLine = Math.Round(MaintenanceLine ?? 0, 2);
|
|
if (PS.Config.Is厦门象屿)
|
|
{
|
|
var xmxyClient = new XiaMenXiangYuClientInfo
|
|
{
|
|
ClientId = client.id,
|
|
ClientName = client.Name,
|
|
ClientNumber = client.Number,
|
|
FundThreshold = client.FundThreshold
|
|
};
|
|
if (balanceDate != DateTime.Today && clientDb.client_Axis_Fundthresholds.Where(x => x.ClientId == client.id).Any())
|
|
{
|
|
xmxyClient.FundThreshold = clientDb.client_Axis_Fundthresholds.Where(x => x.ValueDate <= balanceDate && x.ClientId == client.id).OrderByDescending(x => x.ValueDate)?.FirstOrDefault()?.FundThreshold;
|
|
}
|
|
new XiaMenXiangYuCashService(this).ExecuteV2(xmxyClient, clientbalancedaily, fundObject, out var InOutFund, _context.SettleDate, positionTrades.Count);
|
|
NetFund += InOutFund;
|
|
MarginBalance += InOutFund;
|
|
}
|
|
|
|
clientbalancedaily.FundObject = fundObject;
|
|
clientbalancedaily.FundJson = JsonHelper.Serialize(fundObject);
|
|
|
|
#endregion
|
|
|
|
#region 客户冻结状态
|
|
//如果应付资金总额PayableFund大于0 则设置client
|
|
//PayableFund => Math.Max(ClosedTradePayableFund + PositionTradePayableFund + MarginByPayableMarginCalc, 0);
|
|
var ToDayRemainFund = clientbalancedaily.ToDayRemainFund ?? 0;
|
|
//var PositionPremiumNetCash = clientbalancedaily.PositionPremiumNetCash ?? 0;
|
|
//请知道d1、d2、d3含义的注释一下
|
|
var d1 = Math.Min(ToDayRemainFund + PositionPremiumNetCash, 0);
|
|
var d2 = Math.Max(PositionPremiumNetCash - Math.Max(ToDayRemainFund + PositionPremiumNetCash, 0), 0);
|
|
var d3 = -(clientbalancedaily.PayableMargin ?? 0.0) - Math.Max(ToDayRemainFund - d1 + d2, 0)
|
|
- (clientbalancedaily.TodayRemianFundProduct ?? 0.0) - (clientbalancedaily.Credit ?? 0.0);
|
|
if (Math.Max(-d1 + d2 + d3, 0) > 0)
|
|
{
|
|
client.PendingMarginCallPayment = 1;
|
|
clientbalancedaily.State = "冻结";
|
|
}
|
|
else
|
|
{
|
|
//如果计算追保金额小于等于0则解冻
|
|
if (client.PendingMarginCallPayment == 1)
|
|
{
|
|
client.PendingMarginCallPayment = 0;
|
|
clientbalancedaily.State = "正常";
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 结算合计
|
|
|
|
clientbalancedaily.OptionPremiumSum = clientbalancedaily.OptionPremium;
|
|
clientbalancedaily.OptionPremiumSwapSum = clientbalancedaily.OptionPremiumSwap;
|
|
clientbalancedaily.SettlementBalanceSum = clientbalancedaily.SettlementBalance;
|
|
clientbalancedaily.UnwindBalanceSum = clientbalancedaily.UnwindBalance;
|
|
clientbalancedaily.ExerciseBalanceSum = clientbalancedaily.ExerciseBalance;
|
|
clientbalancedaily.CouponSum = clientbalancedaily.Coupon;
|
|
clientbalancedaily.SwapBalanceSum = clientbalancedaily.SwapBalance;
|
|
clientbalancedaily.WinLossSum = clientbalancedaily.WinLoss;
|
|
clientbalancedaily.trade_fee_sum = clientbalancedaily.trade_fee;
|
|
clientbalancedaily.interest_pnl_sum = clientbalancedaily.interest_pnl;
|
|
clientbalancedaily.EndPremiumSum = clientbalancedaily.EndPremium;
|
|
clientbalancedaily.CashInCashOutProductChangeSum = clientbalancedaily.CashInCashOutProductChange;
|
|
|
|
if (clientbalancedailyPre != null)
|
|
{
|
|
clientbalancedaily.NetFundSum = 0;
|
|
clientbalancedaily.InFundSum = 0;
|
|
clientbalancedaily.OutFundSum = 0;
|
|
clientbalancedaily.OtherFundSum = 0;
|
|
clientbalancedaily.vm_in_fund_sum = 0;
|
|
clientbalancedaily.vm_out_fund_sum = 0;
|
|
foreach (var item in currencyCodes)
|
|
{
|
|
var rateObj = new eod_currency_rate
|
|
{
|
|
Rate = 1,
|
|
SellRate = 1,
|
|
BuyRate = 1,
|
|
ForeignCurrency = item,
|
|
LocalCurrency = client.SettlementCurrency,
|
|
};
|
|
|
|
if (PS.Config.ErpElement.SupportMultiCurrency)
|
|
{
|
|
currencyProvider.TryGetCurrencyRate(item, client.SettlementCurrency, out rateObj);
|
|
if (rateObj == null)
|
|
{
|
|
_context.RaiseError("结算客户资金", $"[{client.Name}]找不到汇率:{item}{client.SettlementCurrency}");
|
|
}
|
|
}
|
|
|
|
clientbalancedailyPre.FundObject.NetFundSum.TryGetValue(item, out var preNetFundSum);
|
|
clientbalancedaily.FundObject.NetFund.TryGetValue(item, out var netFundToday);
|
|
clientbalancedaily.FundObject.NetFundSum[item] = preNetFundSum + netFundToday;
|
|
clientbalancedaily.NetFundSum += clientbalancedaily.FundObject.NetFundSum[item] * rateObj.Rate;
|
|
|
|
clientbalancedailyPre.FundObject.InFundSum.TryGetValue(item, out var preInFundSum);
|
|
clientbalancedailyPre.FundObject.VmInFundSum.TryGetValue(item, out var vmpreInFundSum);
|
|
clientbalancedaily.FundObject.InFund.TryGetValue(item, out var inFundToday);
|
|
clientbalancedaily.FundObject.VmInFund.TryGetValue(item, out var vminFundToday);
|
|
clientbalancedaily.FundObject.InFundSum[item] = preInFundSum + inFundToday;
|
|
clientbalancedaily.FundObject.VmInFundSum[item] = vmpreInFundSum + vminFundToday;
|
|
clientbalancedaily.InFundSum += clientbalancedaily.FundObject.InFundSum[item] * rateObj.Rate;
|
|
clientbalancedaily.vm_in_fund_sum += clientbalancedaily.FundObject.VmInFundSum[item] * rateObj.Rate;
|
|
|
|
clientbalancedailyPre.FundObject.OutFundSum.TryGetValue(item, out var preOutFundSum);
|
|
clientbalancedaily.FundObject.OutFund.TryGetValue(item, out var outFundToday);
|
|
clientbalancedailyPre.FundObject.VmOutFundSum.TryGetValue(item, out var vmpreOutFundSum);
|
|
clientbalancedaily.FundObject.VmOutFund.TryGetValue(item, out var vmoutFundToday);
|
|
clientbalancedaily.FundObject.OutFundSum[item] = preOutFundSum + outFundToday;
|
|
clientbalancedaily.FundObject.VmOutFundSum[item] = vmpreOutFundSum + vmoutFundToday;
|
|
clientbalancedaily.OutFundSum += clientbalancedaily.FundObject.OutFundSum[item] * rateObj.Rate;
|
|
clientbalancedaily.vm_out_fund_sum += clientbalancedaily.FundObject.VmOutFundSum[item] * rateObj.Rate;
|
|
|
|
clientbalancedailyPre.FundObject.OtherFundSum.TryGetValue(item, out var preOtherFundSum);
|
|
clientbalancedaily.FundObject.OtherFund.TryGetValue(item, out var otherFundToday);
|
|
clientbalancedaily.FundObject.OtherFundSum[item] = preOtherFundSum + otherFundToday;
|
|
clientbalancedaily.OtherFundSum += clientbalancedaily.FundObject.OtherFundSum[item] * rateObj.Rate;
|
|
}
|
|
clientbalancedaily.OptionPremiumSum += clientbalancedailyPre.OptionPremiumSum;
|
|
clientbalancedaily.OptionPremiumSwapSum += (clientbalancedailyPre.OptionPremiumSwapSum ?? 0);
|
|
clientbalancedaily.SettlementBalanceSum += clientbalancedailyPre.SettlementBalanceSum;
|
|
clientbalancedaily.UnwindBalanceSum += clientbalancedailyPre.UnwindBalanceSum;
|
|
clientbalancedaily.ExerciseBalanceSum += clientbalancedailyPre.ExerciseBalanceSum;
|
|
clientbalancedaily.CouponSum += clientbalancedailyPre.CouponSum;
|
|
clientbalancedaily.SwapBalanceSum += clientbalancedailyPre.SwapBalanceSum;
|
|
clientbalancedaily.WinLossSum += clientbalancedailyPre.WinLossSum;
|
|
clientbalancedaily.trade_fee_sum += clientbalancedailyPre.trade_fee_sum??0;
|
|
clientbalancedaily.interest_pnl_sum += clientbalancedailyPre.interest_pnl_sum??0;
|
|
clientbalancedaily.EndPremiumSum += (clientbalancedailyPre.EndPremiumSum ?? 0);
|
|
clientbalancedaily.CashInCashOutProductChangeSum += clientbalancedailyPre.CashInCashOutProductChangeSum;
|
|
}
|
|
else
|
|
{
|
|
clientbalancedaily.FundObject.NetFundSum = clientbalancedaily.FundObject.NetFund;
|
|
clientbalancedaily.FundObject.InFundSum = clientbalancedaily.FundObject.InFund;
|
|
clientbalancedaily.FundObject.OutFundSum = clientbalancedaily.FundObject.OutFund;
|
|
clientbalancedaily.FundObject.VmInFundSum = clientbalancedaily.FundObject.VmInFund;
|
|
clientbalancedaily.FundObject.VmOutFundSum = clientbalancedaily.FundObject.VmOutFund;
|
|
clientbalancedaily.FundObject.OtherFundSum = clientbalancedaily.FundObject.OtherFund;
|
|
|
|
clientbalancedaily.NetFundSum = clientbalancedaily.NetFund;
|
|
clientbalancedaily.InFundSum = clientbalancedaily.InFund;
|
|
clientbalancedaily.vm_in_fund_sum= clientbalancedaily.vm_in_fund;
|
|
clientbalancedaily.OutFundSum = clientbalancedaily.OutFund;
|
|
clientbalancedaily.vm_out_fund_sum = clientbalancedaily.vm_out_fund;
|
|
clientbalancedaily.OtherFundSum = clientbalancedaily.OtherFund;
|
|
}
|
|
|
|
#endregion
|
|
|
|
clientbalancedaily.FundJson = JsonHelper.Serialize(clientbalancedaily.FundObject);
|
|
|
|
newClientBalanceDaily.Add(clientbalancedaily);
|
|
|
|
if (PS.Config.Is广发商贸)
|
|
{
|
|
clientbalancedaily.PositionPnl = 0;
|
|
clientbalancedaily.RoundedPositionPnl = 0;
|
|
clientbalancedaily.RoundedPv = 0;
|
|
clientbalancedaily.Pv = 0;
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 计算渠道方合计
|
|
var baseName = PS.Config.CompanyFullName;
|
|
var baseClient = clientDb.client.FirstOrDefault(t => baseName.Equals(t.Name));
|
|
//判断存在渠道商配置信息时
|
|
if (baseClient != null)
|
|
{
|
|
//获取当前结算的非渠道本身的所有客户的结算信息(当日)
|
|
var allNewClientbalanceList = newClientBalanceDaily.Where(t => t.ClientId != baseClient.id);
|
|
//渠道客户当日结算信息(不包括其他客户合计)
|
|
var baseClientBalanceDaily = newClientBalanceDaily.FirstOrDefault(t => t.ClientId == baseClient.id);
|
|
|
|
#region 处理渠道商历史资金结算信息
|
|
//检查当前渠道商是否已有过结算记录
|
|
var tempBaseClientbalancedaily = preClientbalancedailys.FirstOrDefault(t => t.ClientId == baseClient.id);
|
|
//如果渠道商客户结算数据不存在则按结算日期顺序结算历史数据行
|
|
var RemainFund = 0.0;
|
|
if (tempBaseClientbalancedaily == null)
|
|
{
|
|
var allOldClientbalancedaily = DbContext.ClientBalanceDaily.AsNoTracking().Where(t => t.BalanceDate < balanceDate && allClientIds.Contains(t.ClientId) && t.ClientId != baseClient.id).ToList();
|
|
var balanceDateList = allOldClientbalancedaily.Select(t => t.BalanceDate).Distinct().OrderBy(t => t).ToList();
|
|
for (var i = 0; i < balanceDateList.Count; i++)
|
|
{
|
|
var tempBalancedaily = allOldClientbalancedaily.Where(t => t.BalanceDate == balanceDateList[i]);
|
|
var tempNewclientbalancedaily = new ClientBalanceDaily
|
|
{
|
|
ClientId = baseClient.id,
|
|
ClientName = baseClient.Name,
|
|
ClientNumber = baseClient.Number,
|
|
BalanceDate = balanceDateList[i],
|
|
ToDayRemainFund = RemainFund + tempBalancedaily.Sum(t => -((t.OptionPremium ?? 0.0) + (t.OptionPremiumSwap ?? 0.0) + (t.SettlementBalance ?? 0.0) + (t.Coupon ?? 0.0) + (t.SwapBalance ?? 0.0))),
|
|
LastDayRemainFund = RemainFund,
|
|
DayGainLoss = tempBalancedaily.Sum(t => -(t.DayGainLoss ?? 0.0)),
|
|
OptionPremium = tempBalancedaily.Sum(t => -(t.OptionPremium ?? 0.0)),
|
|
OptionPremiumSwap = tempBalancedaily.Sum(t => -(t.OptionPremiumSwap ?? 0.0)),
|
|
SettlementBalance = tempBalancedaily.Sum(t => -(t.SettlementBalance ?? 0.0)),
|
|
UnwindBalance = tempBalancedaily.Sum(t => -(t.UnwindBalance ?? 0.0)),
|
|
SwapBalance = tempBalancedaily.Sum(t => -(t.SwapBalance ?? 0.0)),
|
|
Coupon = tempBalancedaily.Sum(t => -(t.Coupon ?? 0.0)),
|
|
ExerciseBalance = tempBalancedaily.Sum(t => -(t.ExerciseBalance ?? 0.0)),
|
|
AdvisableMargin = RemainFund + tempBalancedaily.Sum(t => -((t.OptionPremium ?? 0.0) + (t.OptionPremiumSwap ?? 0.0) + (t.SettlementBalance ?? 0.0) + (t.Coupon ?? 0.0) + (t.SwapBalance ?? 0.0))),
|
|
TotalNominal = tempBalancedaily.Sum(t => (t.TotalNominal ?? 0.0)),
|
|
Pv = tempBalancedaily.Sum(t => -(t.Pv ?? 0.0)),
|
|
MarginBalance = RemainFund + tempBalancedaily.Sum(t => -((t.OptionPremium ?? 0.0) + (t.OptionPremiumSwap ?? 0.0) + (t.SettlementBalance ?? 0.0) + (t.Coupon ?? 0.0) + (t.SwapBalance ?? 0.0))),
|
|
OptId = UserId,
|
|
OptName = UserName,
|
|
OptDate = DateTime.Now,
|
|
};
|
|
RemainFund = tempNewclientbalancedaily.ToDayRemainFund ?? 0.0;
|
|
newClientBalanceDaily.Add(tempNewclientbalancedaily);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
if (allNewClientbalanceList.Any())
|
|
{
|
|
if (baseClientBalanceDaily == null)
|
|
{
|
|
baseClientBalanceDaily = new ClientBalanceDaily
|
|
{
|
|
ClientId = baseClient.id,
|
|
ClientName = baseClient.Name,
|
|
ClientNumber = baseClient.Number,
|
|
BalanceDate = balanceDate,
|
|
OptId = UserId,
|
|
OptName = UserName,
|
|
OptDate = DateTime.Now,
|
|
};
|
|
}
|
|
|
|
baseClientBalanceDaily.ToDayRemainFund += allNewClientbalanceList.Sum(t => -((t.OptionPremium ?? 0.0) + (t.OptionPremiumSwap ?? 0.0) + (t.SettlementBalance ?? 0.0) + (t.Coupon ?? 0.0) + (t.SwapBalance ?? 0.0))) + RemainFund;
|
|
baseClientBalanceDaily.LastDayRemainFund += RemainFund;
|
|
baseClientBalanceDaily.DayGainLoss = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.DayGainLoss) + allNewClientbalanceList.Sum(t => -(t.DayGainLoss ?? 0.0));
|
|
baseClientBalanceDaily.OptionPremium = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.OptionPremium) + allNewClientbalanceList.Sum(t => -(t.OptionPremium ?? 0.0));
|
|
baseClientBalanceDaily.OptionPremiumSwap = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.OptionPremiumSwap) + allNewClientbalanceList.Sum(t => -(t.OptionPremiumSwap ?? 0.0));
|
|
baseClientBalanceDaily.SettlementBalance = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.SettlementBalance) + allNewClientbalanceList.Sum(t => -(t.SettlementBalance ?? 0.0));
|
|
baseClientBalanceDaily.UnwindBalance = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.UnwindBalance) + allNewClientbalanceList.Sum(t => -(t.UnwindBalance ?? 0.0));
|
|
baseClientBalanceDaily.ExerciseBalance = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.ExerciseBalance) + allNewClientbalanceList.Sum(t => -(t.ExerciseBalance ?? 0.0));
|
|
baseClientBalanceDaily.Coupon = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.Coupon) + allNewClientbalanceList.Sum(t => -(t.Coupon ?? 0.0));
|
|
baseClientBalanceDaily.SwapBalance = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.SwapBalance) + allNewClientbalanceList.Sum(t => -(t.SwapBalance ?? 0.0));
|
|
baseClientBalanceDaily.AdvisableMargin = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.ToDayRemainFund) + allNewClientbalanceList.Sum(t => -((t.OptionPremium ?? 0.0) + (t.OptionPremiumSwap ?? 0.0) + (t.SettlementBalance ?? 0.0) + (t.Coupon ?? 0.0) + (t.SwapBalance ?? 0.0))) + RemainFund;
|
|
baseClientBalanceDaily.TotalNominal = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.TotalNominal) + allNewClientbalanceList.Sum(t => (t.TotalNominal ?? 0.0));
|
|
baseClientBalanceDaily.Pv = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.Pv) + allNewClientbalanceList.Sum(t => -(t.Pv ?? 0.0));
|
|
baseClientBalanceDaily.MarginBalance = (baseClientBalanceDaily == null ? 0 : baseClientBalanceDaily.MarginBalance) + allNewClientbalanceList.Sum(t => -((t.OptionPremium ?? 0.0) + (t.OptionPremiumSwap ?? 0.0) + (t.SettlementBalance ?? 0.0) + (t.Coupon ?? 0.0) + (t.SwapBalance ?? 0.0))) + RemainFund;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region DB删除历史数据 增加当日数据
|
|
var sql = $"{nameof(ClientBalanceDaily.BalanceDate)}='{balanceDate.ToSqlDate()}'";
|
|
if (_context.ClienIds != null && _context.ClienIds.Any())
|
|
{
|
|
sql += $" and ClientId in ({string.Join(",", _context.ClienIds)})";
|
|
}
|
|
//删除 当日导入的old日数据
|
|
DbContext.BulkDelete<ClientBalanceDaily>(sql);
|
|
//MySqlBulkExtensions.BulkInsert(DbContext, newClientBalanceDaily);
|
|
DbContext.ClientBalanceDaily.AddRange(newClientBalanceDaily);
|
|
DbContext.SaveChanges();
|
|
|
|
#endregion
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 客户资金未确认状态检查
|
|
/// </summary>
|
|
public void ClientCashInCashOutCheck()
|
|
{
|
|
var balanceDate = _context.SettleDate;
|
|
var reqClientIds = _context.Request.ClientIds;
|
|
var newValuedate = balanceDate.AddDays(1);
|
|
var cashInCashOuts = DbContext.ClientCashInCashOut.Where(x => x.HappenDate >= balanceDate && x.HappenDate < newValuedate && x.ValidState != ConsGlobal.InValid && ClientCashInCashOut.calcCashs.Contains(x.State) && ClientCashInCashOut.cashStateChecks.Contains(x.Direction)).AsNoTracking().ToList();
|
|
if (reqClientIds != null && reqClientIds.Any())
|
|
{
|
|
cashInCashOuts = cashInCashOuts.Where(x => reqClientIds.Contains(x.ClientId ?? 0)).ToList();
|
|
}
|
|
if (cashInCashOuts.Any())
|
|
{
|
|
_context.RaiseError("客户资金结算", $"{balanceDate:yyyy年MM月dd日}存在未确认的资金,请先将资金确认后再操作");
|
|
}
|
|
}
|
|
private void AddToFund(Dictionary<string, double> fundDictionary, string currencyCode, double amount)
|
|
{
|
|
if (fundDictionary.ContainsKey(currencyCode))
|
|
{
|
|
fundDictionary[currencyCode] += amount;
|
|
}
|
|
else
|
|
{
|
|
fundDictionary.Add(currencyCode, amount);
|
|
}
|
|
}
|
|
}
|
|
}
|