222 lines
13 KiB
C#
222 lines
13 KiB
C#
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";
|
||
}
|
||
}
|
||
}
|