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
{
///
/// 客户结算
///
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();
}
}
///
/// 客户结算
///
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 eodRiskList = null;
//循环客户信息计算客户资金信息
IQueryable 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 frozenClientIdList = null, normalClientIdList = null;
if (_context.IsCurrentDay)
{
frozenClientIdList = new List(50);
normalClientIdList = new List(50);
}
var newClientBalanceDaily = new List(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($"{nameof(ct1.BalanceDate)}='{balanceDate.ToSqlDate()}'");
}
else
{
DbContext.BulkDelete(
$"{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 todayTrades, IQueryable eodpnlList, IQueryable 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(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() : 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 确认成交的持仓数据 LastPvSum,TotalPnlSum 当天了结的没有计算
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 GetClients(ClientDBContext clientDb, IEnumerable reqClientIds)
{
var balanceDate = _context.SettleDate;
var preBalanceDate = _context.PreSettleDate;
if (reqClientIds != null && !reqClientIds.Any(n => n > 0))
{
reqClientIds = null;
}
//获取所有客户信息
var clientPrediate = PredicateBuilder.Create(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(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(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(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(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(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;
}
///
/// 获取结算日相关的资金了结记录
///
private IEnumerable GetFinishedTradeCashSumList(IEnumerable 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(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; }
///
/// 是否人工修改过
///
public bool ModifiedFlag { get; set; }
}
class ClientProductDto
{
public int ClientId { get; set; }
///
/// 抵押记录编号
///
public string ProductNumber { get; set; }
public int? UnderlyingId { get; set; }
public string UnderlyingCode { get; set; }
///
/// 质押数量
///
public double? ProductAmount { get; set; }
///
/// 质押率
///
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; }
///
/// 资金限额
///
public double? FundThreshold { get; set; }
///
/// 是否追保
///
public double PendingMarginCallPayment { get; set; }
//-----授信-----
///
/// 客户授信合计
///
public double CreditSum { get; set; }
///
/// 客户授信名义本金合计
///
public double CreditStockEqvNotionalSum { get; set; }
//-----其他-----
///
/// 上日结算数据
///
public ClientBalanceDaily PreDaily { get; set; }
///
/// 客户保证金
///
public ClientSpanDto ClientSpan { get; set; }
///
/// 这个需要保持数据追踪状态以便更新数据库数据
///
public IEnumerable EntryexitList { get; set; }
///
/// 这个需要保持数据追踪状态以便更新数据库数据
///
public IEnumerable EntryexitSwapList { get; set; }
///
/// 抵押品信息
///
public IEnumerable ClientProductList { get; set; }
///
/// 冻结资金汇总
///
public ClientFrozenFunds FrozenFunds { get; set; }
///
/// 客户关联交易资金记录
///
public IEnumerable TodayTradeCashList { get; set; }
//获取客户导入的所有持仓信息 -- 收益互换(国君)
public IEnumerable eodPositionSwapMannual { get; set; }
}
class EodPnlSum
{
///
/// 昨日价值
///
public double LastPvSum { get; set; }
///
/// 当日价值
///
public double PvSum { get; set; }
///
///
///
public double SellPvSum { get; set; }
///
/// 当日四舍五入价值
///
public double RoundedPvSum { get; set; }
///
/// 当日浮动盈亏
///
public double DailyPnLSum { get; set; }
///
/// 当日持仓盈亏
///
public double PositionPnlSum { get; set; }
///
/// 当日四舍五入持仓盈亏
///
public double RoundedPositionPnlSum { get; set; }
///
/// 当日累积总盈亏
///
public double TotalPnlSum { get; set; }
}
class MyComparer
{
PropertyInfo[] _props;
readonly List _diffList;
readonly HashSet _ignorePropNames;
public MyComparer()
{
ClientBalanceDaily ct;
_ignorePropNames = new HashSet(StringComparer.OrdinalIgnoreCase) {
nameof(ct.id),
nameof(ct.OptId),
nameof(ct.OptDate),
nameof(ct.OptName),
};
_diffList = new List(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().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
}
}
//计算渠道方合计