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

1676 lines
77 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BaseOUDAL;
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using YLErp.BLL;
using YLErp.Configuration;
using YLErp.Helpers;
using YLErp.Model.Enum;
using YLErp.Modules.CalculationModule;
namespace YLErp.Modules.EodModule.SettlementModule
{
/// <summary>
/// 客户结算
/// </summary>
public class EodClientBalanceCalcV2 : EodSettleServiceBaseV2
{
readonly DateTime balanceDate;
readonly double marginRatio, marginMaxRatio;
readonly MyComparer _myComparer;
public EodClientBalanceCalcV2(EodSettlementContextV2 context, bool compareMode = false) : base(context)
{
balanceDate = _context.SettleDate;
//保证金可取上浮比率
marginRatio = _context.SystemValue.MarginRatio ?? 0.15;
marginMaxRatio = marginRatio + 0.02;
DbContext.Database.SetCommandTimeout(600);
if (compareMode)
{
_myComparer = new MyComparer();
}
}
/// <summary>
/// 客户结算
/// </summary>
public void ClientBalanceCalc()
{
var reqClientIds = _context.Request.ClientIds;
var preBalanceDate = _context.PreSettleDate;
var clientDb = DbContextFactory.GetClientDbContext(OptUser);
//获取所有客户信息
var clients = GetClients(clientDb, reqClientIds);
//获取客户所有交易信息(所及为客户所有确认交易,以及当日平仓或者当日执行的交易)
var trades = _context.OtcTrades;
//获取所有用户当日Eod_Risk
IQueryable<EodTradeRisk> eodRiskList = null;
//循环客户信息计算客户资金信息
IQueryable<EodTradePosition> eodpnlList = null;
if (PS.Config.Is国投)
{
eodRiskList = DbContext.eod_trade_risk_openvol.Where(t => t.ValueDate == balanceDate);
eodpnlList = DbContext.eod_trade_position_openvol.Where(t => t.ValueDate == balanceDate);
}
else if (PS.Config.Company == CompanyEnum.格林大华)
{
eodRiskList = DbContext.eod_trade_risk.Where(t => t.ValueDate == balanceDate);
eodpnlList = DbContext.eod_trade_position.Where(t => t.ValueDate == balanceDate);
}
else
{
eodRiskList = DbContext.eod_trade_risk.Where(t => t.ValueDate == balanceDate);
eodpnlList = DbContext.eod_trade_position.Where(t => t.ValueDate == balanceDate);
}
List<int> frozenClientIdList = null, normalClientIdList = null;
if (_context.IsCurrentDay)
{
frozenClientIdList = new List<int>(50);
normalClientIdList = new List<int>(50);
}
var newClientBalanceDaily = new List<ClientBalanceDaily>(100);
foreach (var client in clients)
{
_context.CancellationToken.ThrowIfCancellationRequested();
var daily = ProcessClientBalance(client, _context.OtcTrades, eodpnlList, eodRiskList);
newClientBalanceDaily.Add(daily);
if (_context.IsCurrentDay)
{
if (daily.State == "冻结")
{
if (client.PendingMarginCallPayment != 1)
{
frozenClientIdList.Add(daily.ClientId);
}
}
else if (daily.State == "正常")
{
if (client.PendingMarginCallPayment != 0)
{
normalClientIdList.Add(daily.ClientId);
}
}
}
if (_myComparer != null)
{
var dataOld = DbContext.ClientBalanceDaily.FirstOrDefault(n => n.BalanceDate == balanceDate && n.ClientId == client.id);
_myComparer.Compare(client, daily, dataOld);
}
}
if (_myComparer != null)
{
return;
}
#region DB删除历史数据 增加当日数据
//删除 当日导入的old日数据
ClientBalanceDaily ct1;
if (reqClientIds == null)
{
DbContext.BulkDelete<ClientBalanceDaily>($"{nameof(ct1.BalanceDate)}='{balanceDate.ToSqlDate()}'");
}
else
{
DbContext.BulkDelete<ClientBalanceDaily>(
$"{nameof(ct1.BalanceDate)}='{balanceDate.ToSqlDate()}' AND {nameof(ct1.ClientId)} in @clientIds"
, new { clientIds = reqClientIds });
}
DbContext.ClientBalanceDaily.AddRange(newClientBalanceDaily);
DbContext.SaveChanges();
#endregion
//更新客户表是否追保
if (_context.IsCurrentDay)
{
var sql = "";
if (frozenClientIdList.Count > 0)
{
sql = string.Format("update client set PendingMarginCallPayment=1 where id in ({0});"
, string.Join(",", frozenClientIdList));
}
if (normalClientIdList.Count > 0)
{
sql += string.Format("update client set PendingMarginCallPayment=0 where id in ({0});"
, string.Join(",", normalClientIdList));
}
if (!string.IsNullOrWhiteSpace(sql))
{
clientDb.Database.ExecuteSqlRaw(sql);
}
}
}
//计算客户资金
private ClientBalanceDaily ProcessClientBalance(ClientDto client, IEnumerable<trade> todayTrades, IQueryable<EodTradePosition> eodpnlList, IQueryable<EodTradeRisk> eodRiskList)
{
var preDaily = client.PreDaily;
var eodPriceProvider = _context.GetEodPriceProvider().GetPriceProvider();
var fundObject = new FundObject();
var currencyCodes = _context.CurrencyCodes;
var currencyProvider = _context.EodCurrencyProvider;
var underlyDataSource = DataCacheProvider.GetUnderlyingDataSource();
var varietyDataSource = DataCacheProvider.GetVarietyDataSource();
foreach (var currencyCode in currencyCodes)
{
fundObject.InFund.Add(currencyCode, 0);
fundObject.OutFund.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);
}
#region 变量初始化
//入金
var inFund = 0.0;
//出金
var outFund = 0.0;
//其他收入
var inFundOther = 0.0;
//其他支出
var outFundOther = 0.0;
//当日浮动盈亏
var CurrPnl = 0.0;
//期权空头浮动盈利=∑max(期权空头持仓*(期权合约成本价-期权合约现价), 0) 从客户角度看的
var ClientSellPositionPnl = 0.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;
//应付保证金,可提取保证金
double PayableMargin = 0d, AdvisableMargin = 0d, DeltaMargin = 0d, SwapPayableMargin = 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;
//
ClientBalanceDaily clientbalancedaily = null;
#endregion
#region 客户授信 资信等级 客户昨日现金 clientbalancedaily对象初始化
//获取客户授信
lineOfCredit = client.CreditSum;
clientbalancedaily = new ClientBalanceDaily()
{
ClientId = client.id,
ClientName = client.Name,
ClientNumber = client.Number,
BalanceDate = balanceDate
};
//获取用户最后结算日可用资金
if (preDaily != null)
{
if (!string.IsNullOrEmpty(preDaily.FundJson))
{
preDaily.FundObject = JsonConvert.DeserializeObject<FundObject>(preDaily.FundJson);
if (preDaily.FundObject.InFund.Count() == 1 && preDaily.FundObject.InFund.ContainsKey(string.Empty) && currencyCodes.FirstOrDefault() != string.Empty)
{
if (string.IsNullOrEmpty(client.SettlementCurrency))
{
throw new Exception("客户:" + client.Name + "未配置结算币种");
}
preDaily.FundObject.InFund.Add(client.SettlementCurrency, preDaily.InFund ?? 0);
preDaily.FundObject.InFundSum.Add(client.SettlementCurrency, preDaily.InFundSum ?? 0);
preDaily.FundObject.OutFund.Add(client.SettlementCurrency, preDaily.OutFund ?? 0);
preDaily.FundObject.OutFundSum.Add(client.SettlementCurrency, preDaily.OutFundSum ?? 0);
preDaily.FundObject.NetFund.Add(client.SettlementCurrency, preDaily.NetFund ?? 0);
preDaily.FundObject.NetFundSum.Add(client.SettlementCurrency, preDaily.NetFundSum ?? 0);
preDaily.FundObject.OtherFund.Add(client.SettlementCurrency, preDaily.OtherFund ?? 0);
preDaily.FundObject.OtherFundSum.Add(client.SettlementCurrency, preDaily.OtherFundSum ?? 0);
preDaily.FundObject.TodayRemainFund.Add(client.SettlementCurrency, preDaily.ToDayRemainFund ?? 0);
}
foreach (var currencyCode in currencyCodes)
{
if (preDaily.FundObject.TodayRemainFund.ContainsKey(currencyCode))
{
fundObject.LastDayRemainFund[currencyCode] = preDaily.FundObject.TodayRemainFund[currencyCode];
}
}
}
else
{
preDaily.FundObject = new FundObject() { };
if (currencyCodes.Count() == 1 && currencyCodes.FirstOrDefault() == string.Empty)
{
preDaily.FundObject = new FundObject();
preDaily.FundObject.InFund.Add(string.Empty, preDaily.InFund ?? 0);
preDaily.FundObject.InFundSum.Add(string.Empty, preDaily.InFundSum ?? 0);
preDaily.FundObject.OutFund.Add(string.Empty, preDaily.OutFund ?? 0);
preDaily.FundObject.OutFundSum.Add(string.Empty, preDaily.OutFundSum ?? 0);
preDaily.FundObject.NetFund.Add(string.Empty, preDaily.NetFund ?? 0);
preDaily.FundObject.NetFundSum.Add(string.Empty, preDaily.NetFundSum ?? 0);
preDaily.FundObject.OtherFund.Add(string.Empty, preDaily.OtherFund ?? 0);
preDaily.FundObject.OtherFundSum.Add(string.Empty, preDaily.OtherFundSum ?? 0);
fundObject.LastDayRemainFund[string.Empty] = preDaily.ToDayRemainFund ?? 0;
}
else
{
preDaily.FundObject.InFund.Add(client.SettlementCurrency, preDaily.InFund ?? 0);
preDaily.FundObject.InFundSum.Add(client.SettlementCurrency, preDaily.InFundSum ?? 0);
preDaily.FundObject.OutFund.Add(client.SettlementCurrency, preDaily.OutFund ?? 0);
preDaily.FundObject.OutFundSum.Add(client.SettlementCurrency, preDaily.OutFundSum ?? 0);
preDaily.FundObject.NetFund.Add(client.SettlementCurrency, preDaily.NetFund ?? 0);
preDaily.FundObject.NetFundSum.Add(client.SettlementCurrency, preDaily.NetFundSum ?? 0);
preDaily.FundObject.OtherFund.Add(client.SettlementCurrency, preDaily.OtherFund ?? 0);
preDaily.FundObject.OtherFundSum.Add(client.SettlementCurrency, preDaily.OtherFundSum ?? 0);
fundObject.LastDayRemainFund[client.SettlementCurrency] = preDaily.ToDayRemainFund ?? 0;
}
}
LastDayPositionPremiumNetCash = preDaily.PositionPremiumNetCash ?? 0.0;
LastGuaranteesTotalAmount = preDaily.TodayRemianFundProduct ?? 0.0;
}
AvailableStockEqvNotional = client.CreditStockEqvNotionalSum -
(todayTrades.Where(O => ConsTrade.PositionTradeStatusList.Contains(O.TradeStatus) && O.ClientId == client.id).Sum(O => (double?)O.StockEqvNotional) ?? 0.0);
#endregion
#region 出金 入金 当日可用资金计算
//获取客户所有出入金列表
if (client.EntryexitList != null)
{
var tradeCashGroupIds = client.EntryexitList.Where(y => y.IsGroup == 1).Select(y => y.TradeCashId).ToArray();
var tradeCashGroups = DbContext.trade_cash.Where(x => tradeCashGroupIds.Contains(x.id));
foreach (var clientEntryexit in client.EntryexitList)
{
if (null == clientEntryexit.Direction)
{
throw new Exception("客户:" + client.Name + "有一条出入记录存在出入金方向存在问题!");
}
if (clientEntryexit.CurrencyCode == null)
{
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("入金"))
{
if (fundObject.InFund.ContainsKey(clientEntryexit.CurrencyCode))
{
fundObject.InFund[clientEntryexit.CurrencyCode] += clientEntryexit.Money ?? 0;
}
else
{
fundObject.InFund.Add(clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
}
if (fundObject.NetFund.ContainsKey(clientEntryexit.CurrencyCode))
{
fundObject.NetFund[clientEntryexit.CurrencyCode] += clientEntryexit.Money ?? 0;
}
else
{
fundObject.NetFund.Add(clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
}
}
else if (clientEntryexit.Direction.Equals("出金"))
{
if (fundObject.OutFund.ContainsKey(clientEntryexit.CurrencyCode))
{
fundObject.OutFund[clientEntryexit.CurrencyCode] += clientEntryexit.Money ?? 0;
}
else
{
fundObject.OutFund.Add(clientEntryexit.CurrencyCode, clientEntryexit.Money ?? 0);
}
if (fundObject.NetFund.ContainsKey(clientEntryexit.CurrencyCode))
{
fundObject.NetFund[clientEntryexit.CurrencyCode] -= clientEntryexit.Money ?? 0;
}
else
{
fundObject.NetFund.Add(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 (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))
{
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.已结算;
}
}
}
//获取客户所有出入金列表
if (client.EntryexitSwapList != null)
{
foreach (var clientEntryexit in client.EntryexitSwapList)
{
if (null == clientEntryexit.Direction)
{
throw new Exception("客户:" + client.Name + "有一条出入记录存在出入金方向存在问题!");
}
if (clientEntryexit.CurrencyCode == null)
{
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))
{
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;
}
else if (ClientCashInCashOut.系统操作_互换.Equals(clientEntryexit.Action))
{
CurrChangeAmount += clientEntryexit.Money ?? 0.0;
SwapBalance += 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[item] + fundObject.NetFund[item] + fundObject.OtherFund[item];
}
else
{
fundObject.TodayRemainFund.Add(item, fundObject.LastDayRemainFund[item] + fundObject.NetFund[item] + fundObject.OtherFund[item]);
}
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;
outFund += fundObject.OutFund[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 GuaranteesTotalAmount = 0.0;
if (client.ClientProductList != null)
{
foreach (var t in client.ClientProductList)
{
if (!t.UnderlyingId.HasValue || string.IsNullOrEmpty(t.UnderlyingCode))
{
throw new Exception($"抵押品,出入金单号[{t.ProductNumber}]标的ID[{t.UnderlyingId}]未找到对应标的基本信息!");
}
if (eodPriceProvider.TryGetPrice(t.UnderlyingCode, out var price))
{
GuaranteesTotalAmount += (t.ProductAmount ?? 0) * (t.Rate ?? 0.0) * price;
}
else
{
throw new Exception($"抵押品,出入金单号[{t.ProductNumber}]标的[{t.UnderlyingCode}]在{balanceDate:yyyy-MM-dd}收盘价不存在!");
}
}
}
#endregion
#region 当日冻结权利金 当日应收权利金 潜在行权盈余 持仓市值 持仓Pnl
//持仓交易
var positionTrades = todayTrades.Where(t => t.TradeStatus.Equals(ConsTrade.确认成交) && t.ClientId == client.id).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 = client.FrozenFunds;
//当前持仓并且未到支付日的卖出交易(客户为买入,渠道为卖出)则为冻结的权利金
//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;
//获取客户持仓交易的pv以及浮动盈亏
var eodpnlQuery = eodpnlList.Where(t => positionTradeIds.Contains(t.TradeId)).ToArray();
//未了结名义成交金额 todo //持仓的买入 以及卖出是否都统计
TotalNominal = positionTrades == null || positionTrades.Count == 0 ? 0 : positionTrades.Sum(t => t.UnderlyingInstrumentType == "Stock" ? t.StockEqvNotional : (t.Notional * (t.SpotPrice ?? 0.0)));
//计算潜在客户行权盈余 max{名义成交金额*(标的当日结算价-标的初始价格)/行权价格, 0}
foreach (var t in positionTrades)
{
if (t.TradeType != "现金流交易")
{
var spotPrice = t.SpotPrice ?? t.SpotPrice ?? 0.0;
var nominal = t.UnderlyingInstrumentType == "Stock" ? t.StockEqvNotional : (t.Notional * spotPrice);
if (!eodPriceProvider.TryGetPrice(t.UnderlyingCode, 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 == "买入")
{
var um = underlyDataSource.GetData(t.UnderlyingCode);
//deltaS/S
var rate = um?.DeltaS_S ?? 0;
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 = risk != null ? Math.Abs(risk.DeltaCash) * rate + 0.5 * 100 * rate * rate * Math.Abs(Math.Min(risk.GammaCash, 0)) : 0;
PFE += Math.Min(pfe1, pfe2);
}
}
//todo:收益互换没有OriginalNotional
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));
if (client.TodayTradeCashList != null && client.TodayTradeCashList.Any())
{
WinLoss = client.TodayTradeCashList.Sum(tc =>
{
var cost = 0d;
if (tc.TradeType != "远期")
{
cost = TradeCalcHelper.GetSign(tc.BuySell) * tc.TradePrice * tc.TcUnwindPercentRateSum;
}
else
{
cost = -tc.TradePrice * tc.TcUnwindPercentRateSum;//远期开仓总费用占比
}
return cost - tc.TcAmountSum.OtcFormatValue(OtcFormatFlag.tradePrice);
});
//了结开仓费用
EndPremium = client.TodayTradeCashList.Sum(tc =>
{
var cost = 0d;
if (tc.TradeType != "远期")
{
cost = TradeCalcHelper.GetSign(tc.BuySell) * tc.TradePrice * tc.TcUnwindPercentRateSum;
}
else
{
cost = -tc.TradePrice * tc.TcUnwindPercentRateSum;//远期开仓总费用占比
}
return cost;
});
}
var eodPnlSum = new EodPnlSum();
if (eodpnlQuery.Any())
{
//todo: eodpnlQuery 确认成交的持仓数据 LastPvSumTotalPnlSum 当天了结的没有计算
foreach (var x in eodpnlQuery)
{
eodPnlSum.LastPvSum -= x.LastPv;
eodPnlSum.PvSum -= x.Pv;
if (x.BuySell == "买入")
{
eodPnlSum.SellPvSum -= x.Pv;
}
eodPnlSum.RoundedPvSum -= x.RoundedPv;
eodPnlSum.TotalPnlSum -= x.TotalPnL;
eodPnlSum.PositionPnlSum -= x.PositionPnL;
eodPnlSum.RoundedPositionPnlSum -= x.RoundedPositionPnL;
//期权空头浮动盈利=∑max(期权空头持仓*(期权合约成本价-期权合约现价), 0) 从客户角度看的, 结构化交易需要将两条腿的空头Pnl合计
if (x.TradeType != "结构化交易" && x.ParentTradeId == 0 && x.BuySell == "买入")
{
ClientSellPositionPnl += Math.Max(-x.PositionPnL, 0);
}
}
if (_context.SystemValue.PotentialSurplusCalcMode == valuedate.PotentialSurplusCalcMode_Pv)
{
PotentialSurpluses = eodPnlSum.PvSum;
}
}
if (eodpnlList.Where(t => t.ClientId == client.id).Any())
{
eodPnlSum.DailyPnLSum = eodpnlList.Where(t => t.ClientId == client.id).Sum(q => q.DailyPnL) * (-1);//当日浮动盈亏
}
//合计持仓浮动盈亏
CurrPnl = eodPnlSum.DailyPnLSum;
clientPv = eodPnlSum.PvSum;
roundedClientPv = eodPnlSum.RoundedPvSum;
clientSellPv = eodPnlSum.SellPvSum;
#endregion
#region 应缴保证金 保证金余额 可取保证金 追保额度
//获取tradespan 追保金额 = (当日资金余额 - 维持保证金) + 授信额度
var clientSpan = client.ClientSpan;
if (clientSpan != null)
{
PayableMargin = clientSpan.WorstCastClientPayable ?? 0d;
DeltaMargin = clientSpan.DeltaMargin ?? 0d;
SwapPayableMargin = clientSpan.SwapWorstCastClientPayable ?? 0d;
TwoSideMargin = clientSpan.TwoSideMargin ?? 0d;
OtherSideMargin = clientSpan.OtherSideMargin ?? 0d;
MySideMargin = clientSpan.MySideMargin ?? 0d;
AdditionalMargin = (clientSpan.AdditionalWorstCastClientPayable) ?? 0d;
}
//冻结资金
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%)
AdvisableMargin = Math.Max(MarginBalance + PayableMargin * marginMaxRatio / marginRatio, 0);
//计算追保金额 维持保证金带方向 所以计算追保金额是 为相加
var IsTradeCredit = (client.IsTradeCredit ?? 0) == 1;
//是否期权费授信
if (IsTradeCredit)
{
//期权费授信可以支付权利金 则保证金余额未0时 资金从
Margin = Math.Min(MarginBalance + lineOfCredit + PayableMargin, 0);
}
else
{
//期权费授信不可以支付权利金时
Margin = Math.Min(Math.Max(MarginBalance, 0) + lineOfCredit + PayableMargin, 0) + Math.Min(MarginBalance, 0);
}
#endregion
#region 国君收益互换--导入持仓
if (client.eodPositionSwapMannual != null && client.eodPositionSwapMannual.Any())
{
double swapMargin = 0.0;
double swappv = 0.0;
double swappnl = 0.0;
foreach (var x in client.eodPositionSwapMannual)
{
var underly = underlyDataSource.GetData(x.UnderlyingCode);
var variety = varietyDataSource.GetData(underly.UnderlyingTypeId);
currencyProvider.TryGetCurrencyRate(variety.QuoteCurrency, client.SettlementCurrency, out var rateObj);
//保证金导入是客户方向,其他值是交易员方向
swapMargin += (x.Margin) * rateObj.Rate;
swappv += (-x.PositionPnl + x.TotalFee) * rateObj.Rate;
swappnl += (-x.PositionPnl * rateObj.Rate);
}
PayableMargin -= swapMargin;
clientPv = (clientPv ?? 0) + swappv;
roundedClientPv = (roundedClientPv ?? 0) + swappv;
eodPnlSum.PositionPnlSum += swappnl;
eodPnlSum.RoundedPositionPnlSum += swappnl;
}
#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.InFund = inFund;
clientbalancedaily.OutFund = outFund;
clientbalancedaily.InFundOther = inFundOther;
clientbalancedaily.OutFundOther = outFundOther;
clientbalancedaily.BalanceDate = balanceDate;
clientbalancedaily.DayGainLoss = CurrPnl;
clientbalancedaily.PositionPnl = eodPnlSum.PositionPnlSum;
clientbalancedaily.RoundedPositionPnl = eodPnlSum.RoundedPositionPnlSum;
clientbalancedaily.ClientSellPositionPnl = ClientSellPositionPnl;
clientbalancedaily.TotalPnl = eodPnlSum.TotalPnlSum;
clientbalancedaily.DailyPnl = eodPnlSum.DailyPnLSum;
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.Pv = clientPv ?? 0;
clientbalancedaily.RoundedPv = roundedClientPv ?? 0;
clientbalancedaily.SellPv = clientSellPv ?? 0;
clientbalancedaily.PrepaymentAmount = PrepaymentAmount;
clientbalancedaily.CopeWithLastPremium = CopeWithLastPremium;
clientbalancedaily.CopeWithExpirePremium = CopeWithExpirePremium;
clientbalancedaily.EndPremium = EndPremium;
clientbalancedaily.FrozenBalance = FrozenBalance;
clientbalancedaily.FrozenPremium = FrozenPremium;
clientbalancedaily.FrozenOutFund = clientFrozenFund.OutFunds;
clientbalancedaily.FrozenRedeemFunds = clientFrozenFund.RedeemFunds;
clientbalancedaily.MarginBalance = MarginBalance;
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.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);
if (PS.Config.Is厦门象屿)
{
var xmxyClient = new XiaMenXiangYuClientInfo
{
ClientId = client.id,
ClientName = client.Name,
ClientNumber = client.Number,
FundThreshold = client.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)
{
clientbalancedaily.State = "冻结";
}
else
{
//如果计算追保金额小于等于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.EndPremiumSum = clientbalancedaily.EndPremium;
clientbalancedaily.CashInCashOutProductChangeSum = clientbalancedaily.CashInCashOutProductChange;
if (preDaily != null)
{
clientbalancedaily.NetFundSum = 0;
clientbalancedaily.InFundSum = 0;
clientbalancedaily.OutFundSum = 0;
clientbalancedaily.OtherFundSum = 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}");
}
}
preDaily.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;
preDaily.FundObject.InFundSum.TryGetValue(item, out var preInFundSum);
clientbalancedaily.FundObject.InFund.TryGetValue(item, out var inFundToday);
clientbalancedaily.FundObject.InFundSum[item] = preInFundSum + inFundToday;
clientbalancedaily.InFundSum += clientbalancedaily.FundObject.InFundSum[item] * rateObj.Rate;
preDaily.FundObject.OutFundSum.TryGetValue(item, out var preOutFundSum);
clientbalancedaily.FundObject.OutFund.TryGetValue(item, out var outFundToday);
clientbalancedaily.FundObject.OutFundSum[item] = preOutFundSum + outFundToday;
clientbalancedaily.OutFundSum += clientbalancedaily.FundObject.OutFundSum[item] * rateObj.Rate;
preDaily.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 += preDaily.OptionPremiumSum;
clientbalancedaily.OptionPremiumSwapSum += (preDaily.OptionPremiumSwapSum ?? 0);
clientbalancedaily.SettlementBalanceSum += preDaily.SettlementBalanceSum;
clientbalancedaily.UnwindBalanceSum += preDaily.UnwindBalanceSum;
clientbalancedaily.ExerciseBalanceSum += preDaily.ExerciseBalanceSum;
clientbalancedaily.CouponSum += preDaily.CouponSum;
clientbalancedaily.SwapBalanceSum += preDaily.SwapBalanceSum;
clientbalancedaily.WinLossSum += preDaily.WinLossSum;
clientbalancedaily.EndPremiumSum += (preDaily.EndPremiumSum ?? 0);
clientbalancedaily.CashInCashOutProductChangeSum += preDaily.CashInCashOutProductChangeSum;
}
else
{
clientbalancedaily.FundObject.NetFundSum = clientbalancedaily.FundObject.NetFund;
clientbalancedaily.FundObject.InFundSum = clientbalancedaily.FundObject.InFund;
clientbalancedaily.FundObject.OutFundSum = clientbalancedaily.FundObject.OutFund;
clientbalancedaily.FundObject.OtherFundSum = clientbalancedaily.FundObject.OtherFund;
clientbalancedaily.NetFundSum = clientbalancedaily.NetFund;
clientbalancedaily.InFundSum = clientbalancedaily.InFund;
clientbalancedaily.OutFundSum = clientbalancedaily.OutFund;
clientbalancedaily.OtherFundSum = clientbalancedaily.OtherFund;
}
#endregion
clientbalancedaily.FundJson = JsonHelper.Serialize(clientbalancedaily.FundObject);
return clientbalancedaily;
}
//获取客户信息
private IEnumerable<ClientDto> GetClients(ClientDBContext clientDb, IEnumerable<int> reqClientIds)
{
var balanceDate = _context.SettleDate;
var preBalanceDate = _context.PreSettleDate;
if (reqClientIds != null && !reqClientIds.Any(n => n > 0))
{
reqClientIds = null;
}
//获取所有客户信息
var clientPrediate = PredicateBuilder.Create<Client>(t => t.ProcessStatus != "未提交");
if (reqClientIds != null)
{
clientPrediate = clientPrediate.And(t => reqClientIds.Contains(t.id));
}
var isHistory = balanceDate != DateTime.Today;
var clientDic = clientDb.client.Where(clientPrediate).Select(n => new ClientDto
{
id = n.id,
Name = n.Name,
Number = n.Number,
IsTradeCredit = n.IsTradeCredit,
FundThreshold = isHistory ? 0 : n.FundThreshold,
PendingMarginCallPayment = n.PendingMarginCallPayment ?? 0,
SettlementCurrency = n.SettlementCurrency
}).ToDictionary(n => n.id);
if (isHistory)
{
var fundThresholdDict =
clientDb.client_Axis_Fundthresholds
.Where(x => x.ValueDate <= balanceDate)
.AsEnumerable()
.GroupBy(O => O.ClientId)
.ToDictionary(
K => K.Key,
V => V.OrderByDescending(O => O.ValueDate).FirstOrDefault());
foreach (var item in fundThresholdDict)
{
if (clientDic.TryGetValue(item.Key, out var obj))
{
obj.FundThreshold = item.Value.FundThreshold;
}
}
}
var allClientIds = clientDic.Keys.ToArray();
#region 获取上日客户资金结算
var preDailyPredicate = PredicateBuilder.Create<ClientBalanceDaily>(t => t.BalanceDate == preBalanceDate);
if (reqClientIds != null)
{
preDailyPredicate = preDailyPredicate.And(t => reqClientIds.Contains(t.ClientId));
}
var preDailyList = DbContext.ClientBalanceDaily.Where(preDailyPredicate).ToArray();
foreach (var preDaily in preDailyList)
{
if (clientDic.TryGetValue(preDaily.ClientId, out var client))
{
client.PreDaily = preDaily;
}
}
#endregion
#region 获取所有客户授信
var creditPredicate = PredicateBuilder.Create<CreditTable>(t => t.ClientId != null && t.ProcessStatus == "已审批"
&& (!t.CreditDeadLine.HasValue || t.CreditDeadLine >= balanceDate)
&& (!t.CreditStartDate.HasValue || t.CreditStartDate <= balanceDate));
if (reqClientIds != null)
{
creditPredicate = creditPredicate.And(t => allClientIds.Contains(t.ClientId.Value));
}
var creditQuery = from c in DbContext.credit.Where(creditPredicate)
group c by c.ClientId into g
select new
{
ClientId = g.Key,
CreditSum = g.Sum(t => t.Credit ?? 0),
CreditStockEqvNotionalSum = g.Sum(t => t.StockEqvNotional ?? 0)
};
var creditList = creditQuery.ToArray();
foreach (var credit in creditList)
{
if (clientDic.TryGetValue(credit.ClientId.Value, out var client))
{
client.CreditSum = credit.CreditSum;
client.CreditStockEqvNotionalSum = credit.CreditStockEqvNotionalSum;
}
}
#endregion
#region 出入金记录 获取上个结算日到当前结算日之间的所有已结算和已确认的出入金(包含周末的出入金)
var newValuedate = balanceDate.AddDays(1);
var lastBalanceDateAddOne = preBalanceDate.AddDays(1);
var entryexitPredicate = PredicateBuilder.Create<ClientCashInCashOut>(t => t.ClientId != null && t.ValidState != "InValid"
&& t.HappenDate >= lastBalanceDateAddOne && t.HappenDate < newValuedate
&& (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认));
if (reqClientIds != null)
{
entryexitPredicate = entryexitPredicate.And(t => allClientIds.Contains(t.ClientId.Value));
}
var entryexits = (from cash in DbContext.ClientCashInCashOut.Where(entryexitPredicate)
join trade in DbContext.trade on cash.TradeId equals trade.id into trade
from td in trade.DefaultIfEmpty()
where td.TradeType != "收益互换"
select cash).ToLookup(n => n.ClientId.Value);
var entryexits_swap = (from cash in DbContext.ClientCashInCashOut.Where(entryexitPredicate)
join trade in DbContext.trade.Where(x => x.TradeType == "收益互换") on cash.TradeId equals trade.id
select cash).ToLookup(n => n.ClientId.Value);
foreach (var lookup in entryexits)
{
if (clientDic.TryGetValue(lookup.Key, out var client))
{
client.EntryexitList = lookup.ToArray();
}
}
foreach (var lookup in entryexits_swap)
{
if (clientDic.TryGetValue(lookup.Key, out var client))
{
client.EntryexitSwapList = lookup.ToArray();
}
}
#endregion
#region 获取客户所有现存(抵押状态)抵押品信息
var clientProductPredicate = PredicateBuilder.Create<clientcashincashout_product>(product =>
product.HappenDate < newValuedate
&& (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)
);
if (reqClientIds != null)
{
clientProductPredicate = clientProductPredicate.And(t => allClientIds.Contains(t.ClientId));
}
var clientProductQuery = from product in DbContext.clientcashincashout_product.Where(clientProductPredicate)
join um in DbContext.underlying_manager on product.UnderlyingId equals um.id into um_t
from um in um_t.DefaultIfEmpty()
select new ClientProductDto
{
ProductNumber = product.Number,
ClientId = product.ClientId,
UnderlyingId = product.UnderlyingId,
UnderlyingCode = um.UnderlyingCode,
ProductAmount = product.ProductAmount,
Rate = product.Rate
};
var clientProductLookup = clientProductQuery.ToLookup(n => n.ClientId);
foreach (var lookup in clientProductLookup)
{
if (clientDic.TryGetValue(lookup.Key, out var client))
{
client.ClientProductList = lookup.ToArray();
}
}
#endregion
#region 客户保证金
var clientSpanPredicate = PredicateBuilder.Create<ClientSpan>(t => t.ValueDate == balanceDate && t.SpanType == ClientSpan.SpanType_Eod);
if (reqClientIds != null)
{
clientSpanPredicate = clientSpanPredicate.And(t => allClientIds.Contains(t.ClientId));
}
var clientSpanList = DbContext.client_span.Where(clientSpanPredicate).Select(n => new ClientSpanDto
{
ClientId = n.ClientId,
AdditionalWorstCastClientPayable = n.AdditionalWorstCastClientPayable,
MySideMargin = n.MySideMargin,
OtherSideMargin = n.OtherSideMargin,
TwoSideMargin = n.TwoSideMargin,
WorstCastClientPayable = n.WorstCastClientPayable,
DeltaMargin = n.DeltaMargin,
SwapWorstCastClientPayable = n.SwapWorstCastClientPayable,
ModifiedFlag = n.ModifiedFlag
}).ToArray();
foreach (var spanDto in clientSpanList)
{
if (clientDic.TryGetValue(spanDto.ClientId, out var client))
{
client.ClientSpan = spanDto;
}
}
#endregion
//获取冻结资金信息
var clientFrozenFunds = new ClientFrozenFundsService(this).GetDatas(balanceDate, allClientIds);
foreach (var kv in clientFrozenFunds)
{
if (clientDic.TryGetValue(kv.Key, out var client))
{
client.FrozenFunds = kv.Value;
}
}
//获取结算日相关的资金了结记录
var todayTcSumLookup = GetFinishedTradeCashSumList(reqClientIds).ToLookup(n => n.ClientId);
foreach (var lookup in todayTcSumLookup)
{
if (clientDic.TryGetValue(lookup.Key, out var client))
{
client.TodayTradeCashList = lookup.ToArray();
}
}
var EodPositionSwapMannual = DbContext.eod_trade_position_swap_mannual.Where(x => x.ValueDate == balanceDate).ToLookup(n => n.ClientId);
foreach (var lookup in EodPositionSwapMannual)
{
if (clientDic.TryGetValue(lookup.Key, out var client))
{
client.eodPositionSwapMannual = lookup.ToArray();
}
}
//返回数据结果
return clientDic.Values;
}
/// <summary>
/// 获取结算日相关的资金了结记录
/// </summary>
private IEnumerable<TodayTradeCashDto> GetFinishedTradeCashSumList(IEnumerable<int> reqClientIds)
{
var balanceDate = _context.SettleDate;
//如果前一天是假日,要显示包含假日的交易
var preday = balanceDate.AddDays(-1);
//获取上一个交易日的下一天(例如收盘日是周一,上一个交易日就是周五,他的下一天就是周六,获取的是周六)
var nonHolidayAddOne = valuedateBLL.GetNonHolidayDefore(preday).AddDays(1);
var tcActions = new string[] {
ClientCashInCashOut.系统操作_平仓费,
ClientCashInCashOut.系统操作_行权费,
ClientCashInCashOut.系统操作_互换,
ClientCashInCashOut.系统操作_票息,
ClientCashInCashOut.人工操作_其他
};
var tdPredicate = PredicateBuilder.Create<trade>(t => t.ClientId > 0 && t.ValidState != ConsGlobal.InValid && t.IsGroup != 1);
if (reqClientIds != null)
{
tdPredicate = tdPredicate.And(t => reqClientIds.Contains(t.ClientId));
}
var tcQuery = from tc in DbContext.trade_cash
where (tc.ValueDate >= nonHolidayAddOne && tc.ValueDate <= balanceDate && tc.HappenedDate == null
|| tc.HappenedDate >= nonHolidayAddOne && tc.HappenedDate <= balanceDate)
&& tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted
&& tcActions.Contains(tc.Action)
group tc by tc.TradeId into g
select new
{
TradeId = g.Key,
AmountSum = g.Sum(n => n.Amount),
UnwindPercentRateSum = g.Sum(n => n.UnwindPercentRate ?? 0)
};
var query = from tc in tcQuery
join t in DbContext.trade.Where(tdPredicate) on tc.TradeId equals t.id
select new TodayTradeCashDto
{
TradeId = tc.TradeId,
ClientId = t.ClientId,
TradeType = t.TradeType,
BuySell = t.BuySell,
TradePrice = t.TradePrice ?? 0,
TcAmountSum = tc.AmountSum,
TcUnwindPercentRateSum = tc.UnwindPercentRateSum
};
return query.ToArray();
}
#region----InnerClass----
class ClientSpanDto
{
public int ClientId { get; set; }
public double? WorstCastClientPayable { get; set; }
public double? DeltaMargin { get; set; }
public double? SwapWorstCastClientPayable { get; set; }
public double? TwoSideMargin { get; set; }
public double? OtherSideMargin { get; set; }
public double? MySideMargin { get; set; }
public double? AdditionalWorstCastClientPayable { get; set; }
/// <summary>
/// 是否人工修改过
/// </summary>
public bool ModifiedFlag { get; set; }
}
class ClientProductDto
{
public int ClientId { get; set; }
/// <summary>
/// 抵押记录编号
/// </summary>
public string ProductNumber { get; set; }
public int? UnderlyingId { get; set; }
public string UnderlyingCode { get; set; }
/// <summary>
/// 质押数量
/// </summary>
public double? ProductAmount { get; set; }
/// <summary>
/// 质押率
/// </summary>
public double? Rate { get; set; }
}
class TodayTradeCashDto
{
public int TradeId { get; set; }
public int ClientId { get; set; }
public string TradeType { get; set; }
public string BuySell { get; set; }
public double TradePrice { get; set; }
public double TcAmountSum { get; set; }
public double TcUnwindPercentRateSum { get; set; }
}
class ClientDto
{
public int id { get; set; }
public string Name { get; set; }
public string Number { get; set; }
public string SettlementCurrency { get; set; }
public int? IsTradeCredit { get; set; }
/// <summary>
/// 资金限额
/// </summary>
public double? FundThreshold { get; set; }
/// <summary>
/// 是否追保
/// </summary>
public double PendingMarginCallPayment { get; set; }
//-----授信-----
/// <summary>
/// 客户授信合计
/// </summary>
public double CreditSum { get; set; }
/// <summary>
/// 客户授信名义本金合计
/// </summary>
public double CreditStockEqvNotionalSum { get; set; }
//-----其他-----
/// <summary>
/// 上日结算数据
/// </summary>
public ClientBalanceDaily PreDaily { get; set; }
/// <summary>
/// 客户保证金
/// </summary>
public ClientSpanDto ClientSpan { get; set; }
/// <summary>
/// 这个需要保持数据追踪状态以便更新数据库数据
/// </summary>
public IEnumerable<ClientCashInCashOut> EntryexitList { get; set; }
/// <summary>
/// 这个需要保持数据追踪状态以便更新数据库数据
/// </summary>
public IEnumerable<ClientCashInCashOut> EntryexitSwapList { get; set; }
/// <summary>
/// 抵押品信息
/// </summary>
public IEnumerable<ClientProductDto> ClientProductList { get; set; }
/// <summary>
/// 冻结资金汇总
/// </summary>
public ClientFrozenFunds FrozenFunds { get; set; }
/// <summary>
/// 客户关联交易资金记录
/// </summary>
public IEnumerable<TodayTradeCashDto> TodayTradeCashList { get; set; }
//获取客户导入的所有持仓信息 -- 收益互换(国君)
public IEnumerable<eod_trade_position_swap_mannual> eodPositionSwapMannual { get; set; }
}
class EodPnlSum
{
/// <summary>
/// 昨日价值
/// </summary>
public double LastPvSum { get; set; }
/// <summary>
/// 当日价值
/// </summary>
public double PvSum { get; set; }
/// <summary>
///
/// </summary>
public double SellPvSum { get; set; }
/// <summary>
/// 当日四舍五入价值
/// </summary>
public double RoundedPvSum { get; set; }
/// <summary>
/// 当日浮动盈亏
/// </summary>
public double DailyPnLSum { get; set; }
/// <summary>
/// 当日持仓盈亏
/// </summary>
public double PositionPnlSum { get; set; }
/// <summary>
/// 当日四舍五入持仓盈亏
/// </summary>
public double RoundedPositionPnlSum { get; set; }
/// <summary>
/// 当日累积总盈亏
/// </summary>
public double TotalPnlSum { get; set; }
}
class MyComparer
{
PropertyInfo[] _props;
readonly List<string> _diffList;
readonly HashSet<string> _ignorePropNames;
public MyComparer()
{
ClientBalanceDaily ct;
_ignorePropNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) {
nameof(ct.id),
nameof(ct.OptId),
nameof(ct.OptDate),
nameof(ct.OptName),
};
_diffList = new List<string>(20);
}
public void Compare(ClientDto client, ClientBalanceDaily dataNew, ClientBalanceDaily dataOld)
{
if (dataNew is null)
{
throw new ArgumentNullException(nameof(dataNew));
}
if (dataOld is null)
{
throw new Exception("旧数据不存在");
}
_diffList.Clear();
if (string.IsNullOrEmpty(dataOld.State))
{
dataOld.State = "正常";
}
var dd = new[] { dataNew.FrozenRedeemFunds, dataOld.FrozenRedeemFunds };
ReviseData(dataNew);
ReviseData(dataOld);
if (_props == null)
{
_props = typeof(ClientBalanceDaily).GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p =>
{
return !_ignorePropNames.Contains(p.Name)
&& p.CanWrite && p.CanRead
&& p.GetIndexParameters().Length < 1
&& !p.GetCustomAttributes<NotMappedAttribute>().Any();
}).ToArray();
}
foreach (var p in _props)
{
var objNew = p.GetValue(dataNew);
var objOld = p.GetValue(dataOld);
var strNew = string.Empty;
var strOld = string.Empty;
if (p.PropertyType == typeof(double))
{
strNew = ((double)objNew).ToString("F6");
strOld = ((double)objOld).ToString("F6");
}
else if (p.PropertyType == typeof(double?))
{
if (objNew != null)
{
strNew = ((double?)objNew).Value.ToString("F6");
}
if (objOld != null)
{
strOld = ((double?)objOld).Value.ToString("F6");
}
}
else
{
if (objNew != null)
{
strNew = objNew.ToString();
}
if (objOld != null)
{
strOld = objOld.ToString();
}
}
if (strNew != strOld)
{
_diffList.Add($"字段名:{p.Name},新数据:{strNew},旧数据:{strOld}");
}
}
if (_diffList.Any())
{
var diffstr = string.Join(Environment.NewLine, _diffList.ToArray());
throw new Exception($"[{client.id},{client.Name}]新旧数据不一致:\r\n{diffstr}");
}
else
{
Console.WriteLine($"[{client.id},{client.Name}]新旧数据一致");
}
}
private void ReviseData(ClientBalanceDaily data)
{
//因为抵押品是按照实时行情处理的所以需要去除这部分的影响
data.FrozenBalance += data.FrozenRedeemFunds;
data.MarginBalance += data.FrozenRedeemFunds;
if (data.AdvisableMargin > 0)
{
data.AdvisableMargin += data.FrozenRedeemFunds;
}
if (data.Margin < 0)
{
data.Margin += data.FrozenRedeemFunds;
}
data.FrozenRedeemFunds = 0;
}
}
#endregion
}
}
//计算渠道方合计