Files
zszq-trs/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeSettleBillGenerator.cs
T

222 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Newtonsoft.Json.Linq;
using YLErp.Core.Helpers;
using YLErp.DBModels;
using YLErp.DBModels.Consts;
using YLErp.DBModels.Enums;
using YLErp.Models;
using YLErp.Plugins.TradeDocGenerator;
using YLErp.Plugins.TradeDocGenerator.Abstracts;
using YLErp.QdpModule;
namespace YLErp.Plugins.GuoLian.DocumentGenerator
{
/// <summary>
/// 国联证券结算单生成器
/// </summary>
internal class TradeSettleBillGenerator : BaseSettleBillGenerator, ITradeSettleBillGenerator
{
protected override string GetContractNo(out string contractIndex)
{
var contractNo = Context.GenerateContractNo(out contractIndex);
return contractNo;
}
protected override void PrepareViewData(Dictionary<string, object> dic)
{
var client = Context.GetClient();
var flowEvents = Context.GetFlowEvents();
var allFlowEvents = Context.GetAllFlowEvents();
var swapPositions = Context.GetSwapPositions();
var trades = Context.Trades;
var tradeIds = trades.Select(t => t.id).ToList();
var tradeExtends = Context.GetTrade_Extends(tradeIds);
List<ExcelReportModel> table = new List<ExcelReportModel>();
SwapEndConfirmModel outPut = new SwapEndConfirmModel();
foreach (var flowEventGroup in flowEvents)
{
var tradeId = flowEventGroup.SwapTradeId;
var positions = swapPositions.Where(x => x.SwapTradeId == tradeId && x.IsInitial).ToList();
var posi = positions.FirstOrDefault(f => f.id == flowEventGroup.PositionId);
var unwindFlowEvents = allFlowEvents.Where(x => x.EventId == flowEventGroup.EventId);
var trade = trades.FirstOrDefault(x => x.id == tradeId);
var preSettleDate = flowEventGroup.UnwindDate.Value.AddDays(-1);
var swapEodPositions = Context.GetEodPositions(tradeId, preSettleDate);
var tradeExtend = tradeExtends.FirstOrDefault(x => x.TradeId == tradeId);
var ratio = posi.PositionType == (int)PositionTypeFlag.Long ? 1 : -1;
ExcelReportModel row = new ExcelReportModel();
var confirmNo = Context.Gettrade_contract_r(tradeId, ContractTypeEnum.Trade);
if (string.IsNullOrEmpty(confirmNo))
{
// 定位要点:带上事件id便于与 SwapSettlementBillGenerateService 的"生成范围扩张日志"对齐——
// 报错交易常是扩张拉入的同客户同日平仓,并非用户勾选的那笔。
throw new ServiceException($"{trade.TradeNumber}未生成交易确认书(平仓事件id={flowEventGroup.id}, tradeId={tradeId}, 客户={client.Name}, 平仓日={flowEventGroup.UnwindDate?.ToString("yyyy-MM-dd")});请先为该笔交易生成交易确认书后重试");
}
row.TradeNumber = confirmNo;
row.ClientName = client.Name;
row.UnderlyingCode = flowEventGroup.UnderlyingCode;
row.StartDate = trade.StartDate.Value.ToString("yyyy-MM-dd");
var eventDate = flowEventGroup.UnwindDate.Value;
row.EventDate = eventDate.ToString("yyyy-MM-dd");
var payDate = flowEventGroup.PayDate;
var sr = tradeExtend == null ? 0 : tradeExtend.ExtendObj.SettlementRules;
if (!payDate.HasValue)
{
payDate = QdpCalendarHelper.GetNonHoliday(flowEventGroup.EventDate.AddDays(sr));
}
row.PayDate = payDate.Value.ToString("yyyy-MM-dd");
row.ClosePrice = ((flowEventGroup.TradingAmountAvg) * 100).ToString("0.00000000");
decimal interestRate = unwindFlowEvents.Where(x => ConsTrade.InterestModels.Contains(x.InterestMode)).Sum(s => s.InterestRate);
row.InterestRate = interestRate.ToString("0.00%");
var PosiNotionalValue = flowEventGroup.Quantity * flowEventGroup.ContractSize * posi.PosiGrossPrice;
// EQD-6953 期末标的结算收益率:平仓簿记时随 UnwindData 存进 swap_event.EventData
// 此处从浮动腿(PositionType>0)回读。存储态=展示态百分数(6.3721),导出固定 4 位不去零。
decimal? exitYtm = null;
if (flowEventGroup.EventId.HasValue)
{
var swapEvent = Context.GetEvent(flowEventGroup.EventId.Value);
if (swapEvent != null)
{
swapEvent.unwindData = JsonHelper.Deserialize<UnwindData>(swapEvent.EventData);
PosiNotionalValue = swapEvent.unwindData.CloseNotionalValue;
exitYtm = swapEvent.unwindData.FlowEvents?
.FirstOrDefault(f => f.PositionType > 0)?
.ExitYtm;
}
}
row.ExitYtm = exitYtm?.ToString("0.0000") ?? string.Empty;
row.Quantity = flowEventGroup.Quantity.ToString("0.00");
row.PosiNotionalValue = PosiNotionalValue.ToString("0.00");
row.PosiNetPrice = (posi.PosiGrossPrice * 100).ToString("0.00000000");
//var tradingFee = (flowEventGroup.TradingAmountFeeAvg- posi.PosiNetPrice- flowEventGroup.TradingAmountAvg+ posi.PosiGrossPrice)* PosiNotionalValue* ratio;
var tradingFee = flowEventGroup.TradingFee + flowEventGroup.TradingFeePending;
row.Fee = (-tradingFee).ToString("0.00");
var RateDays = (eventDate - trade.StartDate.Value).Days;
RateDays = RateDays < 0 ? 0 : RateDays;
row.RateDays = RateDays.ToString();
var MarginAmout = positions.Where(x => x.InterestMode == (int)InterestModeEnum.初始预付金).Sum(s => s.InterestPrincipalFix * (s.InterestDirection == (int)SwapDirectionEnum.收取 ? 1 : -1));
row.MarginAmout = Math.Abs(MarginAmout).ToString("0.00");
var MarginRebateRate = positions.Where(x => x.InterestMode == (int)InterestModeEnum.初始预付金).Sum(s => s.InterestRateDefault);
row.MarginRebateRate = MarginRebateRate.ToString("0.00%");
var MarginInterestAmount = unwindFlowEvents.Where(x => ConsTrade.InterestMarginModels.Contains(x.InterestMode)).Sum(s => s.InterestClosePnL);
row.MarginInterestAmount = (-MarginInterestAmount).ToString("0.00");
var InterestAmount = unwindFlowEvents.Where(x => ConsTrade.InterestModels.Contains(x.InterestMode)).Sum(s => s.InterestClosePnL) * -1;
row.InterestAmount = InterestAmount.ToString("0.00");
//var lastInterestAmount= swapEodPositions.Where(x => ConsTrade.InterestModels.Contains(x.InterestMode)).Sum(s => s.InterestIncomeSum);
//var lastPosiNotionalValue = swapEodPositions.Sum(s=>s.PosiNotionalValue);
//var InterestAmount = lastPosiNotionalValue==0?0: - lastInterestAmount* PosiNotionalValue/ lastPosiNotionalValue;
//row.InterestAmount = InterestAmount.ToString("0.00");
//var lastMarginAmount = swapEodPositions.Where(x => ConsTrade.InterestMarginModels.Contains(x.InterestMode)).Sum(s => s.InterestIncomeSum);
//var MarginInterestAmount = lastMarginAmount == 0 ? 0 : -lastMarginAmount * PosiNotionalValue / lastMarginAmount;
//row.MarginInterestAmount = MarginInterestAmount.ToString("0.00");
var FloatRate = PosiNotionalValue == 0 ? 0 : InterestAmount / PosiNotionalValue;
row.FloatRate = FloatRate.ToString("0.0000%");
var PosiPnl = -flowEventGroup.MarkClosePnl;
row.PosiPnl = PosiPnl.ToString("0.00");
var markClosePnl = -flowEventGroup.FloatPnlSum;
row.MarkClosePnl = markClosePnl.ToString("0.00");
row.DividendIn = (-flowEventGroup.DividendIn).ToString("0.00");
var marginBackAmount = unwindFlowEvents.Where(x => ConsTrade.InterestMarginModels.Contains(x.InterestMode)).Sum(s => s.InterestPrincipal);
var NetSettleAmout = unwindFlowEvents.Sum(x => x.InterestClosePnL) * -1 + flowEventGroup.FloatPnlSum * -1 + marginBackAmount;
row.NetSettleAmout = NetSettleAmout.ToString("0.00");
table.Add(row);
}
outPut.table = table;
dic["TRS结算单"] = outPut;
}
protected override void PrepareViewData(Dictionary<string, JToken> dic)
{
var client = Context.GetClient();
if (string.IsNullOrEmpty(client.SettleFileNumber))
{
throw new ServiceException($"{client.Name}未设置定义文件编号");
}
var flowEvents = Context.GetFlowEvents();
var allFlowEvents = Context.GetAllFlowEvents();
var swapPositions = Context.GetSwapPositions();
var trades = Context.Trades;
var eventDate = flowEvents.First().UnwindDate;
var td = trades.First();
var realPositions = swapPositions.Where(x => x.PosiQuantity > 0 && !x.IsInitial).ToList();
var posiNationalValue = realPositions.Sum(x => x.PosiNotionalValue);
var metaDic = Context.GetTradeMetas(td.id);
dic["主协议编号"] = metaDic[ConsTradeMetaKey.MainProtocolCode];
dic["文件编号"] = client.SettleFileNumber;
dic["乙方"] = client.Name;
dic["管理人名称"] = client.Manager;
var confirmNo = Context.Gettrade_contract_r(td.id, ContractTypeEnum.Trade);
if (string.IsNullOrEmpty(confirmNo))
{
throw new ServiceException($"{td.TradeNumber}未生成交易确认书");
}
FormatToDict("平仓日期", eventDate, dic);
JArray table = new JArray();
JArray table2 = new JArray();
foreach (var flowEvent in flowEvents)
{
var tradeId = flowEvent.SwapTradeId;
var positions = swapPositions.Where(x => x.SwapTradeId == tradeId).ToList();
var posi = positions.FirstOrDefault(f => f.PositionId == flowEvent.PositionId);
JObject row = new JObject();
row["交易确认书编号"] = confirmNo;
var ratio = flowEvent.PositionType == (int)PositionTypeFlag.Long ? 1 : -1;
row["多空方向"] = flowEvent.PositionType == (int)PositionTypeFlag.Long ? "多" : "空";
FormatToDict("平仓日期", eventDate, row);
underlying_manager underlying = Context.GetTradeUnderlying(flowEvent.UnderlyingCode);
row["标的代码"] = flowEvent.UnderlyingCode;
row["标的名称"] = underlying?.UnderlyingName;
var preQty = flowEvent.Quantity + flowEvent.PositionQty ?? 0;
FormatToDict("平仓前数量", Convert.ToDouble(preQty) * ratio, row);
FormatToDict("平仓数量", Convert.ToDouble(flowEvent.Quantity), row);
FormatToDict("平仓后数量", Convert.ToDouble(flowEvent.PositionQty ?? 0) * ratio, row);
FormatToDict("平仓成交金额", Convert.ToDouble(flowEvent.Quantity * posi.PosiNetPrice * flowEvent.ContractSize), row);
table.Add(row);
}
JObject row2 = new JObject();
row2["交易确认书编号"] = confirmNo;
FormatToDict("平仓日期", eventDate, row2);
FormatToDict("平仓后名义本金", Convert.ToDouble(posiNationalValue), row2);
table2.Add(row2);
dic["table"] = table;
dic["table2"] = table2;
}
protected override string GetTemplateFilePath()
{
var trades = Context.Trades;
var templatePath = string.Empty;
if (trades.Any(s => s.StructureType == "多空组合" || s.StructureType == "定义文件型债券收益互换"))
{
templatePath = MosPathHelper.Combine(GlobalConfig.PluginFolder, "App_Docs/settlement_template/dma_01.docx");
return templatePath;
}
templatePath = MosPathHelper.Combine(GlobalConfig.PluginFolder, "App_Docs/settlement_template/nodma_01.xlsx");
return templatePath;
}
protected override string GetOutputFileName(string contractNo, string contractIndex)
{
var trades = Context.Trades;
var client = Context.GetClient();
var flowEvents = Context.GetFlowEvents();
var eventDate = flowEvents.FirstOrDefault().UnwindDate.Value;
var valueDate = eventDate.ToString("yyyy-MM-dd");
var count = Context.GetDMASelttementCount(client.id, eventDate);
var countStr = count == 0 ? "" : "-" + (count + 1).ToString();
var FullName = $"结算单-{client.Name}-{valueDate}{countStr}";
if (trades.Any(s => s.StructureType == "多空组合" || s.StructureType == "定义文件型债券收益互换"))
{
FullName = $"{client.Name}-结算确认书-{valueDate}-交易平仓{countStr}";
return $"{FullName}.docx";
}
return $"{FullName}.xlsx";
}
}
}