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

351 lines
20 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YLErp.BLL.Eod;
using YLErp.BLL;
using YLErp.BLL.EodSettlement;
using YLErp.Model;
using YLErp.QdpModule;
using YLErp.DBModels;
using YLErp.Modules.CalculationModule;
using static iTextSharp.text.pdf.AcroFields;
using NPOI.SS.Formula.Functions;
using YLErp.DBModels.Helpers;
using YLErp.Modules.TradeDalModule;
using Qdp.ComputeServiceV2.Data.CommonModels.TradeInfos;
using Microsoft.Office.Interop.Word;
namespace YLErp.Modules.ReportModule
{
public class FinancialSummaryReportZLService : YLBaseService
{
public FinancialSummaryReportZLService(OptUserInfo userInfo) : base(userInfo)
{
}
/// <summary>
/// 获取场外期权账单数据
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
public FinancialSummaryOptionExportModel GetReportData(FinancialSummaryModelReq req)
{
FinancialSummaryOptionExportModel reportModel = new FinancialSummaryOptionExportModel()
{
StartDate = req.CurrentPeriodDateStart,
EndDate = req.CurrentPeriodDateEnd
};
var allClientList = new List<Client>();
using (var db = DbContextFactory.GetClientDbContext(null))
{
allClientList = db.client.Where(s => s.ProcessStatus != "未提交").ToList();
}
var currentDate = QdpCalendarHelper.GetNonHolidayDefore(req.CurrentPeriodDateEnd);
//系统交易日
var valuedate = valuedateBLL.ValueDate;
//获取根据系统时间
var lastBalanceDate = EodOperationBase.GetLastSettlementDate(valuedate);
if (currentDate < lastBalanceDate)
{
lastBalanceDate = currentDate;
}
var startDate = QdpCalendarHelper.GetNonHolidayDefore(req.CurrentPeriodDateStart);
if (startDate > lastBalanceDate)
{
startDate = lastBalanceDate;
}
var beforeMouthLastDay = DbContext.ClientBalanceDaily.Where(n => n.BalanceDate < req.CurrentPeriodDateStart)
.Max(n => n.BalanceDate) ?? DateTime.MinValue; ; //获取上个月最后一天日期
var lastNonHoliday = QdpCalendarHelper.GetNonHoliday(beforeMouthLastDay);
var eodPositionQuery = DbContext.eod_trade_position.Where(x => x.ValueDate == lastBalanceDate && x.TradeId > 0);//取区间最后一天所有场外期权有效的交易
var lastMonthEodPositionQuery = DbContext.eod_trade_position.Where(x => x.ValueDate == lastNonHoliday && x.TradeId > 0);//取区间上个月末最后一天所有场外期权有效的交易
var eodTradeQuery = DbContext.eod_trade.Where(x => x.ValueDate <= lastBalanceDate && x.ValueDate >= req.CurrentPeriodDateStart).ToLookup(x => x.TradeId);
var lastEodTradeQuery = DbContext.eod_trade.Where(x => x.ValueDate == lastNonHoliday).ToList();
List<trade> trades = new List<trade>();
List<trade> lastMonthTrades = lastEodTradeQuery.Select(s => s.trade).ToList();
foreach (var eodTrade in eodTradeQuery)
{
var lastEodTrade = eodTrade.OrderByDescending(o => o.ValueDate).First();
trades.Add(lastEodTrade.trade);
}
var clientbalanceDailys = DbContext.ClientBalanceDailyBS.Where(x => x.BalanceDate <= lastBalanceDate && x.BalanceDate >= startDate).ToList();
var lastMonthClientbalanceDailys = DbContext.ClientBalanceDailyBS.Where(x => x.BalanceDate == lastNonHoliday).ToList();//上个月末数据
var cashActions = new List<string>() { ClientCashInCashOut.系统操作_期权费, ClientCashInCashOut.系统操作_行权费, ClientCashInCashOut.系统操作_平仓费, ClientCashInCashOut.系统操作_票息, ClientCashInCashOut.系统操作_互换, ClientCashInCashOut.人工操作_其他 };
var entryexitPredicate = PredicateBuilder.Create<ClientCashInCashOut>(t => t.ClientId != null && t.ValidState != "InValid"
&& t.HappenDate >= req.CurrentPeriodDateStart && t.HappenDate < lastBalanceDate.AddDays(1)
&& (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认)
&& cashActions.Contains(t.Action));
var entryexits = (from cash in DbContext.ClientCashInCashOut.Where(entryexitPredicate)
join trade in DbContext.trade on cash.TradeId equals trade.id
select cash).ToLookup(n => n.ClientId.Value);
var tradeCashs = DbContext.trade_cash.Where(x => x.ValidState != "InValid" && !x.IsDeleted && x.ValueDate >= req.CurrentPeriodDateStart && x.ValueDate <= lastBalanceDate);
CalculateClientTradeData(reportModel, entryexits, trades, tradeCashs, eodPositionQuery);
var lastMonthReportModel = new FinancialSummaryOptionExportModel();
CalculateClientPosition(lastMonthReportModel, lastMonthTrades, lastMonthEodPositionQuery);
CalculateClientSummary(reportModel, lastMonthReportModel, clientbalanceDailys, lastMonthClientbalanceDailys, allClientList, lastBalanceDate);
return reportModel;
}
/// <summary>
/// 客户买卖权数据计算
/// </summary>
/// <param name="reportModel"></param>
/// <param name="entryexits"></param>
/// <param name="tradeQuerys"></param>
/// <param name="tradeCashs"></param>
/// <param name="eodPositions"></param>
private void CalculateClientTradeData(FinancialSummaryOptionExportModel reportModel, ILookup<int, ClientCashInCashOut> entryexits, List<trade> tradeQuerys, IQueryable<trade_cash> tradeCashs, IQueryable<eod_trade_position> eodPositions)
{
var dealCouponRateCashInOutDic = new Dictionary<int, ClientCashInCashOut>();//已处理的票息
foreach (var groupEntryExits in entryexits)
{
var entryexitList = groupEntryExits.ToList();
foreach (var item in entryexitList)
{
var trade = tradeQuerys.FirstOrDefault(x => x.id == item.TradeId);
if (dealCouponRateCashInOutDic.ContainsKey(item.id) || trade == null)
{
continue;
}
var tradeCash = tradeCashs.FirstOrDefault(x => x.id == item.TradeCashId);
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode);
if (ClientCashInCashOut.系统操作_期权费.Equals(item.Action))
{
CalculateClientOpen(reportModel, trade, underlying, item.Money ?? 0);
}
else
{
CalculateClientUnwind(reportModel, trade, underlying, item, tradeCash);
}
}
}
CalculateClientPosition(reportModel, tradeQuerys, eodPositions);
}
/// <summary>
/// 计算客户开仓情况
/// </summary>
/// <param name="reportModel"></param>
/// <param name="trade"></param>
/// <param name="isBuy"></param>
/// <param name="underlying"></param>
/// <param name="money"></param>
private void CalculateClientOpen(FinancialSummaryOptionExportModel reportModel, trade trade, underlying_manager underlying, double money)
{
bool isBuy = trade.BuySell == "卖出";
ClientOptionOpen clientOptionOpen = new ClientOptionOpen()
{
ClientId = trade.ClientId,
ClientName = trade.ClientName,
TradeType = trade.TradeMultipleType,
TradeNumber = trade.TradeNumber,
UnderlyingCode = trade.UnderlyingCode,
UnderlyingName = trade.UnderlyingName,
OpenPrice = Math.Round(trade.TradeSinglePrice ?? 0, 2),
Qty = Math.Round(trade.OriginalNotional ?? 0 / underlying.CountRatio, 2),
StockEqvNotional = Math.Round(trade.StockEqvNotional, 2),
OpentAmount = Math.Round(trade.TradePrice ?? 0, 2),
OptionAmount = money
};
if (isBuy)
{
reportModel.BuyClientOptionOpens.Add(clientOptionOpen);
}
else
{
reportModel.SellClientOptionOpens.Add(clientOptionOpen);
}
}
/// <summary>
/// 计算客户平仓情况
/// </summary>
/// <param name="reportModel"></param>
/// <param name="trade"></param>
/// <param name="isBuy"></param>
/// <param name="underlying"></param>
/// <param name="item"></param>
/// <param name="tradeCash"></param>
/// <param name="dealCouponRateCashInOutDic"></param>
/// <param name="entryexitList"></param>
private void CalculateClientUnwind(FinancialSummaryOptionExportModel reportModel
, trade trade
, underlying_manager underlying
, ClientCashInCashOut item
, trade_cash tradeCash)
{
bool isBuy = trade.BuySell == "卖出";
var money = Math.Round(tradeCash?.Amount ?? 0, 2);
var couponRate = 0d;
//结算收益
var unWindProfit = money;
var cost = 0d;
if (trade.TradeType != "远期")
{
cost = TradeCalcHelper.GetSign(trade.BuySell) * (trade.TradePrice ?? 0) * (tradeCash?.UnwindPercentRate ?? 0);
}
else
{
cost = -(trade.TradePrice ?? 0) * (tradeCash?.UnwindPercentRate ?? 0);//远期开仓总费用占比
}
unWindProfit = cost - money;
var unwindPrice = Math.Round(tradeCash?.UnwindPrice ?? 0, 2);
if (tradeCash.Action == ClientCashInCashOut.系统操作_票息)//最后一笔操作,去取票息
{
unWindProfit = 0;
couponRate = money;
}
ClientOptionUnwind clientOptionUnwind = new ClientOptionUnwind()
{
ClientId = trade.ClientId,
ClientName = trade.ClientName,
TradeType = trade.TradeMultipleType,
TradeNumber = trade.TradeNumber,
UnderlyingCode = trade.UnderlyingCode,
UnderlyingName = trade.UnderlyingName,
OpenPrice = Math.Round(trade.TradeSinglePrice ?? 0, 2),
Qty = Math.Round((tradeCash?.UnwindNotional ?? 0) / underlying.CountRatio, 2),
OpentAmount = Math.Round((tradeCash?.UnwindNotional * trade.TradeSinglePrice) ?? 0, 2),
UnwindPrice = unwindPrice,
UnwindPnl = Math.Round(unWindProfit, 2),
CouponRate = Math.Round(couponRate, 2),
};
if (isBuy)
{
reportModel.BuyClientOptionUnwinds.Add(clientOptionUnwind);
}
else
{
reportModel.SellClientOptionUnwinds.Add(clientOptionUnwind);
}
}
/// <summary>
/// 计算客户持仓情况
/// </summary>
/// <param name="reportModel"></param>
/// <param name="tradeQuerys"></param>
/// <param name="eodPositions"></param>
private void CalculateClientPosition(FinancialSummaryOptionExportModel reportModel, List<trade> tradeQuerys, IQueryable<eod_trade_position> eodPositions)
{
foreach (var item in eodPositions)
{
var trade = tradeQuerys.FirstOrDefault(x => x.id == item.TradeId);
if (trade==null)
{
continue;
}
bool isBuy = trade.BuySell == "卖出";
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode);
if (ConsTrade.TradeCompleteStatus.Contains(trade.TradeStatus))
{
continue;
}
var currentPrice = TradeHelper.GetTradeSinglePriceByTradePrice(YLErp.PS.Config.IsPVRounded ? item.RoundedPv * -1 : item.Pv * -1, trade.Notional, PS.Config.ErpElement.IsPVIncludePrincipal ? trade.PrincipalSum() : 0, trade.BuySell, trade.TradeType, false);
ClientOptionPosition clientOptionPosition = new ClientOptionPosition()
{
ClientId = trade.ClientId,
ClientName = trade.ClientName,
TradeType = trade.TradeMultipleType,
TradeNumber = trade.TradeNumber,
UnderlyingCode = trade.UnderlyingCode,
UnderlyingName = trade.UnderlyingName,
OpenPrice = Math.Round(trade.TradeSinglePrice ?? 0, 2),
Qty = Math.Round(trade.Notional / underlying.CountRatio, 2),
SettlePrice = Math.Round(currentPrice, 2),
StockEqvNotional = Math.Round(trade.StockEqvNotional, 2),
OpentAmount = Math.Round((trade.TradeSinglePrice ?? 0) * trade.Notional, 2),
PosiPnl = Math.Round(item.PositionPnL * -1, 2),
CouponRate = Math.Round(item.PositionRelizedAmount, 2)
};
if (isBuy)
{
reportModel.BuyClientOptionPositions.Add(clientOptionPosition);
}
else
{
reportModel.SellClientOptionPositions.Add(clientOptionPosition);
}
}
}
/// <summary>
/// 客户买卖权合计
/// </summary>
/// <param name="reportModel"></param>
/// <param name="clientbalanceDailys"></param>
/// <param name="allClientList"></param>
private void CalculateClientSummary(FinancialSummaryOptionExportModel reportModel, FinancialSummaryOptionExportModel lastMonthReportModel, List<ClientBalanceDailyBS> clientbalanceDailys, List<ClientBalanceDailyBS> lastMonthClientbalanceDailys, List<Client> allClientList, DateTime lastBalanceDate)
{
foreach (var client in allClientList)
{
var clientbalanceB = clientbalanceDailys.FirstOrDefault(x => x.ClientId == client.id && x.IsBuy && x.BalanceDate == lastBalanceDate);
var clientbalanceS = clientbalanceDailys.FirstOrDefault(x => x.ClientId == client.id && !x.IsBuy && x.BalanceDate == lastBalanceDate);
var clientbalanceListB = clientbalanceDailys.Where(x => x.ClientId == client.id && x.IsBuy);
var clientbalanceListS = clientbalanceDailys.Where(x => x.ClientId == client.id && !x.IsBuy);
var lastMothClientbalanceB = lastMonthClientbalanceDailys.FirstOrDefault(x => x.ClientId == client.id && x.IsBuy);
var lastMothClientbalanceS = lastMonthClientbalanceDailys.FirstOrDefault(x => x.ClientId == client.id && !x.IsBuy);
var lastMonthClientBuyPositions = lastMonthReportModel.BuyClientOptionPositions.Where(x => x.ClientId == client.id);
var lastMonthClientSellPositions = lastMonthReportModel.SellClientOptionPositions.Where(x => x.ClientId == client.id);
var clientBuyPositions = reportModel.BuyClientOptionPositions.Where(x => x.ClientId == client.id);
var clientSellPositions = reportModel.SellClientOptionPositions.Where(x => x.ClientId == client.id);
double eodAmountS = 0;//卖权期末结存
if (clientbalanceS != null)
{
ClientSummaryOption sellClientSummaryOption = new ClientSummaryOption()
{
ClientName = client.Name,
};
double lastMonthToDayRemainFund = lastMothClientbalanceS?.ToDayRemainFund ?? 0;
double lastMonthPosiTradePrice = lastMonthClientSellPositions.Sum(s => s.OpentAmount);
sellClientSummaryOption.LastMonthRemainFund = lastMonthToDayRemainFund - lastMonthPosiTradePrice;
sellClientSummaryOption.TradePrice = clientbalanceListS.Sum(s => s.OptionPremium);
sellClientSummaryOption.UnwindPnl = clientbalanceListS.Sum(s => s.WinLoss);
sellClientSummaryOption.PosiPnl = clientbalanceS.PositionPnl;
sellClientSummaryOption.CouponRate = clientbalanceListS.Sum(s => s.Coupon);
sellClientSummaryOption.PosiTradePrice = clientSellPositions.Sum(s => s.OpentAmount);
sellClientSummaryOption.LastRemainFund = sellClientSummaryOption.LastMonthRemainFund + sellClientSummaryOption.UnwindPnl + sellClientSummaryOption.PosiPnl + sellClientSummaryOption.CouponRate;
sellClientSummaryOption.LastRemainFundEXPosiPnl = sellClientSummaryOption.LastRemainFund - sellClientSummaryOption.PosiPnl;
sellClientSummaryOption.SellEodBalance = sellClientSummaryOption.LastRemainFundEXPosiPnl + sellClientSummaryOption.PosiTradePrice;
eodAmountS = sellClientSummaryOption.SellEodBalance;
reportModel.SellClientSummaryOptions.Add(sellClientSummaryOption);
}
if (clientbalanceB != null)
{
ClientSummaryOption buyClientSummaryOption = new ClientSummaryOption()
{
ClientName = client.Name,
};
var cash = Math.Abs(clientbalanceListB.Sum(s => s.InFund)) - Math.Abs(clientbalanceListB.Sum(s => s.OutFund));
if (cash > 0)
{
buyClientSummaryOption.CashIn = cash;
}
else
{
buyClientSummaryOption.CashOut = cash;
}
double lastMonthToDayRemainFund = lastMothClientbalanceB?.ToDayRemainFund ?? 0;
double lastMonthPosiTradePrice = lastMonthClientBuyPositions.Sum(s => s.OpentAmount);
buyClientSummaryOption.LastMonthRemainFund = lastMonthToDayRemainFund + lastMonthPosiTradePrice;
buyClientSummaryOption.TradePrice = clientbalanceListB.Sum(s => s.OptionPremium);
buyClientSummaryOption.TradePrice =Math.Abs( buyClientSummaryOption.TradePrice);//买方支付权利金显示为正
buyClientSummaryOption.UnwindPnl = clientbalanceListB.Sum(s => s.WinLoss);
buyClientSummaryOption.PosiPnl = clientbalanceB.PositionPnl;
buyClientSummaryOption.CouponRate = clientbalanceListB.Sum(s => s.Coupon);
buyClientSummaryOption.PosiTradePrice = clientBuyPositions.Sum(s => s.OpentAmount);
buyClientSummaryOption.LastRemainFund = buyClientSummaryOption.LastMonthRemainFund + buyClientSummaryOption.CashIn + buyClientSummaryOption.UnwindPnl + buyClientSummaryOption.PosiPnl + buyClientSummaryOption.CouponRate - buyClientSummaryOption.CashOut;
buyClientSummaryOption.LastRemainFundEXPosiPnl = buyClientSummaryOption.LastRemainFund - buyClientSummaryOption.PosiPnl;
buyClientSummaryOption.BuyEodBalance = buyClientSummaryOption.LastRemainFundEXPosiPnl - buyClientSummaryOption.PosiTradePrice;
buyClientSummaryOption.SellEodBalance = eodAmountS;
buyClientSummaryOption.EodBalance = buyClientSummaryOption.BuyEodBalance + eodAmountS;
reportModel.BuyClientSummaryOptions.Add(buyClientSummaryOption);
}
}
}
}
}