351 lines
20 KiB
C#
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);
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|