1680 lines
94 KiB
C#
1680 lines
94 KiB
C#
using BaseOUDAL;
|
||
using DocumentFormat.OpenXml.Bibliography;
|
||
using DocumentFormat.OpenXml.Spreadsheet;
|
||
using MathNet.Numerics;
|
||
using NPOI.SS.UserModel;
|
||
using YLErp.BLL.Eod;
|
||
using YLErp.DBModels;
|
||
using YLErp.DBModels.Enums;
|
||
using YLErp.Helpers;
|
||
using YLErp.Model;
|
||
using YLErp.Models;
|
||
using YLErp.Modules;
|
||
using YLErp.Modules.ClientModule;
|
||
using YLErp.Modules.SwapModule;
|
||
using YLErp.Modules.SwapModule.Margin;
|
||
|
||
namespace YLErp.BLL.EodSettlement
|
||
{
|
||
/// <summary>
|
||
/// 客户结算信息工具类
|
||
/// </summary>
|
||
public class ClientBalanceUtility
|
||
{
|
||
/// <summary>
|
||
/// 获取startDate至endDate 所有客户结算信息统计
|
||
/// </summary>
|
||
public static IEnumerable<ClientSettleBalance> GetAllClientBanlances(DateTime startDate, DateTime endDate, bool IsGetOuterMarginGap = false
|
||
, Abstract.IDataSource<ClientMainInfo> clientDataSource = null)
|
||
{
|
||
using var db = DbContextFactory.GetClientDbContext(null);
|
||
var clientIds = db.client.Where(s => s.ProcessStatus != "未提交").Select(n => n.id).ToList();
|
||
return GetClientBanlances(
|
||
clientIdList: clientIds,
|
||
startDate: startDate,
|
||
endDate: endDate,
|
||
IsGetOuterMarginGap: IsGetOuterMarginGap,
|
||
clientDataSource: clientDataSource);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取startDate至endDate 客户结算信息统计
|
||
/// </summary>
|
||
public static IEnumerable<ClientSettleBalance> GetClientBanlances(List<int> clientIdList
|
||
, DateTime startDate, DateTime endDate, bool IsClientBalanceGap = false, bool IsGetOuterMarginGap = false, bool ParentFlag = false
|
||
, Abstract.IDataSource<ClientMainInfo> clientDataSource = null)
|
||
{
|
||
if (startDate > endDate)
|
||
{
|
||
throw new ArgumentException("startDate不能大于endDate");
|
||
}
|
||
|
||
if (null == clientIdList || !clientIdList.Any())
|
||
{
|
||
return Enumerable.Empty<ClientSettleBalance>();
|
||
}
|
||
|
||
var returnClientId = clientIdList[0];
|
||
|
||
if (ParentFlag)
|
||
{
|
||
clientIdList = GetSubclientId(clientIdList[0]);
|
||
}
|
||
|
||
//一些客户在下面没有关联的数据,在这里直接赋值
|
||
var dic = clientIdList.ToHashSet().ToDictionary(n => n, m => new ClientSettleBalance
|
||
{
|
||
ClientId = m,
|
||
ValueDate = endDate,
|
||
});
|
||
foreach (var clientId in clientIdList)
|
||
{
|
||
var balance = dic[clientId];
|
||
var client = DataCacheProvider.GetClientDataSource().GetData(clientId);
|
||
balance.DesirableRate = client?.DesirableRate ?? 0;
|
||
balance.CreditCanApplySwap = client?.creditCanApplySwap ?? false;
|
||
balance.ClientType = client?.SwapTradeType ?? 0;
|
||
}
|
||
if (PS.Config.Is广期资本)
|
||
{
|
||
Dictionary<int, int?> samePeerDic = null;
|
||
|
||
using (var clientDb = DbContextFactory.GetClientDbContext(null))
|
||
{
|
||
samePeerDic = clientDb.client.AsNoTracking().Where(p => clientIdList.Contains(p.id)).ToDictionary(p => p.id, p => p.SamePeer);
|
||
}
|
||
|
||
samePeerDic ??= new Dictionary<int, int?>();
|
||
foreach (var kv in dic)
|
||
{
|
||
kv.Value.SamePeer = samePeerDic.ContainsKey(kv.Key) ? samePeerDic[kv.Key] ?? 0 : 0;
|
||
}
|
||
}
|
||
|
||
if (PS.Config.Is宏源)
|
||
{
|
||
Dictionary<int, double?> ratio1Dic = null;
|
||
using (var clientDb = DbContextFactory.GetClientDbContext(null))
|
||
{
|
||
ratio1Dic = (from c in clientDb.client
|
||
join cl in clientDb.clientlevel on c.LevelId equals cl.id into t_cl
|
||
from temp in t_cl.DefaultIfEmpty()
|
||
where clientIdList.Contains(c.id)
|
||
select new { Id = c.id, Ratio1 = temp == null ? null : temp.Ratio1 }).ToDictionary(p => p.Id, p => p.Ratio1);
|
||
}
|
||
|
||
ratio1Dic ??= new Dictionary<int, double?>();
|
||
foreach (var kv in dic)
|
||
{
|
||
kv.Value.Ratio1 = ratio1Dic.ContainsKey(kv.Key) ? ratio1Dic[kv.Key] ?? 1.0 : 1.0;
|
||
}
|
||
}
|
||
|
||
var clientIdS = new List<int>();
|
||
clientIdS.AddRange(clientIdList);
|
||
using (var db = new YLContext())
|
||
{
|
||
//系统交易日
|
||
var valuedate = valuedateBLL.ValueDate;
|
||
var lastpushLog = db.push_log.Where(x => x.data_type == (int)SwapPushDataEnum.日终估值获取 && x.data_state == (int)SwapPushDataStateEnum.接收处理成功 && x.create_time > valuedate).OrderByDescending(o => o.create_time).FirstOrDefault();
|
||
//获取根据系统时间
|
||
var lastBalanceDate = EodOperationBase.GetLastSettlementDate(valuedate);
|
||
var lastDate = lastBalanceDate;
|
||
|
||
//查询历史记录
|
||
if (startDate <= lastBalanceDate)
|
||
{
|
||
if (endDate < lastBalanceDate)
|
||
{
|
||
lastDate = db.ClientBalanceDaily.Where(n => n.BalanceDate <= endDate)
|
||
.Max(n => n.BalanceDate) ?? DateTime.MinValue;
|
||
}
|
||
|
||
var sumQuery = from t in db.ClientBalanceDaily
|
||
where t.BalanceDate == lastDate && clientIdS.Contains(t.ClientId)
|
||
select new ClientSettleBalance
|
||
{
|
||
ClientId = t.ClientId,
|
||
NetFund = t.NetFundSum ?? 0,
|
||
InFund = t.InFundSum ?? 0,
|
||
OutFund = t.OutFundSum ?? 0,
|
||
OtherFund = t.OtherFundSum ?? 0,
|
||
OptionPremium = t.OptionPremiumSum ?? 0,
|
||
OptionPremiumSwap = t.OptionPremiumSwapSum ?? 0,
|
||
SettlementBalance = t.SettlementBalanceSum ?? 0,
|
||
UnwindBalance = t.UnwindBalanceSum ?? 0,
|
||
SwapBalance = t.SwapBalanceSum ?? 0,
|
||
Coupon = t.CouponSum ?? 0,
|
||
ExerciseBalance = t.ExerciseBalanceSum ?? 0,
|
||
CashInCashOutProductChange = t.CashInCashOutProductChangeSum ?? 0,
|
||
WinLoss = t.WinLossSum ?? 0,
|
||
EndPremiumSum = t.EndPremiumSum ?? 0,
|
||
FundJson = t.FundJson,
|
||
PFE = t.PFE,
|
||
EAD = t.EAD,
|
||
LastSettlemetTime = t.OptDate,
|
||
TradeFee = t.trade_fee_sum ?? 0,
|
||
InterestPnl = t.interest_pnl_sum ?? 0
|
||
};
|
||
|
||
var sumDatas = sumQuery.ToArray();
|
||
//获取结束日期那一天的Sum总值
|
||
//例如2018-08-08到2019-08-08:区间段sum值 = sum(2019-08-08) - sum(2018-08-08)
|
||
//此处取的是sum(2019-08-08)
|
||
foreach (var data in sumDatas)
|
||
{
|
||
var balance = dic[data.ClientId];
|
||
balance.NetFund = data.NetFund;
|
||
balance.InFund = data.InFund;
|
||
balance.OutFund = data.OutFund;
|
||
balance.OtherFund = data.OtherFund;
|
||
balance.OptionPremium = data.OptionPremium;
|
||
balance.OptionPremiumSwap = data.OptionPremiumSwap;
|
||
balance.OptionPremiumAndSwapSum = data.OptionPremium + data.OptionPremiumSwap;
|
||
balance.EndPremiumSum = data.EndPremiumSum;
|
||
balance.SettlementBalance = data.SettlementBalance;
|
||
balance.UnwindBalance = data.UnwindBalance;
|
||
balance.ExerciseBalance = data.ExerciseBalance;
|
||
balance.SwapBalance = data.SwapBalance;
|
||
balance.Coupon = data.Coupon;
|
||
balance.CashInCashOutProductChange = data.CashInCashOutProductChange;
|
||
balance.WinLoss = data.WinLoss;
|
||
balance.TradeFee = data.TradeFee;
|
||
balance.InterestPnl = data.InterestPnl;
|
||
//起始时间 有值 和 WinLoss 区分 -- 国投不含当天
|
||
balance.WinLossSum = data.WinLoss;
|
||
balance.FundJson = data.FundJson;
|
||
balance.PFE = data.PFE;
|
||
balance.EAD = data.EAD;
|
||
balance.LastSettlemetTime = endDate <= lastDate ? data.LastSettlemetTime : null;
|
||
balance.LastHTSettlemetTime = lastpushLog == null ? "未同步" : lastpushLog.update_time.ToString("yyyy-MM-dd HH:mm:ss");
|
||
}
|
||
}
|
||
|
||
//--------------------------------------------
|
||
// 期末资金信息(取最新结算日当日信息)
|
||
//--------------------------------------------
|
||
|
||
//当日客户资金
|
||
if (valuedate > lastBalanceDate && lastBalanceDate < endDate)
|
||
{
|
||
var todayClientBalance = new RealTimeClientBanlanceService(OptUserInfo.SystemUser)
|
||
.GetBanlances(clientIdS, startDate > lastBalanceDate ? startDate : lastBalanceDate.AddDays(1), endDate);
|
||
foreach (var data in todayClientBalance)
|
||
{
|
||
data.TdWinLoss = data.WinLoss; //当日实现盈亏
|
||
if (dic.TryGetValue(data.ClientId, out var balance))
|
||
{
|
||
data.NetFund += balance.NetFund;
|
||
data.InFund += balance.InFund;
|
||
data.OutFund += balance.OutFund;
|
||
data.OtherFund += balance.OtherFund;
|
||
data.OptionPremium += balance.OptionPremium;
|
||
data.OptionPremiumSwap += balance.OptionPremiumSwap;
|
||
data.OptionPremiumAndSwapSum += balance.OptionPremium + balance.OptionPremiumSwap;
|
||
data.EndPremiumSum += balance.EndPremiumSum;
|
||
data.SettlementBalance += balance.SettlementBalance;
|
||
data.UnwindBalance += balance.UnwindBalance;
|
||
data.ExerciseBalance += balance.ExerciseBalance;
|
||
data.SwapBalance += balance.SwapBalance;
|
||
data.Coupon += balance.Coupon;
|
||
data.CashInCashOutProductChange += balance.CashInCashOutProductChange;
|
||
data.WinLoss += balance.WinLoss;
|
||
data.TradeFee += balance.TradeFee;
|
||
data.InterestPnl += balance.InterestPnl;
|
||
//data.AvailableStockEqvNotional = balance.AvailableStockEqvNotional;
|
||
data.LastSettlemetTime = balance.LastSettlemetTime;
|
||
data.LastHTSettlemetTime = balance.LastHTSettlemetTime;
|
||
}
|
||
dic[data.ClientId] = data;
|
||
data.UpdateDate = DateTime.Now;
|
||
data.IsLatestDate = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var endQuery = from t in db.ClientBalanceDaily
|
||
join cs in db.client_span.Where(eod_cs => eod_cs.SpanType == ClientSpan.SpanType_Eod) on new { t.ClientId, ValueDate = t.BalanceDate } equals new { cs.ClientId, cs.ValueDate }
|
||
into eodClientSpan
|
||
from cs in eodClientSpan.DefaultIfEmpty()
|
||
|
||
where t.BalanceDate == lastDate
|
||
&& clientIdS.Contains(t.ClientId)
|
||
select new
|
||
{
|
||
ClientId = t.ClientId,
|
||
FreezePremium = t.FrozenPremium ?? 0.0,
|
||
ReceivablesPremium = 0.0,
|
||
AmountFund = t.ToDayRemainFund ?? 0.0,
|
||
GuaranteesTotalAmount = t.TodayRemianFundProduct ?? 0.0,
|
||
//仅用于广期资本可用资金计算
|
||
//可用资金1 = 净入金 + 已实现盈亏 + 浮动盈亏 - 次日最大亏损;
|
||
//可用资金2 = 净入金 + 已实现盈亏 - 持仓期初净支付权利金;
|
||
//可用资金 = min(可用资金1,可用资金2);
|
||
AvailableAmount1 = (t.NetFundSum ?? 0) + (t.WinLossSum ?? 0) + (t.PositionPnl ?? 0) + (cs.WorstCastClientPayable ?? 0),
|
||
AvailableAmount2 = (t.NetFundSum ?? 0) + (t.WinLossSum ?? 0) - (t.OptionPremiumSum ?? 0) - (t.OptionPremiumSwapSum ?? 0),
|
||
AvailableAmount = (t.MarginBalance ?? 0.0) + (t.PayableMargin ?? 0.0) - (t.FrozenMarginMoney ?? 0.0) - (t.TodayRemianFundProduct ?? 0.0),//t.FrozenMarginMoney是通道业务显示所用到的
|
||
TotalCredit = t.Credit ?? 0.0,
|
||
PayableMargin = t.PayableMargin ?? 0.0,
|
||
DeltaMargin = t.DeltaMargin ?? 0d,
|
||
SwapPayableMargin = t.SwapPayableMargin ?? 0.0,
|
||
SwapUnPayableMargin = t.SwapUnPayableMargin ?? 0.0,
|
||
TwoSideMargin = t.TwoSideMargin ?? 0.0,
|
||
OtherSideMargin = t.OtherSideMargin ?? 0.0,
|
||
MySideMargin = t.MySideMargin ?? 0.0,
|
||
MaintenanceMargin = cs.VariationMargin ?? 0.0,
|
||
IsPayableMarginManual = t.IsPayableMarginManual,
|
||
IsPayableMarginLock = cs == null ? false : cs.ModifiedFlag,
|
||
FrozenMarginMoney = t.FrozenMarginMoney ?? 0.0,
|
||
FrozenOutFund = t.FrozenOutFund ?? 0.0,
|
||
MarginBalance = t.MarginBalance ?? 0.0,
|
||
Coupon = t.Coupon ?? 0.0,
|
||
SwapBalance = t.SwapBalance ?? 0.0,
|
||
Margin = t.Margin ?? 0.0,
|
||
//IsTradeCredit = t.IsTradeCredit ?? c.IsTradeCredit == 1,
|
||
TodayNewMargin = 0,
|
||
PositionPv = t.Pv ?? 0,
|
||
RoundedPositionPv = t.RoundedPv ?? 0,
|
||
SellPv = t.SellPv ?? 0,
|
||
PrepaymentAmount = t.PrepaymentAmount ?? 0.0,
|
||
DaliyPnl = t.DailyPnl ?? 0,
|
||
PositionPnl = t.PositionPnl ?? 0,
|
||
RoundedPositionPnl = t.RoundedPositionPnl ?? 0,
|
||
ClientSellPositionPnl = t.ClientSellPositionPnl ?? 0,
|
||
PositionPremiumNetCash = t.PositionPremiumNetCash ?? 0,
|
||
LastDayPositionPremiumNetCash = t.LastDayPositionPremiumNetCash ?? 0,
|
||
SellTradePrice = t.SellTradePrice,
|
||
AvailableStockEqvNotional = t.AvailableStockEqvNotional ?? 0,
|
||
FrozenBalance = t.FrozenBalance ?? 0,
|
||
TdWinLoss = t.WinLoss,
|
||
MarginJson = cs.PVJsons,
|
||
MaintenanceLine = t.MaintenanceLine,
|
||
TotalNominal = t.TotalNominal,
|
||
InFundSum = t.InFundSum,
|
||
OutFundSum = t.OutFundSum,
|
||
VmInFundSum = t.vm_in_fund_sum,
|
||
VmOutFundSum = t.vm_out_fund_sum,
|
||
};
|
||
|
||
var endDatas = endQuery.ToArray();
|
||
|
||
//阶段三 §3.2 估值报告口径输入:已使用授信(授信出入表)、互换初始保证金(应付预付金净额)、
|
||
//交易维度追加保证金合计(Σ(维持−累计),规则15交易)——与实时口径共用同一查询(SwapSpanBalanceQueryService)
|
||
var usedCreditDic = ClientCreditInoutService.GetUsedCreditByClients(clientIdS, db);
|
||
var swapInitMarginDic = SwapSpanBalanceQueryService.GetSwapInitMarginByClients(clientIdS, lastDate, db);
|
||
var swapAdditionalDic = SwapSpanBalanceQueryService.GetTradeAdditionalMarginByClients(clientIdS, lastDate, db);
|
||
|
||
foreach (var data in endDatas)
|
||
{
|
||
if (dic.TryGetValue(data.ClientId, out var balance))
|
||
{
|
||
var client = DataCacheProvider.GetClientDataSource().GetData(data.ClientId);
|
||
|
||
var lasttoDay = EodOperationBase.GetLastSettlementDate(lastDate, true);
|
||
var lastClientBalanceDaily = db.ClientBalanceDaily.Where(a => a.BalanceDate == lasttoDay && a.ClientId == data.ClientId).FirstOrDefault();
|
||
balance.FrozenBalance = data.FrozenBalance;
|
||
balance.FreezePremium = data.FreezePremium;
|
||
balance.ReceivablesPremium = data.ReceivablesPremium;
|
||
balance.AmountFund = data.AmountFund;
|
||
|
||
|
||
balance.TotalCredit = data.TotalCredit;
|
||
balance.PayableMargin = data.PayableMargin;
|
||
balance.GuaranteesTotalAmount = data.GuaranteesTotalAmount;
|
||
balance.FrozenMarginMoney = data.FrozenMarginMoney;
|
||
balance.DaliyPnl = data.DaliyPnl;
|
||
balance.RoundedDaliyPnl = data.RoundedPositionPnl - (lastClientBalanceDaily?.RoundedPositionPnl ?? 0);
|
||
balance.PositionPnl = data.PositionPnl;
|
||
balance.RoundedPositionPnl = data.RoundedPositionPnl;
|
||
balance.DeltaMargin = data.DeltaMargin;
|
||
balance.SwapPayableMargin = data.SwapPayableMargin;
|
||
balance.SwapUnMargin = data.SwapUnPayableMargin;
|
||
balance.TwoSideMargin = data.TwoSideMargin;
|
||
balance.OtherSideMargin = data.OtherSideMargin;
|
||
balance.MySideMargin = data.MySideMargin;
|
||
balance.MaintenanceMargin = data.MaintenanceMargin;
|
||
balance.IsPayableMarginManual = data.IsPayableMarginManual;
|
||
balance.IsPayableMarginLock = data.IsPayableMarginLock;
|
||
balance.FrozenMarginMoney = data.FrozenMarginMoney;
|
||
balance.FrozenOutFund = data.FrozenOutFund;
|
||
balance.MarginBalance = data.MarginBalance;
|
||
balance.Margin = data.Margin;
|
||
balance.UpdateDate = DateTime.Now;
|
||
balance.IsTradeCredit = client?.IsTradeCredit == 1;
|
||
balance.TodayNewMargin = data.TodayNewMargin;
|
||
|
||
balance.PositionPv = data.PositionPv;
|
||
balance.RoundedPositionPv = data.RoundedPositionPv;
|
||
balance.SellPv = data.SellPv;
|
||
balance.PrepaymentAmount = data.PrepaymentAmount;
|
||
balance.ClientSellPositionPnl = data.ClientSellPositionPnl;
|
||
balance.PositionPremiumNetCash = data.PositionPremiumNetCash;
|
||
balance.SellTradePrice = data.SellTradePrice ?? 0;
|
||
balance.LastDayPositionPremiumNetCash = data.LastDayPositionPremiumNetCash;
|
||
balance.MarginOptionType = client?.MarginOptionType ?? 0;
|
||
balance.IsLatestDate = true;
|
||
balance.IsEodData = true;
|
||
balance.TdWinLoss = data.TdWinLoss ?? 0;
|
||
balance.AvailableStockEqvNotional = data.AvailableStockEqvNotional;
|
||
balance.MarginJson = data.MarginJson;
|
||
balance.ClientType = client.SwapTradeType ?? 0;
|
||
balance.ClientName = client.Name;
|
||
balance.MaintenanceLine = data.MaintenanceLine ?? 0;
|
||
balance.PositionNotionalPrincipal = data.TotalNominal ?? 0;
|
||
|
||
balance.OutFundSum = data.OutFundSum ?? 0;
|
||
balance.InFundSum = data.InFundSum ?? 0;
|
||
balance.VmInFundSum = data.VmInFundSum ?? 0;
|
||
balance.VmOutFundSum = data.VmOutFundSum ?? 0;
|
||
//预付金金额=期末结存-初始预付金金额
|
||
balance.MarginBalance = balance.AmountFund - balance.MySideMargin;
|
||
//阶段三 §3.2:已使用授信/互换初始保证金/交易维度追加保证金(估值报告字段与可用资金公式共用输入)
|
||
balance.UsedCredit = usedCreditDic.TryGetValue(data.ClientId, out var usedCredit) ? usedCredit : 0;
|
||
balance.SwapInitMargin = swapInitMarginDic.TryGetValue(data.ClientId, out var swapInit) ? swapInit : 0;
|
||
balance.SwapAdditionalMarginTotal = swapAdditionalDic.TryGetValue(data.ClientId, out var swapAdd) ? swapAdd : 0;
|
||
// 可用资金:配置了追保规则维度的客户按维度分流(R2公式,实时/EOD三处一致);
|
||
// 未配置(MarginWatchRule=NULL,存量客户)维持旧口径:期末结存-追保账户余额
|
||
if (client?.MarginWatchRule == 0)
|
||
{
|
||
balance.AvailableAmount = SwapSpanBalanceCalc.CalcContractDimensionAvailable(
|
||
balance.AmountFund, balance.TotalCredit, balance.UsedCredit, balance.SwapAdditionalMarginTotal);
|
||
}
|
||
else if (client?.MarginWatchRule == 1)
|
||
{
|
||
//维持保证金(净收取为正)= -MySideMargin(client_span 维持保证金反号聚合)
|
||
balance.AvailableAmount = SwapSpanBalanceCalc.CalcClientDimensionAvailable(
|
||
balance.AmountFund, balance.TotalCredit, balance.UsedCredit,
|
||
balance.SwapInitMargin, -balance.MySideMargin);
|
||
}
|
||
else
|
||
{
|
||
balance.AvailableAmount = balance.MarginBalance - (balance.VmInFundSum - balance.VmOutFundSum);
|
||
}
|
||
// 是否追保/追保金额(阶段四 §4.2 按维度分流,允许负值=双向,不以 0 截断):
|
||
// 客户维度(==1)= (维持−初始) − (现金+授信−已使用),负=可返还;
|
||
// 合约维度(==0)= −(现金+授信−已使用)(需求原文公式的应追加方向取值,开放问题2,两值均有产出);
|
||
// 未配置(NULL 存量)维持旧口径:盯市低于维持时 = 初始保证金金额−盯市金额,否则 0
|
||
if (client?.MarginWatchRule == 1)
|
||
{
|
||
balance.MarginByPayableMarginTotal = SwapSpanBalanceCalc.CalcClientDimensionCallMargin(
|
||
balance.AmountFund, balance.TotalCredit, balance.UsedCredit, balance.SwapInitMargin, -balance.MySideMargin);
|
||
balance.NeedAddMargin = balance.MarginByPayableMarginTotal > 0;
|
||
}
|
||
else if (client?.MarginWatchRule == 0)
|
||
{
|
||
balance.MarginByPayableMarginTotal = SwapSpanBalanceCalc.CalcContractDimensionCallMargin(
|
||
balance.AmountFund, balance.TotalCredit, balance.UsedCredit);
|
||
balance.NeedAddMargin = balance.MarginByPayableMarginTotal > 0;
|
||
}
|
||
else
|
||
{
|
||
balance.NeedAddMargin = balance.SwapMarketAmount < balance.MaintenanceMargin;
|
||
balance.MarginByPayableMarginTotal = balance.NeedAddMargin ? (balance.MySideMargin - balance.SwapMarketAmount) : 0;
|
||
}
|
||
// 可取资金=Math.Max(期末结存-min(持仓盈亏,0)-初始保证金,0)
|
||
balance.DesirableFund = Math.Max(balance.MarginBalance + Math.Min(balance.RoundedPositionPnl, 0), 0);
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
//--------------------------------------------
|
||
//对出入金,权利金,结算收支,实现盈亏,抵押品变化区间段sum处理
|
||
//例如2018-08-08到2019-08-08:区间段sum值 = sum(2019-08-08) - sum(2018-08-07)
|
||
//--------------------------------------------
|
||
|
||
if (startDate <= lastBalanceDate)
|
||
{
|
||
//默认期初结存为0
|
||
foreach (var balance1 in dic.Values)
|
||
{
|
||
balance1.LastDayRemainFund = 0;
|
||
balance1.LastDayRemainFundWithProduct = 0;
|
||
balance1.LastGuaranteesTotalAmount = 0;
|
||
balance1.LastDayPositionPremiumNetCash = 0;
|
||
}
|
||
|
||
//该判断代表起始时间是选择了的,而不是空,需要区间逻辑处理
|
||
if (startDate.Year > 2008)
|
||
{
|
||
var query = from t in db.ClientBalanceDaily
|
||
where t.BalanceDate >= startDate && t.BalanceDate <= endDate
|
||
&& clientIdS.Contains(t.ClientId)
|
||
group t by t.ClientId into g
|
||
select new
|
||
{
|
||
ClientId = g.Key,
|
||
BalanceDate = g.Min(n => n.BalanceDate)
|
||
};
|
||
|
||
var startQuery = from t in db.ClientBalanceDaily
|
||
join t2 in query on new { t.ClientId, t.BalanceDate } equals new { t2.ClientId, t2.BalanceDate }
|
||
select new
|
||
{
|
||
ClientId = t.ClientId,
|
||
LastDayRemainFund = t.LastDayRemainFund ?? 0,
|
||
TodayRemianFundProduct = t.TodayRemianFundProduct ?? 0,
|
||
CashInCashOutProductChange = t.CashInCashOutProductChange ?? 0,
|
||
LastDayPositionPremiumNetCash = t.LastDayPositionPremiumNetCash ?? 0,
|
||
|
||
//此处取上一日的sum,例如sum(2018-08-07)
|
||
NetFundSum = (t.NetFundSum ?? 0) - (t.NetFund ?? 0),
|
||
InFundSum = (t.InFundSum ?? 0) - (t.InFund ?? 0),
|
||
OutFundSum = (t.OutFundSum ?? 0) - (t.OutFund ?? 0),
|
||
OtherFundSum = (t.OtherFundSum ?? 0) - (t.OtherFund ?? 0),
|
||
OptionPremiumSum = (t.OptionPremiumSum ?? 0) - (t.OptionPremium ?? 0),
|
||
OptionPremiumSwapSum = (t.OptionPremiumSwapSum ?? 0) - (t.OptionPremiumSwap ?? 0),
|
||
SettlementBalanceSum = (t.SettlementBalanceSum ?? 0) - (t.SettlementBalance ?? 0),
|
||
UnwindBalanceSum = (t.UnwindBalanceSum ?? 0) - (t.UnwindBalance ?? 0),
|
||
ExerciseBalanceSum = (t.ExerciseBalanceSum ?? 0) - (t.ExerciseBalance ?? 0),
|
||
SwapBalanceSum = (t.SwapBalanceSum ?? 0) - (t.SwapBalance ?? 0),
|
||
CouponSum = (t.CouponSum ?? 0) - (t.Coupon ?? 0),
|
||
WinLossSum = (t.WinLossSum ?? 0) - (t.WinLoss ?? 0),
|
||
CashInCashOutProductChangeSum = (t.CashInCashOutProductChange ?? 0) - (t.CashInCashOutProductChange ?? 0),
|
||
};
|
||
|
||
var startDatas = startQuery.ToArray();
|
||
|
||
foreach (var data in startDatas)
|
||
{
|
||
if (dic.TryGetValue(data.ClientId, out var balance))
|
||
{
|
||
balance.LastDayRemainFund = data.LastDayRemainFund;
|
||
balance.LastDayRemainFundWithProduct = data.LastDayRemainFund + data.TodayRemianFundProduct - data.CashInCashOutProductChange;
|
||
balance.LastGuaranteesTotalAmount = data.TodayRemianFundProduct - data.CashInCashOutProductChange;
|
||
balance.LastDayPositionPremiumNetCash = data.LastDayPositionPremiumNetCash;
|
||
|
||
//例如2018-08-08到2019-08-08:区间段sum值 = sum(2019-08-08) - sum(2018-08-07)
|
||
balance.NetFund -= data.NetFundSum;
|
||
balance.InFund -= data.InFundSum;
|
||
balance.OutFund -= data.OutFundSum;
|
||
balance.OtherFund -= data.OtherFundSum;
|
||
balance.OptionPremium -= data.OptionPremiumSum;
|
||
balance.OptionPremiumSwap -= data.OptionPremiumSwapSum;
|
||
balance.OptionPremiumAndSwapSum -= data.OptionPremiumSum + data.OptionPremiumSwapSum;
|
||
balance.SettlementBalance -= data.SettlementBalanceSum;
|
||
balance.UnwindBalance -= data.UnwindBalanceSum;
|
||
balance.ExerciseBalance -= data.ExerciseBalanceSum;
|
||
balance.SwapBalance -= data.SwapBalanceSum;
|
||
balance.Coupon -= data.CouponSum;
|
||
balance.CashInCashOutProductChange -= data.CashInCashOutProductChangeSum;
|
||
balance.WinLoss -= data.WinLossSum;
|
||
balance.WinLossSum -= balance.WinLoss;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
var gapList = db.ClientBalanceGap.Where(c => clientIdS.Contains(c.ClientId) && c.ValueDate == endDate).ToList();
|
||
gapList ??= new List<ClientBalanceGap>();
|
||
|
||
if (IsClientBalanceGap || IsGetOuterMarginGap)
|
||
{
|
||
var ClientBalanceGap = new ClientBalanceGap();
|
||
foreach (var item in dic.Values)
|
||
{
|
||
if (IsClientBalanceGap)
|
||
{
|
||
ClientBalanceGap = gapList.FirstOrDefault(c => c.ClientId == item.ClientId && c.ValueDate == endDate && !c.IsImportOuterMargin);
|
||
}
|
||
if (IsGetOuterMarginGap)
|
||
{
|
||
ClientBalanceGap = gapList.FirstOrDefault(c => c.ClientId == item.ClientId && c.ValueDate == endDate && c.IsImportOuterMargin);
|
||
}
|
||
if (ClientBalanceGap != null)
|
||
{
|
||
if (IsClientBalanceGap)
|
||
{
|
||
|
||
item.ClientBalanceGap = ClientBalanceGap;
|
||
item.IsGap = true;
|
||
|
||
item.AmountFund += ClientBalanceGap.ToDayRemainFund ?? 0;
|
||
item.AvailableAmount += (ClientBalanceGap.ToDayRemainFund ?? 0) - (ClientBalanceGap.PayableMargin ?? 0);
|
||
item.NetFund += ClientBalanceGap.NetFund ?? 0;
|
||
item.OptionPremium += ClientBalanceGap.OptionPremium ?? 0;
|
||
item.OptionPremiumSwap += ClientBalanceGap.OptionPremiumSwap ?? 0;
|
||
|
||
item.OptionPremiumAndSwapSum += ClientBalanceGap.OptionPremium ?? 0;
|
||
item.OptionPremiumAndSwapSum += ClientBalanceGap.OptionPremiumSwap ?? 0;
|
||
|
||
item.SettlementBalance += ClientBalanceGap.SettlementBalance ?? 0;
|
||
item.Coupon += ClientBalanceGap.Coupon ?? 0;
|
||
item.SwapBalance += ClientBalanceGap.SwapBalance ?? 0;
|
||
item.OtherFund += ClientBalanceGap.OtherFund ?? 0;
|
||
item.TotalCredit += ClientBalanceGap.Credit ?? 0;
|
||
//if (ClientBalanceGap.PayableFund != null && ClientBalanceGap.PayableFund != 0)
|
||
//{
|
||
// item.PayableFund += ClientBalanceGap.PayableFund ?? 0;
|
||
//}
|
||
//else
|
||
//{
|
||
// item.MarginByPayableMargin += ClientBalanceGap.MarginByPayableMargin ?? 0;
|
||
//}
|
||
item.WinLoss += ClientBalanceGap.WinLoss ?? 0;
|
||
item.PositionPnl += ClientBalanceGap.PositionPnl ?? 0;
|
||
item.RoundedPositionPnl += ClientBalanceGap.PositionPnl ?? 0;
|
||
item.PositionPv += ClientBalanceGap.PositionPv ?? 0;
|
||
item.RoundedPositionPv += ClientBalanceGap.PositionPv ?? 0;
|
||
}
|
||
if (IsGetOuterMarginGap)
|
||
{
|
||
item.ClientBalanceGap = ClientBalanceGap;
|
||
//(ClientBalanceGap.PayableMargin ?? 0)正数代表客户应付预付金
|
||
//item.PayableMargin负数代表客户应付预付金
|
||
//(ClientBalanceGap.PayableMargin ?? 0) + item.PayableMargin代表客户支付预付金的差额
|
||
item.AvailableAmount += (ClientBalanceGap.ToDayRemainFund ?? 0) - ((ClientBalanceGap.PayableMargin ?? 0) + item.PayableMargin);
|
||
item.IsGap = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//return dic.Values;
|
||
}
|
||
|
||
using (var clientDB = new ClientDBContext())
|
||
{
|
||
var balance1 = dic[returnClientId];
|
||
if (!clientDB.client_Axis_Fundthresholds.Where(x => x.ClientId == returnClientId).Any() || endDate == DateTime.Today)
|
||
{
|
||
balance1.FundThreshold = clientDB.client.Where(n => n.id == returnClientId).Select(n => n.FundThreshold).FirstOrDefault();
|
||
}
|
||
else
|
||
{
|
||
balance1.FundThreshold = clientDB.client_Axis_Fundthresholds.Where(x => x.ValueDate <= endDate && x.ClientId == returnClientId).OrderByDescending(x => x.ValueDate)?.FirstOrDefault()?.FundThreshold;
|
||
}
|
||
}
|
||
|
||
if (clientDataSource != null)
|
||
{
|
||
foreach (var item in dic.Values)
|
||
{
|
||
var client = clientDataSource.GetData(item.ClientId);
|
||
item.ClientNumber = client?.Number;
|
||
item.ClientName = client?.Name;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
foreach (var item in dic.Values)
|
||
{
|
||
var client = DataCacheProvider.GetClientDataSource().GetData(item.ClientId);
|
||
item.ClientNumber = client?.Number;
|
||
item.ClientName = client?.Name;
|
||
}
|
||
}
|
||
if (dic.Values != null && dic.Values.Count > 0)
|
||
{
|
||
if (PS.Config.Is宏源 || PS.Config.Company == Configuration.CompanyEnum.广发商贸)
|
||
{
|
||
//宏源 二次计算预付金占用及相关数据
|
||
//var clientIds = new List<int>();
|
||
|
||
//foreach (var item in dic.Values)
|
||
//{
|
||
// clientIds.Add(item.ClientId);
|
||
//}
|
||
|
||
var marginFactorDict = new ClientMarginTemplateService(OptUserInfo.SystemUser).GetMarginFactorDict(endDate, clientIdList, true);
|
||
dic.Values.ToList().ForEach(p => p.ReCaculatePayableMargin(p.ClientId, marginFactorDict));
|
||
}
|
||
}
|
||
//当是单一客户的时候,或者包含子级 执行新的字段返回,其他来源使用原来字段
|
||
if (ParentFlag || clientIdList.Count() == 1)
|
||
{
|
||
var DicTotal = dic[returnClientId];
|
||
#region 循环统计所有客户
|
||
foreach (var dc in dic)
|
||
{
|
||
#region 所有客户数据进行累加
|
||
if (dc.Key == returnClientId)
|
||
{
|
||
DicTotal.OptionPremiumAndUnwindBalanceTotal = DicTotal.OptionPremiumAndUnwindBalance;
|
||
DicTotal.MinusPayableMarginTotal = DicTotal.MinusPayableMargin;
|
||
DicTotal.TotalMarginTotal = DicTotal.TotalMargin;
|
||
DicTotal.RoundedTotalAmountTotal = DicTotal.RoundedTotalAmount;
|
||
DicTotal.TotalAmountTotal = DicTotal.TotalAmount;
|
||
DicTotal.MarginByPayableMarginTotal = DicTotal.MarginByPayableMarginTotal;
|
||
//if (PS.Config.Is广期资本)
|
||
//{
|
||
// DicTotal.MarginByPayableMarginTotal = Math.Max(-DicTotal.AvailableAmount, 0);
|
||
//}
|
||
|
||
DicTotal.ClosedTradePayableFundTotal = DicTotal.ClosedTradePayableFund;
|
||
DicTotal.PositionTradePayableFundTotal = DicTotal.PositionTradePayableFund;
|
||
DicTotal.PayableFundTotal = DicTotal.PayableFund;
|
||
DicTotal.DesirableFundTotal = DicTotal.DesirableFund;
|
||
DicTotal.TotalNetSettlementTotal = DicTotal.TotalNetSettlement;
|
||
DicTotal.IsLatestDate = true;
|
||
continue;
|
||
}
|
||
DicTotal.SettlementBalance += dc.Value.SettlementBalance;
|
||
DicTotal.LastDayRemainFund += dc.Value.LastDayRemainFund;
|
||
DicTotal.NetFund += dc.Value.NetFund;
|
||
DicTotal.InFund += dc.Value.InFund;
|
||
DicTotal.OutFund += dc.Value.OutFund;
|
||
DicTotal.OptionPremium += dc.Value.OptionPremium;
|
||
DicTotal.OptionPremiumSwap += dc.Value.OptionPremiumSwap;
|
||
DicTotal.OptionPremiumAndSwapSum += dc.Value.OptionPremiumAndSwapSum;
|
||
DicTotal.OtherFund += dc.Value.OtherFund;
|
||
DicTotal.Coupon += dc.Value.Coupon;
|
||
DicTotal.SwapBalance += dc.Value.SwapBalance;
|
||
DicTotal.OptionPremiumAndUnwindBalanceTotal += dc.Value.OptionPremiumAndUnwindBalance;
|
||
DicTotal.ExerciseBalance += dc.Value.ExerciseBalance;
|
||
DicTotal.AmountFund += dc.Value.AmountFund;
|
||
DicTotal.GuaranteesTotalAmount += dc.Value.GuaranteesTotalAmount;
|
||
|
||
DicTotal.MinusPayableMarginTotal += dc.Value.MinusPayableMargin;
|
||
|
||
DicTotal.AvailableAmount += dc.Value.AvailableAmount;
|
||
DicTotal.TotalMarginTotal += dc.Value.TotalMargin;
|
||
DicTotal.TotalCredit += dc.Value.TotalCredit;
|
||
DicTotal.WinLoss += dc.Value.WinLoss;
|
||
DicTotal.TdWinLoss += dc.Value.TdWinLoss;
|
||
DicTotal.PositionPremiumNetCash += dc.Value.PositionPremiumNetCash;
|
||
|
||
DicTotal.RoundedPositionPv += dc.Value.RoundedPositionPv;
|
||
DicTotal.PositionPv += dc.Value.PositionPv;
|
||
|
||
DicTotal.RoundedPositionPnl += dc.Value.RoundedPositionPnl;
|
||
DicTotal.PositionPnl += dc.Value.PositionPnl;
|
||
|
||
DicTotal.RoundedTotalAmountTotal += dc.Value.RoundedTotalAmount;
|
||
DicTotal.TotalAmountTotal += dc.Value.TotalAmount;
|
||
|
||
DicTotal.MarginByPayableMarginTotal += dc.Value.MarginByPayableMarginTotal;
|
||
|
||
DicTotal.ClosedTradePayableFundTotal += dc.Value.ClosedTradePayableFund;
|
||
DicTotal.PositionTradePayableFundTotal += dc.Value.PositionTradePayableFund;
|
||
DicTotal.PayableFundTotal += dc.Value.PayableFund;
|
||
DicTotal.DesirableFundTotal += dc.Value.DesirableFund;
|
||
DicTotal.SellTradePrice += dc.Value.SellTradePrice;
|
||
DicTotal.ClientSellPositionPnl += dc.Value.ClientSellPositionPnl;
|
||
DicTotal.TotalNetSettlementTotal += dc.Value.TotalNetSettlement;
|
||
|
||
DicTotal.MarginBalance += dc.Value.MarginBalance;
|
||
DicTotal.FrozenMarginMoney += dc.Value.FrozenMarginMoney;
|
||
DicTotal.FrozenRedeemFunds += dc.Value.FrozenRedeemFunds;
|
||
//DicTotal.FundThreshold += dc.Value.FundThreshold;
|
||
#endregion
|
||
}
|
||
#endregion
|
||
}
|
||
|
||
return dic.Values;
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取历史交易中追保金额不为0的客户ids(排除对系统日实时的数据的筛选)
|
||
/// </summary>
|
||
/// <param name="searchDate"></param>
|
||
/// <returns></returns>
|
||
public static List<int> GetHaveMarginAmount(DateTime searchDate, string MarginShownType = "default")
|
||
{
|
||
//获取根据系统时间
|
||
var lastDate = searchDate;// EodOperationBase.GetLastSettlementDate(DateTime.Now.Date);
|
||
var clientlist = new List<int>();
|
||
var baseQuery = new List<Pairs>();
|
||
using var db = new YLContext();
|
||
switch (MarginShownType)
|
||
{
|
||
case "default":
|
||
baseQuery = (from t in db.ClientBalanceDaily
|
||
where t.BalanceDate == lastDate
|
||
select new Pairs
|
||
{
|
||
tdaily = t,
|
||
tgap = null
|
||
}).ToList();
|
||
break;
|
||
case "ClientBalanceGap":
|
||
baseQuery = (from t in db.ClientBalanceDaily
|
||
where t.BalanceDate == lastDate
|
||
join tgap in db.ClientBalanceGap.Where(o => !o.IsImportOuterMargin && o.ValueDate == lastDate)
|
||
on new { t.ClientId, date = t.BalanceDate ?? DateTime.MinValue }
|
||
equals new { tgap.ClientId, date = tgap.ValueDate } into tempTgap
|
||
from tgap in tempTgap.DefaultIfEmpty()
|
||
select new Pairs
|
||
{
|
||
tdaily = t,
|
||
tgap = tgap
|
||
}).ToList();
|
||
break;
|
||
case "GetOuterMargin":
|
||
baseQuery = (from t in db.ClientBalanceDaily
|
||
where t.BalanceDate == lastDate
|
||
join tgap in db.ClientBalanceGap.Where(o => o.IsImportOuterMargin && o.ValueDate == lastDate)
|
||
on new { t.ClientId, date = t.BalanceDate ?? DateTime.MinValue }
|
||
equals new { tgap.ClientId, date = tgap.ValueDate } into tempTgap
|
||
from tgap in tempTgap.DefaultIfEmpty()
|
||
select new Pairs
|
||
{
|
||
tdaily = t,
|
||
tgap = tgap
|
||
}).ToList();
|
||
break;
|
||
|
||
}
|
||
if (PS.Config.Is广期资本)
|
||
{
|
||
//同业客户:期末结存+持仓盈亏-冻结+授信+质押市值<0,追保
|
||
//非同业客户:期末结存 + 持仓盈亏 - 预付金占用 - 冻结 + 授信 + 质押市值 < 0,追保
|
||
|
||
if (baseQuery == null || baseQuery.Count == 0)
|
||
{
|
||
return clientlist;
|
||
}
|
||
|
||
var clientIds = baseQuery.Select(p => p.tdaily.ClientId).Distinct().ToList();
|
||
//List<ClientSamePeerDto> samePeerList = null;
|
||
Dictionary<int, int?> samePeerDic = null;
|
||
using (var clientDb = DbContextFactory.GetClientDbContext(null))
|
||
{
|
||
samePeerDic = clientDb.client.AsNoTracking().Where(p => clientIds.Contains(p.id)).ToDictionary(p => p.id, p => p.SamePeer);
|
||
}
|
||
samePeerDic ??= new Dictionary<int, int?>();
|
||
foreach (var t in baseQuery)
|
||
{
|
||
var clientId = t.tdaily.ClientId;
|
||
var clientSettleBalance = new ClientSettleBalance
|
||
{
|
||
AmountFund = t.tdaily.ToDayRemainFund ?? 0.0,
|
||
GuaranteesTotalAmount = t.tdaily.TodayRemianFundProduct ?? 0.0,
|
||
PositionPnl = t.tdaily.PositionPnl ?? 0.0,
|
||
FreezePremium = t.tdaily.FrozenPremium ?? 0.0,
|
||
FrozenOutFund = t.tdaily.FrozenOutFund ?? 0.0,
|
||
FrozenRedeemFunds = t.tdaily.FrozenRedeemFunds ?? 0.0,
|
||
FrozenMarginMoney = t.tdaily.FrozenMarginMoney ?? 0.0,
|
||
TotalCredit = t.tdaily.Credit ?? 0.0,
|
||
PayableMargin = t.tdaily.PayableMargin ?? 0.0,
|
||
PositionPremiumNetCash = t.tdaily.PositionPremiumNetCash ?? 0.0,
|
||
};
|
||
|
||
if (t.tgap != null)
|
||
{
|
||
clientSettleBalance.ClientBalanceGap = t.tgap;
|
||
clientSettleBalance.IsGap = true;
|
||
}
|
||
clientSettleBalance.SamePeer = samePeerDic.ContainsKey(clientId) ? samePeerDic[clientId] ?? 0 : 0;
|
||
|
||
if (clientSettleBalance.OtherMarginByPayableMargin < 0)
|
||
{
|
||
clientlist.Add(clientId);
|
||
}
|
||
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//-PayableMargin - Math.Max(AmountFund + ClosedTradePayableFund + PositionTradePayableFund, 0) - GuaranteesTotalAmount - TotalCredit
|
||
//ClosedTradePayableFund: -1 * Math.Min(AmountFund + PositionPremiumNetCash, 0)
|
||
//PositionTradePayableFund: Math.Max(PositionPremiumNetCash - Math.Max(AmountFund + PositionPremiumNetCash, 0), 0)
|
||
|
||
foreach (var t in baseQuery)
|
||
{
|
||
var clientId = t.tdaily.ClientId;
|
||
double MarginPayableMargin = 0;
|
||
if (t.tgap != null)
|
||
{
|
||
if (t.tgap.MarginByPayableMargin != null && t.tgap.MarginByPayableMargin != 0)
|
||
{
|
||
MarginPayableMargin = -(t.tdaily.PayableMargin ?? 0.0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0)
|
||
- Math.Min((t.tdaily.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0), 0)
|
||
+ Math.Max((t.tdaily.PositionPremiumNetCash ?? 0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0), 0), 0), 0)
|
||
- (t.tdaily.TodayRemianFundProduct ?? 0.0)
|
||
- (t.tdaily.Credit ?? 0.0)
|
||
+ (t.tgap.MarginByPayableMargin ?? 0);
|
||
}
|
||
else
|
||
{
|
||
MarginPayableMargin = -((t.tdaily.PayableMargin ?? 0.0) - (t.tgap.PayableMargin ?? 0))
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0)
|
||
- Math.Min((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0), 0)
|
||
+ Math.Max((t.tdaily.PositionPremiumNetCash ?? 0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0), 0), 0), 0)
|
||
- ((t.tdaily.TodayRemianFundProduct ?? 0.0) + (t.tgap.ToDayRemainFund ?? 0))
|
||
- ((t.tdaily.Credit ?? 0.0) + (t.tgap.Credit ?? 0));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
MarginPayableMargin = -(t.tdaily.PayableMargin ?? 0.0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0)
|
||
- Math.Min((t.tdaily.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0), 0)
|
||
+ Math.Max((t.tdaily.PositionPremiumNetCash ?? 0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0), 0), 0), 0)
|
||
- (t.tdaily.TodayRemianFundProduct ?? 0.0)
|
||
- (t.tdaily.Credit ?? 0.0);
|
||
}
|
||
if (MarginPayableMargin > 1e-3)
|
||
{
|
||
clientlist.Add(clientId);
|
||
}
|
||
}
|
||
}
|
||
return clientlist;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前客户中总资产小于1的客户ids(排除对系统日实时的数据的筛选)
|
||
/// </summary>
|
||
public static List<int> GetTotalAssetClientIds(DateTime value)
|
||
{
|
||
List<int> result = null;
|
||
using (var db = new YLContext())
|
||
{
|
||
var tempList = db.ClientBalanceDaily.Where(O => O.BalanceDate == value).AsEnumerable();
|
||
if (PS.Config.IsPVRounded)
|
||
{
|
||
result = tempList.Where(O => (O.RoundedTotalAmount ?? 0) > 1).Select(O => O.ClientId).ToList();
|
||
}
|
||
else
|
||
{
|
||
result = tempList.Where(O => (O.TotalAmount ?? 0) > 1).Select(O => O.ClientId).ToList();
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取历史交易中应付资金总额不为0的客户ids(排除对系统日实时的数据的筛选)
|
||
/// </summary>
|
||
public static List<int> GetHavePayableFund(DateTime searchDate, string MarginShownType = "default")
|
||
{
|
||
//获取根据系统时间
|
||
var lastDate = searchDate;// EodOperationBase.GetLastSettlementDate(DateTime.Now.Date);
|
||
using var db = new YLContext();
|
||
var clientlist = new List<int>();
|
||
var baseQuery = new List<Pairs>();
|
||
switch (MarginShownType)
|
||
{
|
||
case "default":
|
||
baseQuery = (from t in db.ClientBalanceDaily
|
||
where t.BalanceDate == lastDate
|
||
select new Pairs
|
||
{
|
||
tdaily = t,
|
||
tgap = null
|
||
}).ToList();
|
||
break;
|
||
case "ClientBalanceGap":
|
||
baseQuery = (from t in db.ClientBalanceDaily
|
||
where t.BalanceDate == lastDate
|
||
join tgap in db.ClientBalanceGap.Where(o => !o.IsImportOuterMargin && o.ValueDate == lastDate)
|
||
on new { t.ClientId, date = t.BalanceDate ?? DateTime.MinValue }
|
||
equals new { tgap.ClientId, date = tgap.ValueDate } into tempTgap
|
||
from tgap in tempTgap.DefaultIfEmpty()
|
||
select new Pairs
|
||
{
|
||
tdaily = t,
|
||
tgap = tgap
|
||
}).ToList();
|
||
break;
|
||
case "GetOuterMargin":
|
||
baseQuery = (from t in db.ClientBalanceDaily
|
||
where t.BalanceDate == lastDate
|
||
join tgap in db.ClientBalanceGap.Where(o => o.IsImportOuterMargin && o.ValueDate == lastDate)
|
||
on new { t.ClientId, date = t.BalanceDate ?? DateTime.MinValue }
|
||
equals new { tgap.ClientId, date = tgap.ValueDate } into tempTgap
|
||
from tgap in tempTgap.DefaultIfEmpty()
|
||
select new Pairs
|
||
{
|
||
tdaily = t,
|
||
tgap = tgap
|
||
}).ToList();
|
||
break;
|
||
}
|
||
|
||
foreach (var t in baseQuery)
|
||
{
|
||
var ClientId = t.tdaily.ClientId;
|
||
double PayableFund = 0;
|
||
if (t.tgap != null)
|
||
{
|
||
if (t.tgap.PayableFund != null && t.tgap.PayableFund != 0)
|
||
{
|
||
PayableFund = Math.Max(
|
||
(-Math.Min((t.tdaily.ToDayRemainFund + t.tdaily.PositionPremiumNetCash) ?? 0, 0))
|
||
+ Math.Max((t.tdaily.PositionPremiumNetCash ?? 0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0)
|
||
, 0)
|
||
, 0)
|
||
+ Math.Max(-(t.tdaily.PayableMargin ?? 0.0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0)
|
||
- Math.Min((t.tdaily.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0)
|
||
, 0)
|
||
+ Math.Max((t.tdaily.PositionPremiumNetCash ?? 0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0)
|
||
, 0)
|
||
, 0)
|
||
, 0)
|
||
- (t.tdaily.TodayRemianFundProduct ?? 0.0)
|
||
- (t.tdaily.Credit ?? 0.0), 0)
|
||
, 0)
|
||
+ (t.tgap == null ? 0 : t.tgap.PayableFund ?? 0);
|
||
}
|
||
else
|
||
{
|
||
PayableFund = Math.Max(
|
||
(-Math.Min(((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0) + t.tdaily.PositionPremiumNetCash) ?? 0, 0))
|
||
+ Math.Max((t.tdaily.PositionPremiumNetCash ?? 0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0)
|
||
, 0)
|
||
, 0)
|
||
+ Math.Max(-((t.tdaily.PayableMargin ?? 0.0) - (t.tgap.PayableMargin ?? 0))
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0)
|
||
- Math.Min((t.tdaily.ToDayRemainFund ?? 0) + (t.tgap.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0)
|
||
, 0)
|
||
+ Math.Max((t.tdaily.PositionPremiumNetCash ?? 0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0 + (t.tgap.ToDayRemainFund ?? 0))
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0)
|
||
, 0)
|
||
, 0)
|
||
, 0)
|
||
- (t.tdaily.TodayRemianFundProduct ?? 0.0)
|
||
- ((t.tdaily.Credit ?? 0.0) + (t.tgap.Credit ?? 0)), 0)
|
||
, 0);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PayableFund = Math.Max(
|
||
(-Math.Min((t.tdaily.ToDayRemainFund + t.tdaily.PositionPremiumNetCash) ?? 0, 0))
|
||
+ Math.Max((t.tdaily.PositionPremiumNetCash ?? 0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0)
|
||
, 0)
|
||
, 0)
|
||
+ Math.Max(-(t.tdaily.PayableMargin ?? 0.0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0)
|
||
- Math.Min((t.tdaily.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0)
|
||
, 0)
|
||
+ Math.Max((t.tdaily.PositionPremiumNetCash ?? 0)
|
||
- Math.Max((t.tdaily.ToDayRemainFund ?? 0)
|
||
+ (t.tdaily.PositionPremiumNetCash ?? 0)
|
||
, 0)
|
||
, 0)
|
||
, 0)
|
||
- (t.tdaily.TodayRemianFundProduct ?? 0.0)
|
||
- (t.tdaily.Credit ?? 0.0), 0)
|
||
, 0);
|
||
|
||
}
|
||
if (PayableFund > 1)
|
||
{
|
||
clientlist.Add(ClientId);
|
||
}
|
||
}
|
||
return clientlist;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 对传入的客户进行指定日期有持仓记录的筛选(排除对系统日实时的数据的筛选)
|
||
/// </summary>
|
||
public static List<int> GetHavePositionClientIds(DateTime searchDate)
|
||
{
|
||
using var db = new YLContext();
|
||
var query = from eodpos in db.eod_trade_position
|
||
where eodpos.ValueDate == searchDate
|
||
&& eodpos.ClientId > 0
|
||
&& eodpos.TradeId > 0
|
||
select eodpos.ClientId;
|
||
return query.Distinct().ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 进行指定日期应付了结交易款是否大于1元的筛选(排除对系统日实时的数据的筛选)
|
||
/// </summary>
|
||
public static List<int> GetClosePayableFundClientIds(DateTime searchDate, string MarginShownType = "default")
|
||
{
|
||
using var db = new YLContext();
|
||
var clientlist = new List<int>();
|
||
var baseQuery = (from t in db.ClientBalanceDaily
|
||
where t.BalanceDate == searchDate
|
||
select t.ClientId).Distinct().ToList();
|
||
|
||
var IsGap = false;
|
||
var IsOuter = false;
|
||
if (MarginShownType == "ClientBalanceGap")
|
||
{
|
||
IsGap = true;
|
||
}
|
||
if (MarginShownType == "GetOuterMargin")
|
||
{
|
||
IsOuter = true;
|
||
}
|
||
|
||
var balances = GetClientBanlances(baseQuery, searchDate, searchDate, IsGap, IsOuter);
|
||
|
||
foreach (var item in balances)
|
||
{
|
||
if (item.ClosedTradePayableFund >= 1)
|
||
{
|
||
clientlist.Add(item.ClientId);
|
||
}
|
||
}
|
||
return clientlist;
|
||
}
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
public static IEnumerable<ClientSettleBalance> GetClientRiskMonitor(List<int> clientIdList, DateTime searchDate, string marginShownType)
|
||
{
|
||
if (null == clientIdList || !clientIdList.Any())
|
||
{
|
||
return null;
|
||
}
|
||
|
||
//获取根据系统时间
|
||
var lastBalanceDate = EodOperationBase.GetLastSettlementDate(DateTime.Now.Date);
|
||
//系统交易日
|
||
var valuedate = valuedateBLL.ValueDate;
|
||
|
||
using var db = new YLContext();
|
||
var IsGap = false;
|
||
var IsOuter = false;
|
||
if (marginShownType == "ClientBalanceGap")
|
||
{
|
||
IsGap = true;
|
||
}
|
||
if (marginShownType == "GetOuterMargin")
|
||
{
|
||
IsOuter = true;
|
||
}
|
||
//db.SetDebugLog();
|
||
var lastClientBalances = GetClientBanlances(clientIdList, DateTime.MinValue, searchDate, IsGap, IsOuter);
|
||
|
||
//历史查询,部分交易信息重新计算
|
||
if (valuedate <= lastBalanceDate || valuedate > searchDate)
|
||
{
|
||
//----------------------------------------
|
||
// 所有交易合计
|
||
//----------------------------------------
|
||
|
||
var allTradeQuery = from t in db.trade
|
||
where t.TradeDate <= searchDate
|
||
&& t.ValidState != "InValid"
|
||
&& (t.TradeType != "结构化交易" || t.IsGroup == 1) && t.IsGroup != 2
|
||
&& clientIdList.Contains(t.ClientId)
|
||
&& ConsTrade.TradeStatusAfterConfirmed.Contains(t.TradeStatus)
|
||
select new
|
||
{
|
||
t.ClientId,
|
||
OriginalStockEqvNotional = t.OriginalStockEqvNotional > 0 ? t.OriginalStockEqvNotional.Value :
|
||
(t.SpotPrice ?? 0.0) * (t.OriginalNotional ?? 0),
|
||
BuyCount = t.BuySell == "买入" ? 0 : 1,//从客户角度看
|
||
SellCount = t.BuySell == "卖出" ? 0 : 1,//从客户角度看
|
||
TodayCount = t.TradeDate == searchDate ? 1 : 0
|
||
};
|
||
|
||
var allTradeQuerySum = from t in allTradeQuery
|
||
group t by t.ClientId into g
|
||
select new
|
||
{
|
||
ClientId = g.Key,
|
||
SellNotionalPrincipal = g.Sum(a => a.SellCount * a.OriginalStockEqvNotional),
|
||
BuyNotionalPrincipal = g.Sum(a => a.BuyCount * a.OriginalStockEqvNotional),
|
||
BuyCount = g.Sum(n => n.BuyCount),
|
||
SellCount = g.Sum(n => n.SellCount),
|
||
TodayCount = g.Sum(n => n.TodayCount),
|
||
TodayNotionalPrincipal = g.Sum(n => n.TodayCount * n.OriginalStockEqvNotional)
|
||
};
|
||
|
||
var tradeSumDic = allTradeQuerySum.ToDictionary(n => n.ClientId);
|
||
|
||
//----------------------------------------
|
||
// 交易结算预付金统计
|
||
//----------------------------------------
|
||
|
||
//组合交易和结构化交易获取的是父亲交易(不包含子交易)
|
||
var tradeOriginQuery = from x in db.trade
|
||
where x.ParentTradeId == 0
|
||
&& x.ValidState != ConsGlobal.InValid
|
||
select x;
|
||
|
||
var eodTradePositionQuery = from eodTradePosition in db.eod_trade_position
|
||
where eodTradePosition.ValueDate == searchDate &&
|
||
clientIdList.Contains(eodTradePosition.ClientId)
|
||
select eodTradePosition;
|
||
|
||
//组合交易和结构化交易获取的是父亲交易(不包含子交易)
|
||
var eodTradeQuery = from eodTrade in db.eod_trade
|
||
join tradeOrigin in tradeOriginQuery on eodTrade.TradeId equals tradeOrigin.id
|
||
where eodTrade.ValueDate == searchDate
|
||
&& clientIdList.Contains(eodTrade.ClientId)
|
||
&& ConsTrade.NeedMarginTradeStatusList.Contains(eodTrade.TradeStatus)
|
||
select new { eodTrade.TradeId, et = new xodTradeBase() { TradeJson = eodTrade.TradeJson } };
|
||
|
||
var positionQuery = from eodTradePosition in eodTradePositionQuery
|
||
join eodTrade in db.eod_trade on eodTradePosition.TradeId equals eodTrade.TradeId
|
||
where eodTrade.ValueDate == searchDate
|
||
&& clientIdList.Contains(eodTrade.ClientId)
|
||
&& ConsTrade.NeedMarginTradeStatusList.Contains(eodTrade.TradeStatus)
|
||
select new
|
||
{
|
||
eodTrade.TradeId,
|
||
ClientId = eodTrade.ClientId,
|
||
et = new xodTradeBase() { TradeJson = eodTrade.TradeJson },
|
||
underlyprice = eodTradePosition.UnderlyingPrice,
|
||
};
|
||
|
||
var positionQuerySum = from eodTradePosition in eodTradePositionQuery
|
||
group eodTradePosition by eodTradePosition.ClientId into g
|
||
select new
|
||
{
|
||
ClientId = g.Key,
|
||
//Margin = g.Sum(n => (n.BuySell == "买入" ? -1 : 0) * n.Margin),
|
||
//增加收益互换只计算主交易主交易限制,收益互换暂不考虑买卖反向
|
||
Margin = g.Sum(n => (((n.BuySell == "买入" && n.TradeType != "收益互换") || (n.TradeType == "收益互换" && n.ParentTradeId == 0)) ? -1 : 0) * n.Margin),
|
||
// 收益互换预付金
|
||
SwapMargin = g.Sum(n => ((n.TradeType == "收益互换" && n.ParentTradeId == 0) ? -1 : 0) * n.Margin),
|
||
// 收益互换预付金容忍金额
|
||
SwapUnMargin = g.Sum(n => ((n.TradeType == "收益互换" && n.ParentTradeId == 0) ? -1 : 0) * n.SwapUnMargin),
|
||
};
|
||
|
||
var eodTrades = eodTradeQuery.ToList().Select(o => new { o.et.trade.ClientId, o.et.trade });
|
||
|
||
var positionSumDic = positionQuerySum.ToDictionary(n => n.ClientId);
|
||
|
||
var positionDic = positionQuery.ToList();
|
||
|
||
//----------------------------------------
|
||
// 新交易统计
|
||
//----------------------------------------
|
||
|
||
var newTradeQuery = from t in db.trade
|
||
where t.TradeDate == searchDate
|
||
&& t.ValidState != "InValid"
|
||
&& (t.TradeType != "结构化交易" || t.IsGroup == 1) && t.IsGroup != 2
|
||
&& clientIdList.Contains(t.ClientId)
|
||
&& ConsTrade.TradeStatusAfterConfirmed.Contains(t.TradeStatus)
|
||
select new
|
||
{
|
||
t.id,
|
||
notionalPrincipal = t.OriginalStockEqvNotional > 0
|
||
? ((t.OriginalStockEqvNotional * t.Notional / t.OriginalNotional) ?? 0)
|
||
: (t.SpotPrice ?? 0.0) * t.Notional
|
||
};
|
||
|
||
var todayPostionQuery = from eodTradePosition in eodTradePositionQuery
|
||
join trad in newTradeQuery on eodTradePosition.TradeId equals trad.id
|
||
select new ClientBalanceEx
|
||
{
|
||
ClientId = eodTradePosition.ClientId,
|
||
UnderlyingCode = eodTradePosition.UnderlyingCode
|
||
};
|
||
|
||
var todayPostionList = todayPostionQuery.ToArray();
|
||
|
||
var todayPostionSumQuery = from t in todayPostionList
|
||
group t by t.ClientId into g
|
||
select new ClientBalanceEx
|
||
{
|
||
ClientId = g.Key
|
||
};
|
||
|
||
var todayPostionSumDic = todayPostionSumQuery.ToDictionary(n => n.ClientId);
|
||
|
||
var tradePostionMarginQuery = from eodTradePosition in eodTradePositionQuery
|
||
select new ClientBalanceEx
|
||
{
|
||
ClientId = eodTradePosition.ClientId,
|
||
BuyerPositionMargin = eodTradePosition.Margin * (eodTradePosition.BuySell == "买入" ? 1 : 0),
|
||
};
|
||
|
||
var tradePostionMarginSumQuery = from t in tradePostionMarginQuery
|
||
group t by t.ClientId into g
|
||
select new ClientBalanceEx
|
||
{
|
||
ClientId = g.Key,
|
||
BuyerPositionMargin = g.Sum(n => n.BuyerPositionMargin),
|
||
};
|
||
|
||
var tradePostionMarginSumDic = tradePostionMarginSumQuery.ToDictionary(n => n.ClientId);
|
||
|
||
//----------------------------------------
|
||
//
|
||
//----------------------------------------
|
||
|
||
foreach (var balance in lastClientBalances)
|
||
{
|
||
if (tradeSumDic.TryGetValue(balance.ClientId, out var dicItem))
|
||
{
|
||
balance.SellNotionalPrincipal = dicItem.SellNotionalPrincipal;
|
||
balance.BuyNotionalPrincipal = dicItem.BuyNotionalPrincipal;
|
||
balance.BuyCount = dicItem.BuyCount;
|
||
balance.SellCount = dicItem.SellCount;
|
||
balance.TradeCount = dicItem.TodayCount;
|
||
balance.TodayNotionalPrincipal = dicItem.TodayNotionalPrincipal;
|
||
balance.TotalNotionalPrincipal = balance.SellNotionalPrincipal + balance.BuyNotionalPrincipal;
|
||
balance.TotalTradeCount = balance.BuyCount + balance.SellCount;
|
||
}
|
||
|
||
if (positionSumDic.TryGetValue(balance.ClientId, out var dicItem2))
|
||
{
|
||
balance.TodayNewMargin = dicItem2.Margin;
|
||
}
|
||
|
||
balance.PositionCount = eodTrades.Where(x => x.ClientId == balance.ClientId).Count();
|
||
balance.SellerPositionPremium = eodTrades.Where(o => o.ClientId == balance.ClientId).Sum(o => (o.trade.TradePrice ?? 0) * (o.trade.BuySell == "买入" ? 0 : 1));
|
||
balance.PositionNotionalPrincipal = eodTrades.Where(o => o.ClientId == balance.ClientId).Sum(o => o.trade.StockEqvNotional);
|
||
|
||
if (tradePostionMarginSumDic.TryGetValue(balance.ClientId, out var dicItem4))
|
||
{
|
||
balance.BuyerPositionMargin = dicItem4.BuyerPositionMargin;
|
||
}
|
||
|
||
if (IsOuter)
|
||
{
|
||
balance.MySideMargin = balance.PayableMargin;
|
||
}
|
||
}
|
||
}
|
||
if (searchDate > lastBalanceDate)
|
||
{
|
||
//get nowTime SellerPositionPremium BuyerPositionMargin
|
||
//get postion trade
|
||
|
||
var suspensionUnderlyingIdList = DataCacheProvider.GetUnderlyingDataSource().AsQueryable()
|
||
.Where(t => t.UnderlyingStatus == underlying_manager.Status_Suspension).Select(t => t.id).ToList();
|
||
|
||
var predicate = PredicateBuilder.Create<trade>(t => t.ClientId > 0
|
||
&& ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus)
|
||
&& (t.TradeType != "结构化交易" && t.IsGroup != 1 || t.IsGroup == 1 && t.TradeType == "结构化交易")
|
||
&& (t.IsGroup != 2 || t.IsGroup == 2 && t.TradeType == "收益互换")
|
||
&& t.ValidState != ConsGlobal.InValid
|
||
&& (t.ExerciseDate >= searchDate || suspensionUnderlyingIdList.Contains(t.UnderlyingId)));
|
||
|
||
if (clientIdList != null && clientIdList.Count() > 0)
|
||
{
|
||
predicate = predicate.And(t => clientIdList.Contains(t.ClientId));
|
||
}
|
||
|
||
var positionTradeQuery = from t in db.trade.Where(predicate)
|
||
join i in db.intraday_trade_position
|
||
on t.id equals i.TradeId
|
||
join risk in db.realtime_trade_risk.Where(tr => tr.ValueDate == searchDate && tr.VolType == "持仓") on t.id equals risk.TradeId into risks
|
||
from risk in risks.DefaultIfEmpty()
|
||
select new ClientBalanceEx
|
||
{
|
||
ClientId = t.ClientId,
|
||
SellerPositionPremium = (t.TradePrice ?? 0) * (t.BuySell == "买入" ? 0 : 1),
|
||
BuyerPositionMargin = i.Margin * (t.BuySell == "买入" ? 1 : 0),
|
||
PositionNotionalPrincipal = t.StockEqvNotional,
|
||
};
|
||
var positionTradeSumQuery = from t in positionTradeQuery
|
||
group t by t.ClientId into g
|
||
select new ClientBalanceEx
|
||
{
|
||
ClientId = g.Key,
|
||
SellerPositionPremium = g.Sum(n => n.SellerPositionPremium),
|
||
BuyerPositionMargin = g.Sum(n => n.BuyerPositionMargin),
|
||
PositionNotionalPrincipal = g.Sum(n => n.PositionNotionalPrincipal),
|
||
};
|
||
var tradePostionMarginSumDic = positionTradeSumQuery.ToDictionary(n => n.ClientId);
|
||
|
||
foreach (var balance in lastClientBalances)
|
||
{
|
||
if (tradePostionMarginSumDic.TryGetValue(balance.ClientId, out var dicItem1))
|
||
{
|
||
balance.SellerPositionPremium = dicItem1.SellerPositionPremium;
|
||
balance.BuyerPositionMargin = dicItem1.BuyerPositionMargin;
|
||
balance.PositionNotionalPrincipal = dicItem1.PositionNotionalPrincipal;
|
||
}
|
||
}
|
||
//
|
||
}
|
||
|
||
return lastClientBalances;
|
||
}
|
||
/// <summary>
|
||
/// 为山西固收而写,因为GetClientBanlances已经拿了历史跟最新,不需要再判断是历史还是最新
|
||
/// </summary>
|
||
/// <param name="clientIdList"></param>
|
||
/// <param name="searchDate"></param>
|
||
/// <param name="marginShownType"></param>
|
||
/// <returns></returns>
|
||
public static IEnumerable<ClientSettleBalance> GetClientRiskMonitorForShanXiGuShou(List<int> clientIdList, DateTime searchDate, string marginShownType)
|
||
{
|
||
if (null == clientIdList || !clientIdList.Any())
|
||
{
|
||
return null;
|
||
}
|
||
//获取根据系统时间
|
||
var lastBalanceDate = EodOperationBase.GetLastSettlementDate(DateTime.Now.Date);
|
||
//系统交易日
|
||
var valuedate = valuedateBLL.ValueDate;
|
||
|
||
using var db = new YLContext();
|
||
var IsGap = false;
|
||
var IsOuter = false;
|
||
if (marginShownType == "ClientBalanceGap")
|
||
{
|
||
IsGap = true;
|
||
}
|
||
if (marginShownType == "GetOuterMargin")
|
||
{
|
||
IsOuter = true;
|
||
}
|
||
var lastClientBalances = GetClientBanlances(clientIdList, DateTime.MinValue, searchDate, IsGap, IsOuter);
|
||
if (valuedate <= lastBalanceDate || valuedate > searchDate)
|
||
{
|
||
//----------------------------------------
|
||
// 所有交易合计
|
||
//----------------------------------------
|
||
|
||
var allTradeQuery = from t in db.trade
|
||
where t.TradeDate <= searchDate
|
||
&& t.ValidState != "InValid"
|
||
&& t.TradeType == "收益互换"
|
||
&& clientIdList.Contains(t.ClientId)
|
||
&& ConsTrade.TradeStatusAfterConfirmed.Contains(t.TradeStatus)
|
||
select new
|
||
{
|
||
t.id,
|
||
t.ClientId,
|
||
OriginalStockEqvNotional = t.OriginalStockEqvNotional > 0 ? t.OriginalStockEqvNotional.Value :
|
||
(t.SpotPrice ?? 0.0) * (t.OriginalNotional ?? 0),
|
||
BuyCount = t.BuySell == "买入" ? 0 : 1,//从客户角度看
|
||
SellCount = t.BuySell == "卖出" ? 0 : 1,//从客户角度看
|
||
TodayCount = t.TradeDate == searchDate ? 1 : 0
|
||
};
|
||
|
||
var allTradeQuerySum = from t in allTradeQuery
|
||
group t by t.ClientId into g
|
||
select new
|
||
{
|
||
ClientId = g.Key,
|
||
SellNotionalPrincipal = g.Sum(a => a.SellCount * a.OriginalStockEqvNotional),
|
||
BuyNotionalPrincipal = g.Sum(a => a.BuyCount * a.OriginalStockEqvNotional),
|
||
BuyCount = g.Sum(n => n.BuyCount),
|
||
SellCount = g.Sum(n => n.SellCount),
|
||
TodayCount = g.Sum(n => n.TodayCount),
|
||
TodayNotionalPrincipal = g.Sum(n => n.TodayCount * n.OriginalStockEqvNotional)
|
||
};
|
||
|
||
var tradeSumDic = allTradeQuerySum.ToDictionary(n => n.ClientId);
|
||
var tradePosiQuery = from t in allTradeQuery
|
||
join p in db.eod_swap_position on t.id equals p.SwapTradeId
|
||
where !p.Invalid
|
||
select new
|
||
{
|
||
t.id,
|
||
t.ClientId,
|
||
p
|
||
};
|
||
|
||
foreach (var balance in lastClientBalances)
|
||
{
|
||
if (tradeSumDic.TryGetValue(balance.ClientId, out var dicItem))
|
||
{
|
||
balance.SellNotionalPrincipal = dicItem.SellNotionalPrincipal;
|
||
balance.BuyNotionalPrincipal = dicItem.BuyNotionalPrincipal;
|
||
balance.BuyCount = dicItem.BuyCount;
|
||
balance.SellCount = dicItem.SellCount;
|
||
balance.TradeCount = dicItem.TodayCount;
|
||
balance.TodayNotionalPrincipal = dicItem.TodayNotionalPrincipal;
|
||
balance.TotalNotionalPrincipal = balance.SellNotionalPrincipal + balance.BuyNotionalPrincipal;
|
||
balance.TotalTradeCount = balance.BuyCount + balance.SellCount;
|
||
}
|
||
|
||
var clientTradePosiQuery = tradePosiQuery.Where(x => x.ClientId == balance.ClientId && x.p.PosiQuantity > 0 && x.p.ValueDate == searchDate);
|
||
balance.PositionCount = clientTradePosiQuery.Select(s => s.id).Distinct().Count();
|
||
//var PosiNotionalValue = clientTradePosiQuery.Sum(o => o.p.PosiNotionalValue);
|
||
//balance.PositionNotionalPrincipal = Convert.ToDouble(PosiNotionalValue);
|
||
}
|
||
}
|
||
return lastClientBalances;
|
||
}
|
||
|
||
public static void FillClientBalanceHisTradeFee()
|
||
{
|
||
var clients = DataCacheProvider.GetClientDataSource().AsQueryable().Where(x => x.ProcessStatus == "已开户").ToList();
|
||
using var db = new YLContext();
|
||
var firstEodStatusDate = db.eodStatus.OrderBy(o => o.ValueDate).FirstOrDefault();
|
||
if (firstEodStatusDate != null)
|
||
{
|
||
var firstDate = firstEodStatusDate.ValueDate;
|
||
var preBalanceDate = valuedateBLL.GetNonHolidayDefore(valuedateBLL.ValueDate.AddDays(-1));
|
||
while (firstDate < valuedateBLL.ValueDate)
|
||
{
|
||
foreach (var client in clients)
|
||
{
|
||
var interestPnl = 0d;
|
||
var tradeFee = 0d;
|
||
var clientBalance = db.ClientBalanceDaily.FirstOrDefault(x => x.ClientId == client.id && x.BalanceDate == firstDate);
|
||
var clientBalancePre = db.ClientBalanceDaily.FirstOrDefault(x => x.ClientId == client.id && x.BalanceDate == preBalanceDate);
|
||
if (clientBalance != null)
|
||
{
|
||
// 互换平仓信息
|
||
var clientEventFlowQuery = from eod in db.swap_flow_event.Where(x => x.EventDate <= firstDate && x.EventDate > preBalanceDate && x.ClientId == client.id && x.DataState == (int)SwapFlowDateStateEnum.完成 && x.EventType == (int)SwapFlowEventTypeEnum.平仓)
|
||
join t in db.trade.Where(x => x.TradeType == "收益互换" && x.ValidState != ConsGlobal.InValid) on eod.SwapTradeId equals t.id
|
||
select eod;
|
||
var clientEodSwaps = clientEventFlowQuery.ToList();
|
||
foreach (var item in clientEodSwaps.GroupBy(x => x.SwapTradeId))
|
||
{
|
||
|
||
var eventPosis = item.Where(t => t.PayDirection > 0).ToList();
|
||
|
||
var eventInterests = item.Where(t => t.PayDirection == 0).ToList();
|
||
interestPnl += Convert.ToDouble(eventInterests.Sum(s => s.InterestClosePnL)) * (-1);
|
||
|
||
tradeFee += Convert.ToDouble(eventPosis.Sum(s => s.TradingFee + s.TradingFeePending)) * (-1);
|
||
}
|
||
clientBalance.trade_fee = tradeFee;
|
||
clientBalance.interest_pnl = interestPnl;
|
||
clientBalance.trade_fee_sum = clientBalance.trade_fee;
|
||
clientBalance.interest_pnl_sum = clientBalance.interest_pnl;
|
||
if (clientBalancePre != null)
|
||
{
|
||
clientBalance.trade_fee_sum += clientBalancePre.trade_fee_sum;
|
||
clientBalance.interest_pnl_sum += clientBalancePre.interest_pnl_sum;
|
||
}
|
||
db.SaveChanges();
|
||
}
|
||
}
|
||
preBalanceDate = firstDate;
|
||
firstDate = valuedateBLL.GetNonHoliday(firstDate.AddDays(1));
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 获取预付金率设置
|
||
/// </summary>
|
||
/// <param name="clientId"></param>
|
||
/// <param name="clientMarginTemplates"></param>
|
||
/// <returns></returns>
|
||
private static client_marginrate GetClientMarginRate(int clientId, List<client_marginrate> clientMarginTemplates)
|
||
{
|
||
var marinRate = clientMarginTemplates.Where(x => x.ClientId == clientId).FirstOrDefault();
|
||
if (marinRate == null)
|
||
{
|
||
marinRate = clientMarginTemplates.Where(x => x.ClientId == 0).FirstOrDefault();
|
||
}
|
||
if (marinRate == null)
|
||
{
|
||
marinRate = new client_marginrate
|
||
{
|
||
InitMarginRate = 1,
|
||
MaintenanceRate = 1,
|
||
};
|
||
}
|
||
return marinRate;
|
||
}
|
||
|
||
class ClientBalanceEx : ClientSettleBalance
|
||
{
|
||
public string UnderlyingCode { get; set; }
|
||
}
|
||
|
||
class Pairs
|
||
{
|
||
public ClientBalanceDaily tdaily { get; set; }
|
||
public ClientBalanceGap tgap { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有子客户id
|
||
/// </summary>
|
||
public static List<int> GetSubclientId(int id)
|
||
{
|
||
return InnerGetSubclientId(id, new HashSet<int>());
|
||
}
|
||
|
||
private static List<int> InnerGetSubclientId(int id, HashSet<int> checkSet)
|
||
{
|
||
checkSet ??= new HashSet<int>();
|
||
|
||
if (!checkSet.Add(id))
|
||
{
|
||
checkSet.Clear();
|
||
|
||
var pid = id;
|
||
var list = new List<string>();
|
||
|
||
for (var i = 0; i < 100; i++)
|
||
{
|
||
if (pid <= 0 || !checkSet.Add(pid)) break;
|
||
|
||
var client = DataCacheProvider.GetClientDataSource().GetData(pid);
|
||
|
||
if (client == null)
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
list.Add(client.Name);
|
||
pid = client.ParentId;
|
||
}
|
||
}
|
||
|
||
if (list.Count > 0)
|
||
{
|
||
list.Add(list[0]);
|
||
}
|
||
|
||
throw new ServiceFaultException("客户父子关系产生了循环依赖:" + string.Join("->", list));
|
||
}
|
||
|
||
var result = new List<int>() { id };
|
||
var clientIdList = DataCacheProvider.GetClientDataSource().AsQueryable(O => O.ParentId == id).Select(O => O.id).ToList();
|
||
foreach (var c in clientIdList)
|
||
{
|
||
result.AddRange(InnerGetSubclientId(c, checkSet));
|
||
}
|
||
return result;
|
||
}
|
||
|
||
public static List<ClientBalanceView> queryClientRiskMonitor(ClientRiskMonitorReq req)
|
||
{
|
||
if (!req.SearchDate.HasValue)
|
||
{
|
||
req.SearchDate = valuedateBLL.ValueDate;
|
||
}
|
||
if (string.IsNullOrWhiteSpace(req.marginShownType))
|
||
{
|
||
req.marginShownType = "default";
|
||
}
|
||
if (req.ClientIds == null || req.ClientIds.Count <= 0)
|
||
{
|
||
var clientService = new ClientQueryService(OptUserInfo.SystemUser);
|
||
var predicate = clientService.CreatePredicate(new ClientReq() { ValueDate = req.SearchDate });
|
||
req.ClientIds = clientService.GetClientListByWhere(predicate).Select(o => o.id).Distinct().ToList();
|
||
}
|
||
var result = ClientBalanceUtility.GetClientRiskMonitorForShanXiGuShou(req.ClientIds, req.SearchDate.Value, req.marginShownType);
|
||
if (result == null)
|
||
{
|
||
return new List<ClientBalanceView>();
|
||
}
|
||
var roundFunc = new Func<double, double>(O => Math.Round(O, ConsGlobal.MoneyRound, MidpointRounding.AwayFromZero));
|
||
//精简字段
|
||
var resultList = result.Select(item => new ClientBalanceView
|
||
{
|
||
ValueDate = req.SearchDate.Value,
|
||
Number = item.ClientNumber ?? "",
|
||
Name = item.ClientName ?? "",
|
||
TotalTradeCount = item.TotalTradeCount,
|
||
TotalNotionalPrincipal = roundFunc(item.TotalNotionalPrincipal),
|
||
TransactionPenNumber = item.TradeCount,
|
||
TodayNotionalPrincipal = roundFunc(item.TodayNotionalPrincipal),
|
||
PositionNotionalPrincipal = roundFunc(item.PositionNotionalPrincipal),
|
||
CurrentHoldingPenNumber = item.PositionCount,
|
||
WinLoss = roundFunc(item.WinLoss),
|
||
PositionPnl = roundFunc(item.PositionPnl),
|
||
RoundedPositionPnl = roundFunc(item.RoundedPositionPnl),
|
||
LastDayRemainFund = roundFunc(item.LastDayRemainFund),
|
||
NetFundAll = roundFunc(item.NetFundAll),
|
||
NetFund = roundFunc(item.NetFund),
|
||
VmFundSum = roundFunc(item.VmFundSum),
|
||
OtherFund = roundFunc(item.OtherFund),
|
||
AmountFund = roundFunc(item.AmountFund),
|
||
MySideMargin = roundFunc(item.MySideMargin),
|
||
MaintenanceMargin = roundFunc(item.MaintenanceMargin),
|
||
SwapMarketAmount = roundFunc(item.SwapMarketAmount),
|
||
SwapMarketAmountPercent = item.SwapMarketAmountPercent,
|
||
AvailableAmount = roundFunc(item.AvailableAmount),
|
||
InsuredAmount = roundFunc(item.MarginByPayableMarginTotal),
|
||
DesirableFund = roundFunc(item.DesirableFund),
|
||
TradeFee = roundFunc(item.TradeFee),
|
||
InterestPnl = roundFunc(item.InterestPnl),
|
||
Updatetime = DateTime.Now
|
||
}).ToList();
|
||
return resultList;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存客户资金监控结果, 用于浙商数据采集
|
||
/// </summary>
|
||
/// <param name="valueDate"></param>
|
||
public static void saveClientRiskMonitor(DateTime valueDate)
|
||
{
|
||
LogFactory.GetLogger("saveClientRiskMonitor").Info($"开始执行 {valueDate:yyyy-MM-dd} 数据落库操作");
|
||
var req = new ClientRiskMonitorReq
|
||
{
|
||
SearchDate = valueDate
|
||
};
|
||
var list = queryClientRiskMonitor(req);
|
||
if (list.Count == 0)
|
||
{
|
||
LogFactory.GetLogger("saveClientRiskMonitor").Info($"{valueDate:yyyy-MM-dd} 记录数为0,跳过落库");
|
||
}
|
||
using (var db = new YLContext())
|
||
{
|
||
db.BulkDelete<ClientBalanceView>($"ValueDate='{valueDate:yyyy-MM-dd}'");
|
||
db.clientBalanceView.AddRange(list);
|
||
db.SaveChanges();
|
||
}
|
||
LogFactory.GetLogger("saveClientRiskMonitor").Info($"{valueDate:yyyy-MM-dd} 记录数为{list.Count},落库完成");
|
||
}
|
||
|
||
public class ClientRiskMonitorReq
|
||
{
|
||
public List<int> ClientIds { get; set; }
|
||
|
||
public DateTime? SearchDate { get; set; }
|
||
|
||
public string marginShownType { get; set; }
|
||
}
|
||
|
||
}
|
||
}
|