Merge branch 'glms/feature/1.4.2' of https://gitee.glmszq.com/gsty/onederiv/trs into glms/feature/1.4.2
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -124,7 +124,7 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
protected override string GetOutputFileName(string contractNo, string contractIndex)
|
||||
{
|
||||
var trade = Context.Trade;
|
||||
var rule = $"{trade.TradeType}交易确认书_{contractNo}";
|
||||
var rule = $"【待用印】{trade.TradeType}交易确认书_{contractNo}";
|
||||
return $"{rule}.{DocType.ToLower()}";
|
||||
}
|
||||
|
||||
@@ -152,9 +152,9 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
dic["乙方名称"] = client.Name;
|
||||
|
||||
// 交易日期相关
|
||||
dic["成交日期"] = trade.TradeDate?.ToString("yyyy年M月d日");
|
||||
dic["开始日期"] = trade.StartDate?.ToString("yyyy年M月d日");
|
||||
dic["到期日期"] = trade.ExerciseDate?.ToString("yyyy年M月d日");
|
||||
dic["成交日期"] = trade.TradeDate?.ToString("【yyyy】年【M】月【d】日");
|
||||
dic["开始日期"] = trade.StartDate?.ToString("【yyyy】年【M】月【d】日");
|
||||
dic["到期日期"] = trade.ExerciseDate?.ToString("【yyyy】年【M】月【d】日");
|
||||
|
||||
// 根据交易类型填充不同数据
|
||||
switch (trade.TradeType)
|
||||
@@ -222,8 +222,8 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
var bond = JsonHelper.Deserialize<UnderlyingBond>(underlying.ExJson) ?? new UnderlyingBond();
|
||||
dic["参考标的发行人"] = bond.UnderlyingIssuer ?? "";
|
||||
dic["参考标的担保人"] = "";
|
||||
dic["票面利率"] = ((double)(bond.CouponRate ?? 0) * 100).ToString("N4");
|
||||
dic["参考标的到期日"] = underlying.MaturityDate?.ToString("yyyy年M月d日") ?? "";
|
||||
dic["票面利率"] = ((double)(bond.CouponRate ?? 0)).ToString("0.00");
|
||||
dic["参考标的到期日"] = underlying.MaturityDate?.ToString("【yyyy】年【M】月【d】日") ?? "";
|
||||
}
|
||||
|
||||
// 从swap_position获取期初价格、保证金率等信息
|
||||
@@ -235,7 +235,7 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
if (swapPosition != null)
|
||||
{
|
||||
// 期初全价和净价(转换为百分比格式)
|
||||
dic["参考标的期初全价"] = ((double)swapPosition.PosiGrossPrice).ToString("N4");
|
||||
dic["参考标的期初全价"] = ((double)swapPosition.PosiGrossPrice).ToString("0.000");
|
||||
dic["参考标的期初净价"] = ((double)(swapPosition.PosiNetNoFeePrice ?? 0m)).ToString("N4");
|
||||
|
||||
dic["参考标的期初全价%"] = ((double)swapPosition.PosiGrossPrice * 100).ToString("N4");
|
||||
@@ -257,40 +257,43 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
dic["维持保障金率"] = ((double)clientMarginRate.maintain_rate * 100).ToString("N4");
|
||||
|
||||
// 期初预付比例和金额
|
||||
dic["期初预付比例"] = ((double)clientMarginRate.init_rate * 100).ToString("N4");
|
||||
dic["期初预付比例"] = ((double)clientMarginRate.init_rate * 100).ToString("0.##");
|
||||
dic["期初预付金额"] = ((trade.OriginalStockEqvNotional ?? 0) * (double)clientMarginRate.init_rate).ToString("N2");
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["初始保障金率"] = "0.0000";
|
||||
dic["维持保障金率"] = "0.0000";
|
||||
dic["期初预付比例"] = "0.0000";
|
||||
dic["期初预付比例"] = "0";
|
||||
dic["期初预付金额"] = "0.00";
|
||||
}
|
||||
bool posiLong = IsCustomerLong(swapPosition);
|
||||
// 计算平仓线、预警线、档位值(利率债TRS,固定4档)
|
||||
var maintainRatePercent = (double)(clientMarginRate?.maintain_rate ?? 0) * 100; // 维持保证金率 A(%)
|
||||
// A = 维持保证金率(%),B = 初始保证金率(%),diff = B - A
|
||||
var maintainRatePercent = (double)(clientMarginRate?.maintain_rate ?? 0) * 100; // A(%)
|
||||
var initRatePercent = (double)(clientMarginRate?.init_rate ?? 0) * 100; // B(%)
|
||||
var diff = initRatePercent - maintainRatePercent; // B - A
|
||||
if (maintainRatePercent > 0)
|
||||
{
|
||||
if (posiLong)
|
||||
{
|
||||
// 客户看多:档位n = 100 - n * A
|
||||
dic["平仓线"] = (100 - 4 * maintainRatePercent).ToString("0.##");
|
||||
dic["预警线"] = (100 - 3 * maintainRatePercent).ToString("0.##");
|
||||
dic["档位1"] = (100 - 1 * maintainRatePercent).ToString("0.##");
|
||||
dic["档位2"] = (100 - 2 * maintainRatePercent).ToString("0.##");
|
||||
dic["档位3"] = (100 - 3 * maintainRatePercent).ToString("0.##");
|
||||
dic["档位4"] = (100 - 4 * maintainRatePercent).ToString("0.##");
|
||||
// 客户看多:档位n = 100 - n * (B-A)
|
||||
dic["档位1"] = (100 - 1 * diff).ToString("0.##");
|
||||
dic["档位2"] = (100 - 2 * diff).ToString("0.##");
|
||||
dic["档位3"] = (100 - 3 * diff).ToString("0.##");
|
||||
dic["档位4"] = (100 - 4 * diff).ToString("0.##");
|
||||
dic["预警线"] = dic["档位4"]; // 预警线 = 最高档位
|
||||
dic["平仓线"] = (100 - 5 * diff).ToString("0.##"); // 平仓线 = 最高档位 - (B-A)
|
||||
}
|
||||
else
|
||||
{
|
||||
// 客户看空:档位n = 100 + n * A
|
||||
dic["平仓线"] = (100 + 4 * maintainRatePercent).ToString("0.##");
|
||||
dic["预警线"] = (100 + 3 * maintainRatePercent).ToString("0.##");
|
||||
dic["档位1"] = (100 + 1 * maintainRatePercent).ToString("0.##");
|
||||
dic["档位2"] = (100 + 2 * maintainRatePercent).ToString("0.##");
|
||||
dic["档位3"] = (100 + 3 * maintainRatePercent).ToString("0.##");
|
||||
dic["档位4"] = (100 + 4 * maintainRatePercent).ToString("0.##");
|
||||
// 客户看空:档位n = 100 + n * (B-A)
|
||||
dic["档位1"] = (100 + 1 * diff).ToString("0.##");
|
||||
dic["档位2"] = (100 + 2 * diff).ToString("0.##");
|
||||
dic["档位3"] = (100 + 3 * diff).ToString("0.##");
|
||||
dic["档位4"] = (100 + 4 * diff).ToString("0.##");
|
||||
dic["预警线"] = dic["档位4"]; // 预警线 = 最高档位
|
||||
dic["平仓线"] = (100 + 5 * diff).ToString("0.##"); // 平仓线 = 最高档位 + (B-A)
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -303,6 +306,96 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
dic["档位4"] = "";
|
||||
}
|
||||
|
||||
// 追保事件/返还追保事件 价格区间和金额比例
|
||||
if (maintainRatePercent > 0)
|
||||
{
|
||||
if (posiLong)
|
||||
{
|
||||
// === 客户看多 追保事件 ===
|
||||
// 区间0:当前净价 ≥ {100-(B-A)}% × 期初净价,追保0%
|
||||
dic["追保区间0下限"] = (100 - 1 * diff).ToString("0.##");
|
||||
dic["追保金额比例0"] = "0";
|
||||
// 区间1:{100-2A}% ≤ 当前净价 < {100-A}%,追保{B-A}%
|
||||
dic["追保区间1下限"] = (100 - 2 * maintainRatePercent).ToString("0.##");
|
||||
dic["追保区间1上限"] = (100 - 1 * maintainRatePercent).ToString("0.##");
|
||||
dic["追保金额比例1"] = (1 * diff).ToString("0.##");
|
||||
// 区间2:{100-3A}% ≤ 当前净价 < {100-2A}%,追保{2(B-A)}%
|
||||
dic["追保区间2下限"] = (100 - 3 * maintainRatePercent).ToString("0.##");
|
||||
dic["追保区间2上限"] = (100 - 2 * maintainRatePercent).ToString("0.##");
|
||||
dic["追保金额比例2"] = (2 * diff).ToString("0.##");
|
||||
// 区间3:{100-4A}% ≤ 当前净价 < {100-3A}%,追保{3(B-A)}%
|
||||
dic["追保区间3下限"] = (100 - 4 * maintainRatePercent).ToString("0.##");
|
||||
dic["追保区间3上限"] = (100 - 3 * maintainRatePercent).ToString("0.##");
|
||||
dic["追保金额比例3"] = (3 * diff).ToString("0.##");
|
||||
|
||||
// === 客户看多 返还追保事件 ===
|
||||
// 区间0:当前净价 ≥ {100-(B-A)}% × 期初净价,返还0%
|
||||
dic["返还区间0下限"] = (100 - 1 * diff).ToString("0.##");
|
||||
dic["返还金额比例0"] = "0";
|
||||
// 区间1:{100-2(B-A)}% ≤ 当前净价 < {100-(B-A)}%,返还{B-A}%
|
||||
dic["返还区间1下限"] = (100 - 2 * diff).ToString("0.##");
|
||||
dic["返还区间1上限"] = (100 - 1 * diff).ToString("0.##");
|
||||
dic["返还金额比例1"] = (1 * diff).ToString("0.##");
|
||||
// 区间2:{100-3(B-A)}% ≤ 当前净价 < {100-2(B-A)}%,返还{2(B-A)}%
|
||||
dic["返还区间2下限"] = (100 - 3 * diff).ToString("0.##");
|
||||
dic["返还区间2上限"] = (100 - 2 * diff).ToString("0.##");
|
||||
dic["返还金额比例2"] = (2 * diff).ToString("0.##");
|
||||
// 区间3:{100-4(B-A)}% ≤ 当前净价 < {100-3(B-A)}%,返还{3(B-A)}%
|
||||
dic["返还区间3下限"] = (100 - 4 * diff).ToString("0.##");
|
||||
dic["返还区间3上限"] = (100 - 3 * diff).ToString("0.##");
|
||||
dic["返还金额比例3"] = (3 * diff).ToString("0.##");
|
||||
}
|
||||
else
|
||||
{
|
||||
// === 客户看空 追保事件 ===
|
||||
// 区间0:当前净价 ≤ {100+(B-A)}% × 期初净价,追保0%
|
||||
dic["追保区间0上限"] = (100 + 1 * diff).ToString("0.##");
|
||||
dic["追保金额比例0"] = "0";
|
||||
// 区间1:{100+(B-A)}% < 当前净价 ≤ {100+2(B-A)}%,追保{B-A}%
|
||||
dic["追保区间1下限"] = (100 + 1 * diff).ToString("0.##");
|
||||
dic["追保区间1上限"] = (100 + 2 * diff).ToString("0.##");
|
||||
dic["追保金额比例1"] = (1 * diff).ToString("0.##");
|
||||
// 区间2:{100+2(B-A)}% < 当前净价 ≤ {100+3(B-A)}%,追保{2(B-A)}%
|
||||
dic["追保区间2下限"] = (100 + 2 * diff).ToString("0.##");
|
||||
dic["追保区间2上限"] = (100 + 3 * diff).ToString("0.##");
|
||||
dic["追保金额比例2"] = (2 * diff).ToString("0.##");
|
||||
// 区间3:{100+3(B-A)}% < 当前净价 ≤ {100+4(B-A)}%,追保{3(B-A)}%
|
||||
dic["追保区间3下限"] = (100 + 3 * diff).ToString("0.##");
|
||||
dic["追保区间3上限"] = (100 + 4 * diff).ToString("0.##");
|
||||
dic["追保金额比例3"] = (3 * diff).ToString("0.##");
|
||||
|
||||
// === 客户看空 返还追保事件 ===
|
||||
// 区间0:当前净价 ≤ {100+(B-A)}% × 期初净价,返还0%
|
||||
dic["返还区间0上限"] = (100 + 1 * diff).ToString("0.##");
|
||||
dic["返还金额比例0"] = "0";
|
||||
// 区间1:{100+(B-A)}% < 当前净价 ≤ {100+2(B-A)}%,返还{B-A}%
|
||||
dic["返还区间1下限"] = (100 + 1 * diff).ToString("0.##");
|
||||
dic["返还区间1上限"] = (100 + 2 * diff).ToString("0.##");
|
||||
dic["返还金额比例1"] = (1 * diff).ToString("0.##");
|
||||
// 区间2:{100+2(B-A)}% < 当前净价 ≤ {100+3(B-A)}%,返还{2(B-A)}%
|
||||
dic["返还区间2下限"] = (100 + 2 * diff).ToString("0.##");
|
||||
dic["返还区间2上限"] = (100 + 3 * diff).ToString("0.##");
|
||||
dic["返还金额比例2"] = (2 * diff).ToString("0.##");
|
||||
// 区间3:{100+3(B-A)}% < 当前净价 ≤ {100+4(B-A)}%,返还{3(B-A)}%
|
||||
dic["返还区间3下限"] = (100 + 3 * diff).ToString("0.##");
|
||||
dic["返还区间3上限"] = (100 + 4 * diff).ToString("0.##");
|
||||
dic["返还金额比例3"] = (3 * diff).ToString("0.##");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 清空追保/返还相关字典值
|
||||
for (int i = 0; i <= 3; i++)
|
||||
{
|
||||
dic[$"追保区间{i}下限"] = "";
|
||||
dic[$"追保区间{i}上限"] = "";
|
||||
dic[$"追保金额比例{i}"] = "";
|
||||
dic[$"返还区间{i}下限"] = "";
|
||||
dic[$"返还区间{i}上限"] = "";
|
||||
dic[$"返还金额比例{i}"] = "";
|
||||
}
|
||||
}
|
||||
|
||||
// 期初预付金利率(InterestMode == 初始预付金)
|
||||
var initialMarginPosition = swapPositions
|
||||
.Where(x => x.InterestMode == (int)InterestModeEnum.初始预付金)
|
||||
@@ -326,8 +419,8 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
|
||||
dic["IsFixed"] = "□";
|
||||
dic["IsFloat"] = "□";
|
||||
dic["期初观察日"] = trade.StartDate?.ToString("yyyy年M月d日") ?? "";
|
||||
dic["期末观察日"] = trade.ExerciseDate?.ToString("yyyy年M月d日") ?? "";
|
||||
dic["期初观察日"] = trade.StartDate?.ToString("【yyyy】年【M】月【d】日") ?? "";
|
||||
dic["期末观察日"] = trade.ExerciseDate?.ToString("【yyyy】年【M】月【d】日") ?? "";
|
||||
if (interestMargin != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(interestMargin.FloatRateUnderlyingCode))
|
||||
@@ -349,8 +442,8 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
{
|
||||
var firstInterval = interestMargin.SwapIntervalList.OrderBy(o=>o.Date).First();
|
||||
var lastInterval = interestMargin.SwapIntervalList.OrderBy(o => o.Date).Last();
|
||||
dic["期初观察日"] = firstInterval.Date.ToString("yyyy年M月d日") ?? "";
|
||||
dic["期末观察日"] = lastInterval.Date.ToString("yyyy年M月d日") ?? "";
|
||||
dic["期初观察日"] = firstInterval.Date.ToString("【yyyy】年【M】月【d】日") ?? "";
|
||||
dic["期末观察日"] = lastInterval.Date.ToString("【yyyy】年【M】月【d】日") ?? "";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -364,7 +457,7 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
var notional = trade.OriginalStockEqvNotional ?? 0;
|
||||
var tradingFee = (double)swapPosition.PosiTradingFeePending;
|
||||
var basicFeeRate = notional == 0 ? 0 : tradingFee / notional * 100;
|
||||
dic["基本费率"] = basicFeeRate.ToString("N4");
|
||||
dic["基本费率"] = basicFeeRate.ToString("0.##");
|
||||
|
||||
// 期初现金交换比例和金额(使用初始预付金数据)
|
||||
dic["期初现金交换比例"] = initialMarginPosition != null
|
||||
@@ -376,31 +469,31 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["参考标的期初全价"] = "0.0000";
|
||||
dic["参考标的期初全价"] = "0.000";
|
||||
dic["参考标的期初净价"] = "0.0000";
|
||||
dic["初始保障金率"] = "0.0000";
|
||||
dic["维持保障金率"] = "0.0000";
|
||||
dic["期初预付比例"] = "0.0000";
|
||||
dic["期初预付比例"] = "0";
|
||||
dic["期初预付金额"] = "0.00";
|
||||
dic["期初预付金利率"] = "0.0000";
|
||||
dic["利率类型"] = "固定利率";
|
||||
dic["固定利率"] = "0.0000";
|
||||
dic["利差"] = "";
|
||||
dic["基本费率"] = "0.0000";
|
||||
dic["基本费率"] = "0";
|
||||
dic["期初现金交换比例"] = "0.0000";
|
||||
dic["期初现金交换金额"] = "0.00";
|
||||
}
|
||||
|
||||
// 参考标的券面总额(名义本金)
|
||||
dic["参考标的券面总额"] = trade.OriginalStockEqvNotional?.ToString("N2") ?? "0.00";
|
||||
dic["参考标的券面总额"] = swapPosition != null ? ((double)swapPosition.PosiQuantity).ToString("N2") : "0";
|
||||
|
||||
// 参考标的证券全称和参考标的名义份额(复用上方已声明的bond)
|
||||
dic["参考标的证券全称"] = underlying != null
|
||||
? (JsonHelper.Deserialize<UnderlyingBond>(underlying.ExJson)?.UnderlyingFullName ?? underlying.UnderlyingName)
|
||||
: "";
|
||||
dic["参考标的名义份额"] = swapPosition != null
|
||||
? ((double)swapPosition.PosiQuantity).ToString("N2")
|
||||
: "0.00";
|
||||
? ((double)swapPosition.PosiQuantity).ToString("0.##")
|
||||
: "0";
|
||||
dic["参考标的基金管理人"] = "";
|
||||
var contractTypeId = (Context.GetContractTypes().FirstOrDefault(O => O.ContactType == "交易确认书接收")?.id) ?? 0;
|
||||
// 乙方联系人信息
|
||||
@@ -417,8 +510,8 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
["标的代码"] = underlying?.UnderlyingCode ?? "",
|
||||
["标的名称"] = underlying?.UnderlyingName ?? "",
|
||||
["名义本金"] = trade.OriginalStockEqvNotional?.ToString("N2") ?? "0.00",
|
||||
["成交日期"] = trade.TradeDate?.ToString("yyyy年M月d日"),
|
||||
["到期日期"] = trade.ExerciseDate?.ToString("yyyy年M月d日")
|
||||
["成交日期"] = trade.TradeDate?.ToString("【yyyy】年【M】月【d】日"),
|
||||
["到期日期"] = trade.ExerciseDate?.ToString("【yyyy】年【M】月【d】日")
|
||||
};
|
||||
table1.Add(row);
|
||||
dic["table1"] = table1;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -333,7 +333,7 @@ namespace YLErp.Modules.SwapModule
|
||||
var grossPrice = realPostitions.Where(x => x.PosiDirection > 0).FirstOrDefault()?.PosiGrossPrice;
|
||||
var closeList = DbContext.swap_flow_event.Where(x => x.SwapTradeId == tradeId && x.UnwindDate == unwindDate && eventTypes.Contains(x.EventType) && x.DataState == (int)SwapFlowDateStateEnum.完成).ToList();
|
||||
bool tdClose = closeList.Count > 0;
|
||||
interests = GetInterests(td, tradeExtend, valueDate, unwindDate, lastEodPositions, positions, stockEqvNotional, posiLongNotionalValue, posiShortNotionalValue, posiNotionalValue, closePercent, eventType, tdClose, false, grossPrice ?? 0, orginPv, true, false, closeList);
|
||||
interests = GetInterests(td, tradeExtend, valueDate, unwindDate, lastEodPositions, positions, stockEqvNotional, posiLongNotionalValue, posiShortNotionalValue, posiNotionalValue, closePercent, eventType, tdClose, false, grossPrice ?? 0, orginPv, true, false,false, closeList);
|
||||
return interests;
|
||||
}
|
||||
/// <summary>
|
||||
@@ -372,6 +372,7 @@ namespace YLErp.Modules.SwapModule
|
||||
decimal orginPv,
|
||||
bool add = false,
|
||||
bool settment = true,
|
||||
bool newCalcLast= false,
|
||||
List<swap_flow_event> closeList = null)
|
||||
{
|
||||
List<swap_flow_event> interests = new List<swap_flow_event>();
|
||||
@@ -409,21 +410,35 @@ namespace YLErp.Modules.SwapModule
|
||||
else
|
||||
{
|
||||
// 盘中互换场景,使用 CalcUnwindInterest
|
||||
interests.Add(CalcUnwindInterest(td, valueDate, endDate, positionClone, rate, floatRate, posiPrincipal, closePrincipal, newClosePercent, annualDays, preEodPosition, eventType, add, swap, orginPv, calcFirst, calcLast));
|
||||
interests.Add(CalcUnwindInterest(td, valueDate, endDate, positionClone, rate, floatRate, posiPrincipal, closePrincipal, newClosePercent, annualDays, preEodPosition, eventType, add, swap, orginPv, calcFirst, calcLast||newCalcLast));
|
||||
}
|
||||
}
|
||||
//当日有平仓或互换记录时,需要把平仓或互换已经结算的利息从计算结果中扣除,避免重复计算
|
||||
//当日有平仓或互换记录时,避免重复结算
|
||||
if (closeList != null && closeList.Count > 0)
|
||||
{
|
||||
foreach (var item in interests)
|
||||
{
|
||||
var closeEvent = closeList.Where(x => x.PositionId == item.PositionId);
|
||||
var closePnl = closeEvent.Sum(s => s.InterestClosePnL);
|
||||
var closeAmount = closeEvent.Sum(s => s.InterestAmount);
|
||||
var closeTdAmount = closeEvent.Sum(s => s.TdInterestAmount);
|
||||
item.InterestAmount = item.InterestAmount - closeAmount;
|
||||
item.TdInterestAmount = item.TdInterestAmount - closeTdAmount;
|
||||
item.InterestClosePnL = item.InterestClosePnL - closePnl;
|
||||
if (eventType == (int)SwapEventTypeEnum.互换 || eventType == (int)SwapEventTypeEnum.自动互换)
|
||||
{
|
||||
// 互换:该仓位当天已有完成事件,直接归0
|
||||
if (closeEvent.Any())
|
||||
{
|
||||
item.InterestAmount = 0;
|
||||
item.TdInterestAmount = 0;
|
||||
item.InterestClosePnL = 0;
|
||||
}
|
||||
}
|
||||
else if (!calcLast && !newCalcLast)
|
||||
{
|
||||
// 平仓不算尾:扣除已结算的利息(算尾时利息已包含关闭日,无重叠)
|
||||
var closePnl = closeEvent.Sum(s => s.InterestClosePnL);
|
||||
var closeAmount = closeEvent.Sum(s => s.InterestAmount);
|
||||
var closeTdAmount = closeEvent.Sum(s => s.TdInterestAmount);
|
||||
item.InterestAmount = item.InterestAmount - closeAmount;
|
||||
item.TdInterestAmount = item.TdInterestAmount - closeTdAmount;
|
||||
item.InterestClosePnL = item.InterestClosePnL - closePnl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return interests;
|
||||
@@ -656,11 +671,11 @@ namespace YLErp.Modules.SwapModule
|
||||
var floateRate = preEodPosition.FloatRate;
|
||||
if (position.InterestType == (int)InterestTypeEnum.复利)
|
||||
{
|
||||
CalcDailyCompoundInterest(preEodPosition, endDate, position, closePosiNotionalValue, posiNotionalValue, interest, annualDays, needPrice, floateRate, closePrecent, orginPv, calcFirst, calcLast, ref InterestAmount, ref TdInterestAmount);
|
||||
CalcDailyCompoundInterest( endDate, position, closePosiNotionalValue, interest, annualDays, needPrice, floateRate, closePrecent, orginPv, calcFirst, calcLast, ref InterestAmount, ref TdInterestAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
CalcDailySimpleInterest(preEodPosition, endDate, position, closePosiNotionalValue, posiNotionalValue, interest, annualDays, needPrice, floateRate, closePrecent, orginPv, calcFirst, calcLast, ref InterestAmount, ref TdInterestAmount);
|
||||
CalcDailySimpleInterest(preEodPosition, endDate, position, posiNotionalValue, interest, annualDays, needPrice, floateRate, closePrecent, orginPv, calcFirst, calcLast, ref InterestAmount, ref TdInterestAmount);
|
||||
}
|
||||
|
||||
interest.InterestAmount = Math.Round(InterestAmount, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
|
||||
@@ -684,26 +699,73 @@ namespace YLErp.Modules.SwapModule
|
||||
/// <param name="isAnnualized">是否年化</param>
|
||||
/// <param name="annualDays">年化天数</param>
|
||||
/// <returns></returns>
|
||||
public void CalcDailyCompoundInterest(eod_swap_position preEodPosition, DateTime endDate, swap_position position, decimal principal, decimal posiPrincipal, swap_flow_event flowEvent, int annualDays, bool needPrice, decimal floateRate, decimal closePercent, decimal orginPv, bool calcFirst, bool calcLast, ref decimal InterestAmount, ref decimal TdInterestAmount)
|
||||
public void CalcDailyCompoundInterest( DateTime endDate, swap_position position, decimal principal, swap_flow_event flowEvent, int annualDays, bool needPrice, decimal floateRate, decimal closePercent, decimal orginPv, bool calcFirst, bool calcLast, ref decimal InterestAmount, ref decimal TdInterestAmount)
|
||||
{
|
||||
// 复利:利息并入本金
|
||||
CalcDailyInterest(preEodPosition, endDate, position, principal, posiPrincipal, flowEvent, annualDays, needPrice, floateRate, closePercent, orginPv, compoundInterest: true, calcFirst, calcLast, ref InterestAmount, ref TdInterestAmount);
|
||||
var startDate = position.PosiStartDate;
|
||||
decimal interestProfitSum = 0;
|
||||
decimal TdInterestPrincipal = 0;
|
||||
decimal interest = interestProfitSum ;
|
||||
decimal tdinterest = interestProfitSum ;
|
||||
int interestPeriod = position.interest_rest_days ?? 1;
|
||||
// 复利:只能用要平仓的名义本金从头开始算
|
||||
decimal dynomicPrincipal = principal;
|
||||
decimal tdDynomicPrincipal = dynomicPrincipal;
|
||||
var calcDays = (endDate - startDate).Days;
|
||||
double floatRate = Convert.ToDouble(floateRate);
|
||||
for (int i = 0; i <= calcDays; i++)
|
||||
{
|
||||
var accrueDate = startDate.AddDays(i);
|
||||
if (!calcFirst && accrueDate == startDate) continue; // 首日不算头
|
||||
if (!calcLast && accrueDate == endDate) continue; // 到期日不算尾
|
||||
if (accrueDate >= startDate)
|
||||
{
|
||||
if (i % interestPeriod == 0)
|
||||
{
|
||||
// 复利时:利息并入本金
|
||||
dynomicPrincipal = principal + interest;
|
||||
tdDynomicPrincipal = principal + interest;
|
||||
// 获取新的浮动利率
|
||||
if (!string.IsNullOrEmpty(position.FloatRateUnderlyingCode))
|
||||
{
|
||||
var fr007RateDate = QdpCalendarHelper.GetNonHolidayDefore(accrueDate.AddDays(position.interest_rule ?? 0));
|
||||
if (TryGetFloatRate(fr007RateDate, position.FloatRateUnderlyingCode, out double floatRate1))
|
||||
{
|
||||
if (floatRate1 != 0) floatRate = floatRate1;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fr007RateDate:yyyy年MM月dd日}的价格");
|
||||
}
|
||||
}
|
||||
flowEvent.InterestPrincipal = tdDynomicPrincipal;
|
||||
TdInterestPrincipal = tdDynomicPrincipal;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 复利非重置日:利息不并入本金,不用closePercent缩放(principal已反映平仓比例)
|
||||
flowEvent.InterestPrincipal = tdDynomicPrincipal;
|
||||
TdInterestPrincipal = tdDynomicPrincipal;
|
||||
}
|
||||
flowEvent.FloatRate = Convert.ToDecimal(floatRate);
|
||||
var interest1 = flowEvent.InterestPrincipal * (flowEvent.InterestRate + Convert.ToDecimal(floatRate));
|
||||
var tdinterest1 = TdInterestPrincipal * (flowEvent.InterestRate + Convert.ToDecimal(floatRate));
|
||||
if (position.IsAnnualized)
|
||||
{
|
||||
interest1 /= annualDays;
|
||||
tdinterest1 /= annualDays;
|
||||
}
|
||||
interest += interest1;
|
||||
tdinterest += tdinterest1;
|
||||
}
|
||||
}
|
||||
InterestAmount = Math.Round(interest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
|
||||
TdInterestAmount = Math.Round(tdinterest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算单利 盘中(按重置天数分段,每段使用对应浮动利率)
|
||||
/// </summary>
|
||||
public void CalcDailySimpleInterest(eod_swap_position preEodPosition, DateTime endDate, swap_position position, decimal principal, decimal posiPrincipal, swap_flow_event flowEvent, int annualDays, bool needPrice, decimal floateRate, decimal closePercent, decimal orginPv, bool calcFirst, bool calcLast, ref decimal InterestAmount, ref decimal TdInterestAmount)
|
||||
{
|
||||
// 单利:利息不并入本金
|
||||
CalcDailyInterest(preEodPosition, endDate, position, principal, posiPrincipal, flowEvent, annualDays, needPrice, floateRate, closePercent, orginPv, compoundInterest: false,calcFirst,calcLast, ref InterestAmount, ref TdInterestAmount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通用日度利息计算方法(单利/复利共用)
|
||||
/// </summary>
|
||||
/// <param name="compoundInterest">是否复利:true=利息并入本金,false=单利</param>
|
||||
private void CalcDailyInterest(eod_swap_position preEodPosition, DateTime endDate, swap_position position, decimal principal, decimal posiPrincipal, swap_flow_event flowEvent, int annualDays, bool needPrice, decimal floateRate, decimal closePercent, decimal orginPv, bool compoundInterest, bool calcFirst, bool calcLast, ref decimal InterestAmount, ref decimal TdInterestAmount)
|
||||
public void CalcDailySimpleInterest(eod_swap_position preEodPosition, DateTime endDate, swap_position position, decimal posiPrincipal, swap_flow_event flowEvent, int annualDays, bool needPrice, decimal floateRate, decimal closePercent, decimal orginPv, bool calcFirst, bool calcLast, ref decimal InterestAmount, ref decimal TdInterestAmount)
|
||||
{
|
||||
var startDate = position.PosiStartDate;
|
||||
decimal interestProfitSum = preEodPosition.InterestProfitSum;
|
||||
@@ -711,35 +773,27 @@ namespace YLErp.Modules.SwapModule
|
||||
decimal interest = interestProfitSum * closePercent;
|
||||
decimal tdinterest = interestProfitSum * closePercent;
|
||||
int interestPeriod = position.interest_rest_days ?? 1;
|
||||
decimal dynomicPrincipal = principal;
|
||||
decimal tdDynomicPrincipal = posiPrincipal;
|
||||
// 单利:可用上一日计息基数
|
||||
decimal dynomicPrincipal = preEodPosition.TdInterestPrincipal + posiPrincipal - orginPv;
|
||||
decimal tdDynomicPrincipal = dynomicPrincipal;
|
||||
var calcDays = (endDate - startDate).Days;
|
||||
double floatRate = Convert.ToDouble(floateRate);
|
||||
for (int i = 0; i <= calcDays; i++)
|
||||
{
|
||||
var accrueDate = startDate.AddDays(i);
|
||||
if (!calcFirst && accrueDate == startDate) continue; // 首日不算头
|
||||
if (!calcLast && accrueDate == endDate) continue; // 到期日不算尾
|
||||
if (!calcFirst && accrueDate == startDate) continue; // 首日不算头
|
||||
if (!calcLast && accrueDate == endDate) continue; // 到期日不算尾
|
||||
if (accrueDate > preEodPosition.ValueDate)
|
||||
{
|
||||
if (i % interestPeriod == 0)
|
||||
{
|
||||
// 复利时:利息并入本金
|
||||
if (compoundInterest)
|
||||
{
|
||||
dynomicPrincipal = dynomicPrincipal + interest;
|
||||
tdDynomicPrincipal = tdDynomicPrincipal + interest;
|
||||
}
|
||||
// 获取新的浮动利率
|
||||
if (!string.IsNullOrEmpty(position.FloatRateUnderlyingCode))
|
||||
{
|
||||
var fr007RateDate = QdpCalendarHelper.GetNonHolidayDefore(accrueDate.AddDays(position.interest_rule ?? 0));
|
||||
if (TryGetFloatRate(fr007RateDate, position.FloatRateUnderlyingCode, out double floatRate1))
|
||||
{
|
||||
if (floatRate1 != 0)
|
||||
{
|
||||
floatRate = floatRate1;
|
||||
}
|
||||
if (floatRate1 != 0) floatRate = floatRate1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -751,9 +805,9 @@ namespace YLErp.Modules.SwapModule
|
||||
}
|
||||
else
|
||||
{
|
||||
flowEvent.InterestPrincipal = (preEodPosition.TdInterestPrincipal + posiPrincipal - orginPv) * closePercent;
|
||||
flowEvent.InterestPrincipal = tdDynomicPrincipal * closePercent;
|
||||
tdDynomicPrincipal = flowEvent.InterestPrincipal;
|
||||
TdInterestPrincipal = (preEodPosition.TdInterestPrincipal + posiPrincipal - orginPv);
|
||||
TdInterestPrincipal = tdDynomicPrincipal;
|
||||
}
|
||||
flowEvent.FloatRate = Convert.ToDecimal(floatRate);
|
||||
var interest1 = flowEvent.InterestPrincipal * (flowEvent.InterestRate + Convert.ToDecimal(floatRate));
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace YLErp.Modules.SwapModule
|
||||
public void SwapPositionCompose(DateTime settleDate, DateTime preSettleDate, IEnumerable<int> ClientIds)
|
||||
{
|
||||
var dateStr = settleDate.ToString("yyyy-MM-dd");
|
||||
Log.Info("SwapPositionCompose:"+"settleDate:" + settleDate+ " preSettleDate:"+ preSettleDate+ " ClientIds:"+JsonHelper.Serialize(ClientIds));
|
||||
Log.Info("SwapPositionCompose:" + "settleDate:" + settleDate + " preSettleDate:" + preSettleDate + " ClientIds:" + JsonHelper.Serialize(ClientIds));
|
||||
var tradePredicate = PredicateBuilder.Create<trade>(n => n.ValidState != ConsGlobal.InValid
|
||||
&& n.TradeType == "收益互换"
|
||||
&& n.TradeDate <= settleDate
|
||||
@@ -221,32 +221,32 @@ namespace YLErp.Modules.SwapModule
|
||||
decimal orginPv)
|
||||
{
|
||||
Log.Info("===================处理利息腿归档====================");
|
||||
|
||||
|
||||
// 添加详细的参数验证日志
|
||||
Log.Info($"[DealInterests] 参数验证 - settleDate: {settleDate:yyyy-MM-dd}, td.id: {td?.id}, td.TradeNumber: {td?.TradeNumber}");
|
||||
Log.Info($"[DealInterests] 参数验证 - interestList.Count: {interestList?.Count ?? 0}, eodPositions.Count: {eodPositions?.Count ?? 0}, todyEodPositions.Count: {todyEodPositions?.Count ?? 0}");
|
||||
Log.Info($"[DealInterests] 参数验证 - flowEvents.Count: {flowEvents?.Count ?? 0}, autoInterests.Count: {autoInterests?.Count ?? 0}");
|
||||
Log.Info($"[DealInterests] 参数验证 - posiLongNational: {posiLongNational}, posiShortNational: {posiShortNational}, closeNational: {closeNational}, grossPrice: {grossPrice}, orginPv: {orginPv}");
|
||||
|
||||
|
||||
// 验证关键参数
|
||||
if (td == null)
|
||||
{
|
||||
Log.Info("[DealInterests] 参数验证: td (trade) 为 null");
|
||||
throw new ArgumentNullException(nameof(td), "交易对象不能为null");
|
||||
}
|
||||
|
||||
|
||||
if (interestList == null)
|
||||
{
|
||||
Log.Info($"[DealInterests] 参数验证: interestList 为 null, td.id: {td.id}");
|
||||
throw new ArgumentNullException(nameof(interestList), "利息腿列表不能为null");
|
||||
}
|
||||
|
||||
|
||||
if (flowEvents == null)
|
||||
{
|
||||
Log.Info($"[DealInterests] 参数验证: flowEvents 为 null, td.id: {td.id}");
|
||||
throw new ArgumentNullException(nameof(flowEvents), "流水事件列表不能为null");
|
||||
}
|
||||
|
||||
|
||||
if (autoInterests == null)
|
||||
{
|
||||
Log.Info($"[DealInterests] 参数验证: autoInterests 为 null, td.id: {td.id}");
|
||||
@@ -390,14 +390,14 @@ namespace YLErp.Modules.SwapModule
|
||||
}
|
||||
unwindData.NotionalValue = Convert.ToDecimal(td.OriginalStockEqvNotional ?? 0);
|
||||
unwindData.PosiNotionalValue = StockEqvNotional;
|
||||
|
||||
|
||||
// 预付金腿类型列表:初始预付金、追加预付金
|
||||
var premiumModes = new List<int>() {(int)InterestModeEnum.初始预付金, (int)InterestModeEnum.追加预付金 };
|
||||
|
||||
var premiumModes = new List<int>() { (int)InterestModeEnum.初始预付金, (int)InterestModeEnum.追加预付金 };
|
||||
|
||||
// 分别计算预付金腿和利息腿的金额
|
||||
var premiumInterests = autoInterests.Where(x => premiumModes.Contains(x.InterestMode)).ToList();
|
||||
var interestLegs = autoInterests.Where(x => !premiumModes.Contains(x.InterestMode)).ToList();
|
||||
|
||||
|
||||
// 预付金腿金额
|
||||
decimal premiumTotal = 0;
|
||||
premiumInterests.ForEach(x =>
|
||||
@@ -406,7 +406,7 @@ namespace YLErp.Modules.SwapModule
|
||||
premiumTotal += x.InterestClosePnL * ratio;
|
||||
});
|
||||
unwindData.SwapMarginRebatePnl = premiumTotal; // 预付金腿金额
|
||||
|
||||
|
||||
// 利息腿金额(总金额减去预付金腿金额)
|
||||
decimal interestTotal = 0;
|
||||
interestLegs.ForEach(x =>
|
||||
@@ -415,10 +415,10 @@ namespace YLErp.Modules.SwapModule
|
||||
interestTotal += x.InterestClosePnL * ratio;
|
||||
});
|
||||
unwindData.SwapCloseAmount = interestTotal; // 利息腿金额
|
||||
|
||||
|
||||
// 总实现盈亏
|
||||
unwindData.SwapRealizedPnL = unwindData.SwapCloseAmount + unwindData.SwapMarginRebatePnl;
|
||||
|
||||
|
||||
SaveAutoSwapDeal(td, autoInterests, unwindData, interval);
|
||||
}
|
||||
/// <summary>
|
||||
@@ -432,7 +432,7 @@ namespace YLErp.Modules.SwapModule
|
||||
//td.UnWindDate = unwindData.ValueDate;
|
||||
//优先使用 interval.SettlementDate 作为资金记录发生日期,如果没有则使用 ValueDate
|
||||
var cashHappenDate = interval?.SettlementDate ?? unwindData.ValueDate;
|
||||
|
||||
|
||||
int clientCashId = 0;
|
||||
// 利息腿:插入资金记录(使用系统操作_互换)
|
||||
if (unwindData.SwapCloseAmount != 0)
|
||||
@@ -445,7 +445,7 @@ namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
AddClientCashInCashOut(td, Convert.ToDouble(-unwindData.SwapMarginRebatePnl), ClientCashInCashOut.系统操作_预付金返息, unwindData.ValueDate);
|
||||
}
|
||||
|
||||
|
||||
string data = JsonConvert.SerializeObject(unwindData);
|
||||
var swapEvent = new SwapEventService(this).AddSwapEventDate(unwindData.ValueDate, unwindData.SwapTradeId, (int)SwapEventTypeEnum.自动互换, data, clientCashId, true, "系统操作-自动互换");//将互换总额存入事件
|
||||
flowEvents.ForEach(x =>
|
||||
@@ -731,7 +731,7 @@ namespace YLErp.Modules.SwapModule
|
||||
newEodPayPosition.InterestFeeSum = eodPayPosition.InterestFeeSum + newEodPayPosition.TdInterestFee - newEodPayPosition.TdCloseInterestFee;
|
||||
newEodPayPosition.InterestProfitSum = newEodPayPosition.InterestIncomeSum + newEodPayPosition.InterestFeeSum;
|
||||
//持仓价值
|
||||
newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum * ratio + newEodPayPosition.PosiProfitSum;
|
||||
newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum * ratio + newEodPayPosition.PosiProfitSum;
|
||||
|
||||
//累计已实现
|
||||
newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio;
|
||||
@@ -759,41 +759,41 @@ namespace YLErp.Modules.SwapModule
|
||||
private List<swap_flow_event> SaveAutoEodInterestPosition(eod_swap_position eodPayPosition, eod_swap_position newEodPayPosition, swap_position position, trade td, DateTime valueDate, IntervalModel interval, eod_swap lastEodSwap, decimal posiLongNotional, decimal posiShortNational, decimal grossPrice, decimal orginPv)
|
||||
{
|
||||
Log.Info($"[SaveAutoEodInterestPosition] 开始执行 - valueDate: {valueDate:yyyy-MM-dd}, td.id: {td?.id}, position.id: {position?.id}");
|
||||
|
||||
|
||||
// 详细的参数验证
|
||||
if (td == null)
|
||||
{
|
||||
Log.Info("[SaveAutoEodInterestPosition] 参数验证: td (trade) 为 null");
|
||||
throw new ArgumentNullException(nameof(td), "交易对象不能为null");
|
||||
}
|
||||
|
||||
|
||||
if (position == null)
|
||||
{
|
||||
Log.Info($"[SaveAutoEodInterestPosition] 参数验证: position 为 null, td.id: {td.id}");
|
||||
throw new ArgumentNullException(nameof(position), "持仓对象不能为null");
|
||||
}
|
||||
|
||||
|
||||
if (interval == null)
|
||||
{
|
||||
Log.Info($"[SaveAutoEodInterestPosition] 参数验证: interval 为 null, td.id: {td.id}, position.id: {position.id}");
|
||||
throw new ArgumentNullException(nameof(interval), "观察日信息不能为null");
|
||||
}
|
||||
|
||||
|
||||
if (td.trade_extend == null)
|
||||
{
|
||||
Log.Info($"[SaveAutoEodInterestPosition] 参数验证: td.trade_extend 为 null, td.id: {td.id}, td.TradeNumber: {td.TradeNumber}");
|
||||
throw new ArgumentNullException("td.trade_extend", "交易扩展信息不能为null");
|
||||
}
|
||||
|
||||
|
||||
Log.Info($"eodPayPosition is {JsonHelper.Serialize(eodPayPosition, false)},newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}");
|
||||
|
||||
|
||||
// 验证 ExtendObj
|
||||
if (td.trade_extend.ExtendObj == null)
|
||||
{
|
||||
Log.Info($"[SaveAutoEodInterestPosition] 参数验证: td.trade_extend.ExtendObj 为 null, td.id: {td.id}");
|
||||
throw new ArgumentNullException("td.trade_extend.ExtendObj", "交易扩展对象不能为null");
|
||||
}
|
||||
|
||||
|
||||
var tradeExtend = td.trade_extend.ExtendObj;
|
||||
decimal oriPosiNotionalValue = posiLongNotional + posiShortNational;
|
||||
decimal posiNotionalValue = oriPosiNotionalValue;
|
||||
@@ -902,20 +902,18 @@ namespace YLErp.Modules.SwapModule
|
||||
Log.Info($"eodPayPosition is {JsonHelper.Serialize(eodPayPosition, false)},newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}");
|
||||
var tradeExtend = td.trade_extend.ExtendObj;
|
||||
decimal oriPosiNotionalValue = posiLongNotional + posiShortNational + closeNational;
|
||||
decimal posiNotionalValue = oriPosiNotionalValue;
|
||||
decimal posiNotionalValue = posiLongNotional + posiShortNational;
|
||||
decimal ratio = position.InterestDirection == (int)SwapDirectionEnum.收取 ? 1m : -1m;//收取为正,支付为负
|
||||
if (marginTypes.Contains(position.InterestMode))
|
||||
{
|
||||
ratio = -ratio;
|
||||
}
|
||||
if (eodPayPosition == null)
|
||||
{
|
||||
eodPayPosition = new eod_swap_position();
|
||||
eodPayPosition.ClientId = td.ClientId;
|
||||
eodPayPosition.SwapTradeId = td.id;
|
||||
eodPayPosition.PosiStartDate = td.StartDate.Value;
|
||||
eodPayPosition.PosiMatuirityDate = td.ExerciseDate.Value;
|
||||
}
|
||||
var lastInterestIncomeSum = eodPayPosition.InterestIncomeSum;
|
||||
eodPayPosition = new eod_swap_position();
|
||||
eodPayPosition.ClientId = td.ClientId;
|
||||
eodPayPosition.SwapTradeId = td.id;
|
||||
eodPayPosition.PosiStartDate = td.StartDate.Value;
|
||||
eodPayPosition.PosiMatuirityDate = td.ExerciseDate.Value;
|
||||
if (newEodPayPosition == null)
|
||||
{
|
||||
newEodPayPosition = eodPayPosition.Clone();
|
||||
@@ -926,6 +924,10 @@ namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
orginPv = eodPayPosition.InterestPrincipalFix;
|
||||
}
|
||||
else
|
||||
{
|
||||
orginPv = posiNotionalValue;
|
||||
}
|
||||
decimal closePercent = oriPosiNotionalValue == 0 ? 0 : closeNational / oriPosiNotionalValue;
|
||||
var eventType = autoSwap ? (int)SwapEventTypeEnum.自动互换 : (int)SwapEventTypeEnum.平仓;
|
||||
bool longShort = td.StructureType == ClientMarginTypeEnum.多空组合.ToString();
|
||||
@@ -941,9 +943,9 @@ namespace YLErp.Modules.SwapModule
|
||||
positions.Add(position);
|
||||
List<eod_swap_position> preEodPositions = new List<eod_swap_position>();
|
||||
preEodPositions.Add(eodPayPosition);
|
||||
var interests = new SwapDealService(this).GetInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions, posiNotionalValue, posiLongNotional, posiShortNational, closeNational, 1, eventType, false, true, grossPrice, orginPv, true);
|
||||
var interests = new SwapDealService(this).GetInterests(td, td.trade_extend, valueDate, valueDate, preEodPositions, positions, posiNotionalValue, posiLongNotional, posiShortNational, closeNational, 1, eventType, false, true, grossPrice, orginPv, true, settment: false, newCalcLast: true);
|
||||
decimal TdInterestAmount = interests.Sum(x => x.TdInterestAmount);
|
||||
|
||||
decimal InterestAmount = interests.Sum(x => x.InterestAmount);
|
||||
newEodPayPosition.ValueDate = valueDate;
|
||||
newEodPayPosition.PositionId = position.id;
|
||||
UpdateDbOption(newEodPayPosition);
|
||||
@@ -964,7 +966,7 @@ namespace YLErp.Modules.SwapModule
|
||||
newEodPayPosition.interest_rest_days = position.interest_rest_days;
|
||||
newEodPayPosition.interest_rule = position.interest_rule;
|
||||
//利息端估值用信息
|
||||
newEodPayPosition.TdInterestPrincipal = interestModes.Contains(position.InterestMode) ? eodPayPosition.InterestPrincipalFix : posiLongNotional + posiShortNational;
|
||||
newEodPayPosition.TdInterestPrincipal = interests.Count > 0 ? interests.First().InterestPrincipal : 0;
|
||||
if (interval != null)
|
||||
{
|
||||
newEodPayPosition.TdInterestRate = interval.Rate;
|
||||
@@ -977,8 +979,13 @@ namespace YLErp.Modules.SwapModule
|
||||
newEodPayPosition.TdInterestFee = flowEvents.Sum(s => s.InterestFee);
|
||||
newEodPayPosition.TdCloseInterestFee = newEodPayPosition.TdInterestFee;
|
||||
newEodPayPosition.TdCloseInterest = flowEvents.Sum(s => s.InterestClosePnL);
|
||||
newEodPayPosition.TdInterestIncome = TdInterestAmount * (1 - closePercent);
|
||||
Log.Info($"InterestIncomeSum is {eodPayPosition.InterestIncomeSum},TdInterestIncome is {newEodPayPosition.TdInterestIncome}" +
|
||||
var intersetAcmount = newEodPayPosition.TdInterestPrincipal*(newEodPayPosition.TdInterestRate + newEodPayPosition.FloatRate);
|
||||
if (position.IsAnnualized)
|
||||
{
|
||||
intersetAcmount /= tradeExtend.AnnualDays;
|
||||
}
|
||||
newEodPayPosition.TdInterestIncome = intersetAcmount;
|
||||
Log.Info($"InterestIncomeSum is {lastInterestIncomeSum},TdInterestIncome is {newEodPayPosition.TdInterestIncome}" +
|
||||
$",TdCloseInterest is {newEodPayPosition.TdCloseInterest}");
|
||||
Log.Info($"InterestFeeSum is {eodPayPosition.InterestFeeSum},TdInterestFee is {newEodPayPosition.TdInterestFee}" +
|
||||
$",TdCloseInterestFee is {newEodPayPosition.TdCloseInterestFee}");
|
||||
@@ -988,7 +995,7 @@ namespace YLErp.Modules.SwapModule
|
||||
}
|
||||
else
|
||||
{
|
||||
newEodPayPosition.InterestIncomeSum = eodPayPosition.InterestIncomeSum + newEodPayPosition.TdInterestIncome - newEodPayPosition.TdCloseInterest * ratio;
|
||||
newEodPayPosition.InterestIncomeSum = InterestAmount;
|
||||
}
|
||||
//持仓内容-利息腿-损益统计(本方视角)
|
||||
newEodPayPosition.InterestFeeSum = eodPayPosition.InterestFeeSum + newEodPayPosition.TdInterestFee - newEodPayPosition.TdCloseInterestFee;
|
||||
@@ -1001,9 +1008,9 @@ namespace YLErp.Modules.SwapModule
|
||||
Log.Info($"InterestFeeSum is {eodPayPosition.InterestFeeSum},TdInterestFee is {newEodPayPosition.TdInterestFee}" +
|
||||
$",TdCloseInterestFee is {newEodPayPosition.TdCloseInterestFee}");
|
||||
//累计已实现
|
||||
newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio ;
|
||||
newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio;
|
||||
newEodPayPosition.RealizedInterestFee = eodPayPosition.RealizedInterestFee + newEodPayPosition.TdCloseInterestFee;
|
||||
newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest + newEodPayPosition.RealizedInterestFee;;
|
||||
newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest + newEodPayPosition.RealizedInterestFee; ;
|
||||
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, valueDate
|
||||
, seekPreday: true, currencyRateType: position.InterestDirection == (int)SwapDirectionEnum.收取 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
|
||||
newEodPayPosition.TdCurrency = Convert.ToDecimal(currencyRate);
|
||||
@@ -1040,7 +1047,7 @@ namespace YLErp.Modules.SwapModule
|
||||
eodPayPosition.ClientId = td.ClientId;
|
||||
eodPayPosition.SwapTradeId = td.id;
|
||||
//eodPayPosition.PositionId = position.id; 为了算利息时找不到给日期重新赋值
|
||||
|
||||
|
||||
eodPayPosition.InterestMode = position.InterestMode;
|
||||
eodPayPosition.InterestPrincipalFix = position.InterestPrincipalFix;
|
||||
eodPayPosition.InterestRateDefault = position.InterestRateDefault;
|
||||
@@ -1123,7 +1130,7 @@ namespace YLErp.Modules.SwapModule
|
||||
newEodPayPosition.InterestFeeSum = eodPayPosition.InterestFeeSum + newEodPayPosition.TdInterestFee - newEodPayPosition.TdCloseInterestFee;
|
||||
newEodPayPosition.InterestProfitSum = newEodPayPosition.InterestIncomeSum + newEodPayPosition.InterestFeeSum;
|
||||
//持仓价值
|
||||
newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum * ratio + newEodPayPosition.PosiProfitSum;
|
||||
newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum * ratio + newEodPayPosition.PosiProfitSum;
|
||||
|
||||
//累计已实现
|
||||
newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio;
|
||||
@@ -2002,8 +2009,10 @@ namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
var predicate = PredicateBuilder.Create<eod_swap_position>(n => !n.Invalid && n.PosiQuantity > 0);
|
||||
var interestPredicate = PredicateBuilder.Create<eod_swap_position>(n => !n.Invalid && n.InterestDirection > 0);
|
||||
var tradePredicate = PredicateBuilder.Create<trade>(n => n.StructureType == req.StructureType
|
||||
&& n.ValidState != "InValid");
|
||||
var tradePredicate = PredicateBuilder.Create<trade>(n => n.ValidState != "InValid");
|
||||
// TODO 这里暂时忽略前端传的值 暂时使用临时方案:同时查普通债券类收益互换和普通收益互换
|
||||
tradePredicate = tradePredicate.And(n => n.StructureType == "普通债券类收益互换" || n.StructureType == "普通收益互换");
|
||||
|
||||
if (req.ClientId > 0)
|
||||
{
|
||||
predicate = predicate.And(x => x.ClientId == req.ClientId);
|
||||
@@ -2055,7 +2064,7 @@ namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
eventDate = QdpCalendarHelper.GetNonHoliday(eventDate.AddDays(tradeExtend.ExtendObj.SettlementRules));
|
||||
}
|
||||
item.DayCount = Math.Max(0,(eventDate - item.position.PosiStartDate).Days + 1);
|
||||
item.DayCount = Math.Max(0, (eventDate - item.position.PosiStartDate).Days + 1);
|
||||
//item.position.PosiProfitSum += item.position.VTradingFee-item.position.PosiFeePending;
|
||||
SetClientEodPosition(item.position);
|
||||
//item.position.PosiProfitSum += item.TradingFee;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace YLErp.Modules.SwapModule
|
||||
|
||||
public eod_commodity_future_price SearchTodayFRData(DateTime dateTime)
|
||||
{
|
||||
var data = DbContext.eod_commodity_future_price.Where(a => a.ValueDate == dateTime).FirstOrDefault();
|
||||
var data = DbContext.eod_commodity_future_price.Where(a => a.ValueDate == dateTime && a.UnderlyingCode == "FR007").FirstOrDefault();
|
||||
if (data == null)
|
||||
{
|
||||
data = new eod_commodity_future_price();
|
||||
@@ -80,7 +80,7 @@ namespace YLErp.Modules.SwapModule
|
||||
public bool AddOrUpdateFRdata(Double price, DateTime dateTime)
|
||||
{
|
||||
string beforedate = "";
|
||||
var frdata = DbContext.eod_commodity_future_price.Where(a => a.ValueDate == dateTime).FirstOrDefault();
|
||||
var frdata = DbContext.eod_commodity_future_price.Where(a => a.ValueDate == dateTime && a.UnderlyingCode == "FR007").FirstOrDefault();
|
||||
if (frdata == null)
|
||||
{
|
||||
frdata = new eod_commodity_future_price();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using YLErp.BLL;
|
||||
using BaseOUDAL;
|
||||
using YLErp.BLL;
|
||||
using YLErp.BLL.Eod;
|
||||
using YLErp.Model;
|
||||
using YLErp.Model.Enum;
|
||||
@@ -143,6 +144,7 @@ namespace YLErp.Modules.TradeModule.DealModule
|
||||
var count = tradeProessQuery.Count();
|
||||
if (count == 0 || td.ProcessOrderId == ProcessTradeLog.审批通过)//投资规模校验已经将数据设置为已通过
|
||||
{
|
||||
req.comments = FormatCommentsWithRole(td.ProcessOrderId, req.comments);
|
||||
result.ChangeConfirmPath = SetTradeOpen(req, td);
|
||||
return result;
|
||||
}
|
||||
@@ -166,7 +168,8 @@ namespace YLErp.Modules.TradeModule.DealModule
|
||||
//}
|
||||
if (nextOrder==null)
|
||||
{
|
||||
|
||||
|
||||
req.comments = FormatCommentsWithRole(td.ProcessOrderId, req.comments);
|
||||
result.ChangeConfirmPath = SetTradeOpen(req, td);
|
||||
return result;
|
||||
}
|
||||
@@ -175,6 +178,8 @@ namespace YLErp.Modules.TradeModule.DealModule
|
||||
// 继续审批流转
|
||||
//-----------------------------------------------
|
||||
|
||||
var oldOrderId = td.ProcessOrderId;
|
||||
var formattedComments = FormatCommentsWithRole(oldOrderId, req.comments);
|
||||
td.ProcessOrderId = nextOrder.order;
|
||||
//client.ProcessStatus = "审批中";
|
||||
td.ProcessOptDate = OptDate;
|
||||
@@ -194,7 +199,12 @@ namespace YLErp.Modules.TradeModule.DealModule
|
||||
|
||||
if (!req.notNeedOperationHistory)
|
||||
{
|
||||
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, req.ignoreMoneyCheck ? "交易特批-交易审批同意" : "交易审批同意", req.comments);
|
||||
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, req.ignoreMoneyCheck ? "交易特批-交易审批同意" : "交易审批同意", formattedComments);
|
||||
}
|
||||
|
||||
if (td.TradeType == "收益互换")
|
||||
{
|
||||
new SwapEventService(UserInfo).AddSwapEventDate(DateTime.Now.Date, td.id, (int)SwapEventTypeEnum.审批通过, "", 0, true, formattedComments);
|
||||
}
|
||||
|
||||
DbContext.SaveChanges();
|
||||
@@ -278,6 +288,8 @@ namespace YLErp.Modules.TradeModule.DealModule
|
||||
/// </summary>
|
||||
private TradeOpenResult TradeReject(TradeOpenReqModel req, trade td)
|
||||
{
|
||||
var oldOrderId = td.ProcessOrderId;
|
||||
req.comments = FormatCommentsWithRole(oldOrderId, req.comments);
|
||||
td.ProcessOrderId = Convert.ToInt32(PStatusEnum.reject);
|
||||
td.ProcessOrderBranch = 0;
|
||||
//td.IsApproval = false;
|
||||
@@ -299,7 +311,7 @@ namespace YLErp.Modules.TradeModule.DealModule
|
||||
var swapFlowEvents = DbContext.swap_flow_event.Where(x => x.SwapTradeId == td.id && x.EventType == swapTradeEventType && x.EventDate == swapEvent.ValueDate);
|
||||
DbContext.swap_flow_event.RemoveRange(swapFlowEvents);
|
||||
}
|
||||
new SwapEventService(UserInfo).AddSwapEventDate(DateTime.Now.Date, td.id, (int)SwapEventTypeEnum.审批拒绝, "", 0, true, "提前终止拒绝");
|
||||
new SwapEventService(UserInfo).AddSwapEventDate(DateTime.Now.Date, td.id, (int)SwapEventTypeEnum.审批拒绝, "", 0, true, req.comments);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -311,7 +323,7 @@ namespace YLErp.Modules.TradeModule.DealModule
|
||||
}
|
||||
if (td.TradeType == "收益互换")
|
||||
{
|
||||
new SwapEventService(UserInfo).AddSwapEventDate(DateTime.Now.Date, td.id, (int)SwapEventTypeEnum.审批拒绝, "", 0, true, "交易审批拒绝");
|
||||
new SwapEventService(UserInfo).AddSwapEventDate(DateTime.Now.Date, td.id, (int)SwapEventTypeEnum.审批拒绝, "", 0, true, req.comments);
|
||||
}
|
||||
}
|
||||
td.ProcessStatus = ProcessTradeStatus.已拒绝.ToString();
|
||||
@@ -515,7 +527,7 @@ namespace YLErp.Modules.TradeModule.DealModule
|
||||
if (td.TradeType=="收益互换")
|
||||
{
|
||||
SwapTradeService swapTradeService = new SwapTradeService(this);
|
||||
new SwapEventService(UserInfo).AddSwapEventDate(DateTime.Now.Date, td.id, (int)SwapEventTypeEnum.审批通过, "", 0, true);
|
||||
new SwapEventService(UserInfo).AddSwapEventDate(DateTime.Now.Date, td.id, (int)SwapEventTypeEnum.审批通过, "", 0, true, req.comments);
|
||||
new TradeConfirmService(UserInfo).SwapTradeConfirm(td, "确认交易",false, optlog: "手工操作");
|
||||
}
|
||||
//组合交易(非互换)
|
||||
@@ -727,6 +739,27 @@ namespace YLErp.Modules.TradeModule.DealModule
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetRoleNameByOrderId(int orderId)
|
||||
{
|
||||
var node = DbContext.approvalprocess
|
||||
.FirstOrDefault(x => x.processType == "TradeProcess" && x.order == orderId);
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
return new ErpBaseContext().Roles
|
||||
.Where(r => r.Id == node.roleId)
|
||||
.Select(r => r.Name)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
private string FormatCommentsWithRole(int orderId, string comments)
|
||||
{
|
||||
var roleName = GetRoleNameByOrderId(orderId);
|
||||
if (string.IsNullOrEmpty(roleName))
|
||||
return comments ?? string.Empty;
|
||||
return $"【角色:{roleName}】{comments}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -8,8 +8,10 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
/// <summary>
|
||||
/// 国贸交易确认书编号生成器
|
||||
/// 规则:
|
||||
/// - 对客交易(OpponentRole为"甲方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{标的代码}-{当日第N笔对客交易(数字递增)},从001开始
|
||||
/// - 非对客交易(OpponentRole为"乙方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{标的代码}-{当日第N笔非对客交易(字母递增)},从A开始
|
||||
/// - 对客交易(OpponentRole为"乙方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{当日第N笔对客交易(数字递增)}-{标的代码},从01开始
|
||||
/// 例:GLMS-IS-20260424-01-250210IB
|
||||
/// - 非对客交易(OpponentRole为"甲方"):GLMS-{对手方代码}-{成交日期(yyyyMMdd)}-{当日第N笔非对客交易使用字母递增}-{标的代码},从A开始
|
||||
/// 例:GLMS-IS-20260424-A-250210IB
|
||||
/// </summary>
|
||||
public class GuolianContractNoGenerator
|
||||
{
|
||||
@@ -27,15 +29,16 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
trade trade,
|
||||
string clientCode)
|
||||
{
|
||||
// 根据trade的OpponentRole判断是否为对客交易
|
||||
var isClientTrade = trade.OpponentRole == "甲方";
|
||||
var underlyingCode = trade.UnderlyingCode ?? "";
|
||||
// 根据trade的OpponentRole判断是否为对客交易(乙方=对客)
|
||||
var isClientTrade = trade.OpponentRole == "乙方";
|
||||
var underlyingCode = (trade.UnderlyingCode ?? "").Replace(".", ""); // 去掉标的代码中的点号
|
||||
var tradeDate = trade.TradeDate ?? DateTime.MinValue;
|
||||
var tradeDateStr = tradeDate.ToString("yyyyMMdd");
|
||||
var prefix = $"GLMS-{clientCode}-{tradeDateStr}-{underlyingCode}-";
|
||||
var prefix = $"GLMS-{clientCode}-{tradeDateStr}-";
|
||||
|
||||
lock (_syncLock)
|
||||
{
|
||||
// 幂等:如果已生成过确认书编号,直接返回
|
||||
var existingForTrade = dbContext.trade_contract_r
|
||||
.Where(r => r.TradeId == trade.id && r.Type == ContractTypeEnum.Trade && r.IsValid)
|
||||
.Select(r => r.ContractCode)
|
||||
@@ -46,111 +49,27 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
return existingForTrade;
|
||||
}
|
||||
|
||||
var existingCodes = dbContext.trade_contract_r
|
||||
.Where(d => d.ContractCode.StartsWith(prefix) && d.Type == ContractTypeEnum.Trade && d.IsValid)
|
||||
.Select(d => d.ContractCode)
|
||||
.ToList();
|
||||
|
||||
var existingCodeSet = new HashSet<string>();
|
||||
for (var i = 0; i < existingCodes.Count; i++)
|
||||
{
|
||||
var code = existingCodes[i];
|
||||
if (!string.IsNullOrWhiteSpace(code))
|
||||
{
|
||||
existingCodeSet.Add(code);
|
||||
}
|
||||
}
|
||||
// 通过当天同客户同类交易的 id 排序确定序号(幂等),每个客户独立递增
|
||||
var tradeDateStart = tradeDate.Date;
|
||||
var sameDayTradesCount = dbContext.trade
|
||||
.Count(t => t.TradeDate >= tradeDateStart
|
||||
&& t.TradeDate < tradeDateStart.AddDays(1)
|
||||
&& t.ClientId == trade.ClientId
|
||||
&& t.OpponentRole == trade.OpponentRole
|
||||
&& t.id < trade.id);
|
||||
var sequenceNo = sameDayTradesCount + 1;
|
||||
|
||||
if (isClientTrade)
|
||||
{
|
||||
var maxNo = 0;
|
||||
var prefixLen = prefix.Length;
|
||||
for (var i = 0; i < existingCodes.Count; i++)
|
||||
{
|
||||
var code = existingCodes[i];
|
||||
if (string.IsNullOrEmpty(code) || code.Length <= prefixLen)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var suffix = code.Substring(prefixLen);
|
||||
if (int.TryParse(suffix, out var n) && n > maxNo)
|
||||
{
|
||||
maxNo = n;
|
||||
}
|
||||
}
|
||||
|
||||
var nextNo = maxNo + 1;
|
||||
var contractNo = $"{prefix}{nextNo:D3}";
|
||||
while (existingCodeSet.Contains(contractNo))
|
||||
{
|
||||
nextNo++;
|
||||
contractNo = $"{prefix}{nextNo:D3}";
|
||||
}
|
||||
return contractNo;
|
||||
return $"{prefix}{sequenceNo:D2}-{underlyingCode}";
|
||||
}
|
||||
else
|
||||
{
|
||||
var maxNo = 0;
|
||||
var prefixLen = prefix.Length;
|
||||
for (var i = 0; i < existingCodes.Count; i++)
|
||||
{
|
||||
var code = existingCodes[i];
|
||||
if (string.IsNullOrEmpty(code) || code.Length <= prefixLen)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var suffix = code.Substring(prefixLen);
|
||||
if (!TryParseLettersToNumber(suffix, out var n))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n > maxNo)
|
||||
{
|
||||
maxNo = n;
|
||||
}
|
||||
}
|
||||
|
||||
var nextNo = maxNo + 1;
|
||||
var contractNo = $"{prefix}{NumberToLetter(nextNo)}";
|
||||
while (existingCodeSet.Contains(contractNo))
|
||||
{
|
||||
nextNo++;
|
||||
contractNo = $"{prefix}{NumberToLetter(nextNo)}";
|
||||
}
|
||||
return contractNo;
|
||||
return $"{prefix}{NumberToLetter(sequenceNo)}-{underlyingCode}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryParseLettersToNumber(string letters, out int number)
|
||||
{
|
||||
number = 0;
|
||||
if (string.IsNullOrEmpty(letters))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < letters.Length; i++)
|
||||
{
|
||||
var c = letters[i];
|
||||
if (c >= 'a' && c <= 'z')
|
||||
{
|
||||
c = (char)(c - 32);
|
||||
}
|
||||
else if (c < 'A' || c > 'Z')
|
||||
{
|
||||
number = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
number = (number * 26) + (c - 'A' + 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将数字转换为字母序列(1=A, 2=B, 26=Z, 27=AA, 28=AB...)
|
||||
/// </summary>
|
||||
|
||||
@@ -194,6 +194,27 @@ namespace YLErp.Modules.UnderlyingModule
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除指定标的的保证金率缓存
|
||||
/// </summary>
|
||||
/// <param name="underlyingCode">标的代码,为空时清除全部</param>
|
||||
public static void ClearMarginRateCache(string underlyingCode = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ylCache == null) return;
|
||||
|
||||
var cachePattern = string.IsNullOrEmpty(underlyingCode)
|
||||
? "ClientMarginRate:*"
|
||||
: $"ClientMarginRate:*:{underlyingCode}:*";
|
||||
ylCache.BatchDelete(cachePattern);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("UnderlyingHelper").Error($"清除保证金率缓存时发生异常: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取篮子标的品种对象
|
||||
/// </summary>
|
||||
|
||||
@@ -2108,16 +2108,16 @@ namespace YLErp.Web.Controllers
|
||||
OptName = n.OptName,
|
||||
OptDate = n.OptDate
|
||||
}).ToArray();
|
||||
datas = datas.GroupBy(O => new { O.OptDate, O.OptName, O.OptType }).Select(O => O.First()).OrderByDescending(n => n.id).ToArray();
|
||||
datas = datas.OrderByDescending(n => n.id).ToArray();
|
||||
foreach (var item in datas)
|
||||
{
|
||||
if (IsExchange)
|
||||
if (IsExchange && item.OptType == "批量调整-标的交易")
|
||||
{
|
||||
item.Changes = item.OptType == "批量调整-标的交易" ? new DatatraceQueryService(CurUser).ReplaceDataChanges(new trade(), item.Changes) : "";
|
||||
item.Changes = new DatatraceQueryService(CurUser).ReplaceDataChanges(new trade(), item.Changes);
|
||||
}
|
||||
else
|
||||
else if (!IsExchange && item.OptType == "修改交易")
|
||||
{
|
||||
item.Changes = item.OptType == "修改交易" ? new DatatraceQueryService(CurUser).ReplaceDataChanges(new trade(), item.Changes) : "";
|
||||
item.Changes = new DatatraceQueryService(CurUser).ReplaceDataChanges(new trade(), item.Changes);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(item.Changes))
|
||||
{
|
||||
|
||||
@@ -477,6 +477,7 @@ namespace YLErp.Web.Controllers
|
||||
model.ExJson = JsonHelper.Serialize(model.Bond);
|
||||
}
|
||||
var r = new UnderlyingDalService(CurUser).SaveUnderlyingData(model);
|
||||
YLErp.Modules.UnderlyingModule.UnderlyingHelper.ClearMarginRateCache(model.UnderlyingCode);
|
||||
return JsonSuccess("更新成功", r);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,17 +100,17 @@
|
||||
<div id="selectTemplate">
|
||||
@Html.MyAceDropdownInput2("setTemplate", "模板名: ", YLErp.Web.Controllers.clientbalanceController.GetAllClientBalanceTemplate(), false, "", true, new { onchange = "changeTemplate()" })
|
||||
</div>
|
||||
<h3>发件人:</h3>
|
||||
<select id="sendUser">
|
||||
<option value="@defaultUser.From">@defaultUser.UserName</option>
|
||||
@if (otherUsers != null)
|
||||
{
|
||||
foreach (var user in otherUsers)
|
||||
{
|
||||
<option value="@user.From">@user.UserName</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
@* <h3>发件人:</h3> *@
|
||||
@* <select id="sendUser"> *@
|
||||
@* <option value="@defaultUser.From">@defaultUser.UserName</option> *@
|
||||
@* @if (otherUsers != null) *@
|
||||
@* { *@
|
||||
@* foreach (var user in otherUsers) *@
|
||||
@* { *@
|
||||
@* <option value="@user.From">@user.UserName</option> *@
|
||||
@* } *@
|
||||
@* } *@
|
||||
@* </select> *@
|
||||
@if (!PS.Config.Is申万)
|
||||
{
|
||||
<div class="form-group">
|
||||
|
||||
Reference in New Issue
Block a user