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

393 lines
17 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.Modules.UnderlyingModule;
using YLErp.Plugins.TradeDocGenerator;
using YLErp.Plugins.TradeDocGenerator.Abstracts;
namespace YLErp.Plugins.GuoLian.DocumentGenerator
{
/// <summary>
/// 国联证券交易确认书生成器(单个生成)
/// </summary>
internal class TradeConfirmationGenerator : BaseConfirmationGenerator, ITradeConfirmationGenerator
{
public TradeConfirmationGenerator()
: base(ContractTypeEnum.Trade)
{
}
/// <summary>
/// 获取模板文件路径
/// 收益互换模板选择逻辑:
/// 1. 客户看多/看空:通过持仓方向判断(PositionType: 1=多头/看多,2=空头/看空)
/// 2. 标的类型:
/// - 债券ETF.SH后缀且511开头,或.SZ后缀且59开头
/// - 现券:其他
/// </summary>
protected override string GetTemplateFilePath()
{
var trade = Context.Trade;
if (trade.TradeType == "收益互换")
{
return GetSwapTemplatePath();
}
else if (trade.TradeType.Contains("期权"))
{
// 期权使用期权模板
return Path.Combine(GlobalConfig.PluginFolder, "App_Docs\\contract_template\\option_01.docx");
}
else
{
throw new Exception($"不支持的贸易类型: {trade.TradeType}");
}
}
/// <summary>
/// 获取收益互换模板路径
/// </summary>
private string GetSwapTemplatePath()
{
var trade = Context.Trade;
var underlying = Context.GetTradeUnderlying();
// 判断看多/看空方向
bool isLong = IsLongPosition(trade);
// 判断标的类型(债券ETF vs 现券)
bool isEtf = IsBondEtf(underlying?.UnderlyingCode ?? string.Empty);
// 选择对应模板(使用客户提供的原始文件名)
string templateName;
if (isLong && !isEtf)
templateName = "国联民生-收益互换交易确认书-境内模板-【客户看多】-【现券】-清洁版.docx";
else if (isLong && isEtf)
templateName = "国联民生-收益互换交易确认书-境内模板-【客户看多】-【债券ETF】-清洁版.docx";
else if (!isLong && !isEtf)
templateName = "国联民生-收益互换交易确认书-境内模板-【客户看空】-【现券】-清洁版.docx";
else
templateName = "国联民生-收益互换交易确认书-境内模板-【客户看空】-【债券ETF】-清洁版.docx";
return Path.Combine(GlobalConfig.PluginFolder, "App_Docs\\contract_template", templateName);
}
/// <summary>
/// 判断是否为多头/看多方向
/// </summary>
private bool IsLongPosition(OtcTradeBase trade)
{
// 通过BuySell判断:买入=看多,卖出=看空
return trade.BuySell == "买入";
}
/// <summary>
/// 判断是否为债券ETF
/// - .SH后缀且511开头 -> 债券ETF
/// - .SZ后缀且59开头 -> 债券ETF
/// - 其他 -> 现券
/// </summary>
private bool IsBondEtf(string underlyingCode)
{
if (string.IsNullOrWhiteSpace(underlyingCode))
return false;
underlyingCode = underlyingCode.Trim().ToUpper();
// 上交所债券ETF511开头.SH后缀
if (underlyingCode.EndsWith(".SH") && underlyingCode.StartsWith("511"))
return true;
// 深交所债券ETF:59开头.SZ后缀
if (underlyingCode.EndsWith(".SZ") && underlyingCode.StartsWith("59"))
return true;
return false;
}
/// <summary>
/// 获取输出文件名
/// </summary>
protected override string GetOutputFileName(string contractNo, string contractIndex)
{
var trade = Context.Trade;
var rule = $"{trade.TradeType}交易确认书_{contractNo}";
return $"{rule}.{DocType.ToLower()}";
}
/// <summary>
/// 获取合同编号
/// </summary>
protected override string GetContractNo(out string contractIndex)
{
var contractNo = Context.GenerateContractNo(out contractIndex);
return contractNo;
}
/// <summary>
/// 准备视图数据(Word模板数据)
/// </summary>
protected override void PrepareViewData(Dictionary<string, JToken> dic)
{
var trade = Context.Trade;
var client = Context.GetClient();
// 基础信息
// 注意:合同编号由基类统一设置,此处不再重复生成
dic["交易编号"] = trade.TradeNumber;
dic["客户名称"] = client.Name;
dic["乙方名称"] = client.Name;
// 交易日期相关
dic["成交日期"] = trade.TradeDate?.ToString("yyyy年M月d日");
dic["开始日期"] = trade.StartDate?.ToString("yyyy年M月d日");
dic["到期日期"] = trade.ExerciseDate?.ToString("yyyy年M月d日");
// 根据交易类型填充不同数据
switch (trade.TradeType)
{
case "收益互换":
SetSwapData(dic);
break;
case "香草期权":
case "亚式期权":
case "障碍期权":
SetOptionData(dic);
break;
default:
// 默认基础数据
SetBaseData(dic);
break;
}
}
/// <summary>
/// 设置收益互换数据
/// </summary>
private void SetSwapData(Dictionary<string, JToken> dic)
{
var trade = Context.Trade;
var client = Context.GetClient();
var bank = Context.GetClientBankCard(false);
dic["交易对手方全称"] = client.ClientType != "产品"
? client.Name
: $"{client.Manager}作为管理人代表{client.Name}";
dic["主协议编号"] = client.MainProtocolCode ?? "";
dic["名义本金"] = trade.OriginalStockEqvNotional?.ToString("N2") ?? "0.00";
// 银行账户信息
dic["户名"] = bank?.ClientName ?? "";
dic["银行账号"] = bank?.Card ?? "";
dic["开户行"] = bank?.Bank ?? "";
dic["大额行号"] = bank?.Payment ?? "";
// 标的相关的数据可以通过 Context 获取
var underlying = Context.GetTradeUnderlying();
if (underlying != null)
{
dic["标的代码"] = underlying.UnderlyingCode;
dic["标的名称"] = underlying.UnderlyingName;
// 标的发行人(从债券信息中获取)
var bond = JsonHelper.Deserialize<UnderlyingBond>(underlying.ExJson) ?? new UnderlyingBond();
dic["参考标的发行人"] = bond.UnderlyingIssuer ?? "";
dic["票面利率"] = (bond.CouponRate ?? 0).ToString("N4");
dic["参考标的到期日"] = underlying.MaturityDate?.ToString("yyyy年M月d日") ?? "";
}
// 从swap_position获取期初价格、保证金率等信息
var swapPositions = Context.GetSwapPositions(trade.id, true);
var swapPosition = swapPositions
.Where(x => x.PositionType == (int)PositionTypeFlag.Long || x.PositionType == (int)PositionTypeFlag.Short)
.FirstOrDefault();
if (swapPosition != null)
{
// 期初全价和净价(转换为百分比格式)
dic["参考标的期初全价"] = ((double)swapPosition.PosiGrossPrice * 100).ToString("N4");
dic["参考标的期初净价"] = ((double)(swapPosition.PosiNetNoFeePrice ?? 0m) * 100).ToString("N4");
// 固定收益率(年化)- 债券期初到期收益率
dic["固定收益率(年化)"] = swapPosition.InitYtm.HasValue
? ((double)swapPosition.InitYtm.Value * 100).ToString("N4")
: "0.0000";
// 获取客户适用的保证金率
var clientMarginRate = UnderlyingHelper.GetApplicableMarginRate(
client.id, swapPosition.UnderlyingCode, trade.TradeDate ?? DateTime.Now);
if (clientMarginRate != null)
{
dic["初始保障金率"] = ((double)clientMarginRate.init_rate * 100).ToString("N4");
dic["维持保障金率"] = ((double)clientMarginRate.maintain_rate * 100).ToString("N4");
// 期初预付比例和金额
dic["期初预付比例"] = ((double)clientMarginRate.init_rate * 100).ToString("N4");
dic["期初预付金额"] = ((trade.OriginalStockEqvNotional ?? 0) * (double)clientMarginRate.init_rate).ToString("N2");
}
else
{
dic["初始保障金率"] = "0.0000";
dic["维持保障金率"] = "0.0000";
dic["期初预付比例"] = "0.0000";
dic["期初预付金额"] = "0.00";
}
// 期初预付金利率(InterestMode == 初始预付金)
var initialMarginPosition = swapPositions
.Where(x => x.InterestMode == (int)InterestModeEnum.初始预付金)
.FirstOrDefault();
dic["期初预付金利率"] = initialMarginPosition != null
? ((double)initialMarginPosition.InterestRateDefault * 100).ToString("N4")
: "0.0000";
// 利率类型判断(固定/浮动)
var interestMargin = swapPositions
.Where(x => ConsTrade.InterestModels.Contains(x.InterestMode) && x.interest_rest_days != null)
.FirstOrDefault();
if (interestMargin == null)
interestMargin = swapPositions
.Where(x => ConsTrade.InterestModels.Contains(x.InterestMode) && string.IsNullOrWhiteSpace(x.FloatRateUnderlyingCode))
.FirstOrDefault();
if (interestMargin == null)
interestMargin = swapPositions
.Where(x => ConsTrade.InterestModels.Contains(x.InterestMode))
.FirstOrDefault();
dic["IsFixed"] = "□";
dic["IsFloat"] = "□";
if (interestMargin != null)
{
if (string.IsNullOrEmpty(interestMargin.FloatRateUnderlyingCode))
{
dic["利率类型"] = "固定利率";
dic["IsFixed"] = "☑"; //☑
dic["固定利率"] = ((double)interestMargin.InterestRateDefault * 100).ToString("N4");
dic["利差"] = "";
}
else
{
dic["利率类型"] = "浮动利率";
dic["IsFloat"] = "☑";
dic["固定利率"] = "";
dic["利差"] = ((double)interestMargin.InterestRateDefault * 10000).ToString("N2");
dic["重置频率"] = (interestMargin.interest_rest_days ?? 0) + "天";
}
}
else
{
dic["利率类型"] = "固定利率";
dic["固定利率"] = "0.0000";
dic["利差"] = "";
}
// 基本费率 = PosiTradingFeePending / 名义本金 * 100
var notional = trade.OriginalStockEqvNotional ?? 0;
var tradingFee = (double)swapPosition.PosiTradingFeePending;
var basicFeeRate = notional == 0 ? 0 : tradingFee / notional * 100;
dic["基本费率"] = basicFeeRate.ToString("N4");
// 期初现金交换比例和金额(使用初始预付金数据)
dic["期初现金交换比例"] = initialMarginPosition != null
? ((double)initialMarginPosition.InterestRateDefault * 100).ToString("N4")
: "0.0000";
dic["期初现金交换金额"] = initialMarginPosition != null
? ((double)initialMarginPosition.InterestPrincipalFix).ToString("N2")
: "0.00";
}
else
{
dic["参考标的期初全价"] = "0.0000";
dic["参考标的期初净价"] = "0.0000";
dic["初始保障金率"] = "0.0000";
dic["维持保障金率"] = "0.0000";
dic["期初预付比例"] = "0.0000";
dic["期初预付金额"] = "0.00";
dic["期初预付金利率"] = "0.0000";
dic["利率类型"] = "固定利率";
dic["固定利率"] = "0.0000";
dic["利差"] = "";
dic["基本费率"] = "0.0000";
dic["期初现金交换比例"] = "0.0000";
dic["期初现金交换金额"] = "0.00";
}
// 参考标的券面总额(名义本金)
dic["参考标的券面总额"] = trade.OriginalStockEqvNotional?.ToString("N2") ?? "0.00";
// 参考标的证券全称和参考标的名义份额(复用上方已声明的bond)
dic["参考标的证券全称"] = underlying != null
? (JsonHelper.Deserialize<UnderlyingBond>(underlying.ExJson)?.UnderlyingFullName ?? underlying.UnderlyingName)
: "";
dic["参考标的名义份额"] = swapPosition != null
? ((double)swapPosition.PosiQuantity).ToString("N2")
: "0.00";
// 乙方联系人信息
var clientDuties = Context.GetClientDuties();
var contact = clientDuties.FirstOrDefault();
dic["联系人"] = contact?.ContactName ?? "";
dic["电子邮件"] = contact?.Email ?? "";
dic["电话"] = contact?.PhoneNumber ?? "";
// 表格数据示例
var table1 = new JArray();
var row = new JObject
{
["序号"] = 1,
["标的代码"] = underlying?.UnderlyingCode ?? "",
["标的名称"] = underlying?.UnderlyingName ?? "",
["名义本金"] = trade.OriginalStockEqvNotional?.ToString("N2") ?? "0.00",
["成交日期"] = trade.TradeDate?.ToString("yyyy年M月d日"),
["到期日期"] = trade.ExerciseDate?.ToString("yyyy年M月d日")
};
table1.Add(row);
dic["table1"] = table1;
}
/// <summary>
/// 设置期权数据
/// </summary>
private void SetOptionData(Dictionary<string, JToken> dic)
{
var trade = Context.Trade;
var client = Context.GetClient();
var underlying = Context.GetTradeUnderlying();
dic["期权类型"] = trade.OptionType;
dic["买卖方向"] = trade.BuySell;
dic["行权价格"] = trade.Strike?.ToString("N4") ?? "0.0000";
dic["名义本金"] = trade.StockEqvNotional.ToString("N2");
dic["期权费"] = trade.TradePrice?.ToString("N2") ?? "0.00";
dic["期初价格"] = trade.SpotPrice?.ToString("N4") ?? "0.0000";
if (underlying != null)
{
dic["标的代码"] = underlying.UnderlyingCode;
dic["标的名称"] = underlying.UnderlyingName;
dic["报价单位"] = underlying.QuoteUnitString ?? "元";
}
// 美式/欧式
dic["行权方式"] = trade.ExerciseMode == "American" ? "美式" : "欧式";
}
/// <summary>
/// 设置基础数据
/// </summary>
private void SetBaseData(Dictionary<string, JToken> dic)
{
var trade = Context.Trade;
var client = Context.GetClient();
dic["交易类型"] = trade.TradeType;
dic["客户编号"] = client.Number;
dic["名义本金"] = trade.OriginalStockEqvNotional?.ToString("N2") ?? "0.00";
}
}
}