Merge remote-tracking branch 'origin/glms/feature/1.4.2' into glms/feature/1.4.2-margin
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using BaseOUDAL;
|
||||
using BaseOUDAL;
|
||||
using DocumentFormat.OpenXml.Bibliography;
|
||||
using ExcelDataReader.Log;
|
||||
using YLErp.DBModels;
|
||||
@@ -59,7 +59,43 @@ namespace YLErp.Modules.EodModule
|
||||
create_time = source.create_time,
|
||||
update_time = source.update_time
|
||||
};
|
||||
var result = query.ToSearchList(req);
|
||||
// 不再依赖 bond-sync 镜像:Stock/Fund 公司行为直接作为展示行返回。
|
||||
// 展示金额按“每 10 份派现金额”换算为 GiveCashAmount / 10;EOD 计算仍使用
|
||||
// GetBondPayments 的内部单位口径,不受此处展示换算影响。
|
||||
var corporateQuery = from un in queryUn
|
||||
join dividend in DbContext.ex_dividend_info.AsNoTracking()
|
||||
on un.UnderlyingCode equals dividend.UnderlyingCode
|
||||
where dividend.ValidStatus
|
||||
&& dividend.EffectiveDate.HasValue
|
||||
&& dividend.EffectiveDate.Value >= valueDtStart
|
||||
&& dividend.EffectiveDate.Value < valueDtEnd
|
||||
&& dividend.GiveCashAmount != 0
|
||||
&& (string.IsNullOrEmpty(req.UnderlyingCode)
|
||||
|| dividend.UnderlyingCode.Contains(req.UnderlyingCode))
|
||||
&& (un.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock
|
||||
|| un.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Fund)
|
||||
&& (string.IsNullOrEmpty(req.DataSource)
|
||||
|| "公司行为除权表".Contains(req.DataSource))
|
||||
select new BondPaymentDto
|
||||
{
|
||||
id = -dividend.id,
|
||||
channel_source = "公司行为除权表",
|
||||
MarketName = un.MarketName,
|
||||
security_id = un.UnderlyingCode,
|
||||
symbol = un.UnderlyingName,
|
||||
coupon_rate = null,
|
||||
payment_date = dividend.EffectiveDate,
|
||||
payment_interest = dividend.GiveCashAmount / 10m,
|
||||
payment_parvalue = null,
|
||||
paying_price = dividend.GiveCashAmount / 10m,
|
||||
create_time = dividend.OptDate,
|
||||
update_time = dividend.OptDate
|
||||
};
|
||||
// EF Core 无法翻译两个对 BondPaymentDto 继承属性赋值集合不完全一致的投影
|
||||
// 直接 Concat;分别执行后在内存合并,不改变两组查询的筛选口径。
|
||||
var rows = query.ToList();
|
||||
rows.AddRange(corporateQuery.ToList());
|
||||
var result = rows.AsQueryable().ToSearchList(req);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -104,7 +140,39 @@ namespace YLErp.Modules.EodModule
|
||||
.Where(x => x.reg_date > startDate && x.reg_date <= endDate)
|
||||
.AsNoTracking().ToList();
|
||||
Log.Info($"[分红-登记日口径] GetBondPayments underlyingCode={underlyingCode} 区间=({startDate:yyyy-MM-dd},{endDate:yyyy-MM-dd}] 按reg_date过滤, 命中 {result.Count} 条: " +
|
||||
string.Join(",", result.Select(r => r.reg_date?.ToString("yyyy-MM-dd"))));
|
||||
string.Join(",", result.Select(r => r.reg_date?.ToString("yyyy-MM-dd"))));
|
||||
|
||||
// 让 Copy/Update EOD 始终只依赖 BondPaymentService,而不必在收盘链路直接累加 ex_dividend_info。
|
||||
// Stock/Fund 公司行为直接从 ex_dividend_info 读取,内部仍按“每 10 份派现金额”保存 GiveCashAmount 原值,
|
||||
// 最后的 /10 只应用于这类内存补充记录;bond_payment_info 原生记录仍按每 100 份处理。
|
||||
var corporatePayments = (from dividend in DbContext.ex_dividend_info.AsNoTracking()
|
||||
join underlying in DbContext.underlying_manager.AsNoTracking()
|
||||
on dividend.UnderlyingCode equals underlying.UnderlyingCode
|
||||
where dividend.ValidStatus
|
||||
&& dividend.EffectiveDate.HasValue
|
||||
&& dividend.EffectiveDate.Value > startDate
|
||||
&& dividend.EffectiveDate.Value <= endDate
|
||||
&& dividend.GiveCashAmount != 0
|
||||
&& dividend.UnderlyingCode == underlyingCode
|
||||
&& (underlying.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock
|
||||
|| underlying.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Fund)
|
||||
select dividend).ToList();
|
||||
foreach (var dividend in corporatePayments)
|
||||
{
|
||||
// 按“每 10 份派现金额”口径,直接存 GiveCashAmount 原值,与同步任务/CalcPayment 保持一致。
|
||||
var paymentInterest = dividend.GiveCashAmount;
|
||||
result.Add(new BondPayment
|
||||
{
|
||||
underlyingCode = dividend.UnderlyingCode,
|
||||
payment_date_pl = dividend.EffectiveDate,
|
||||
payment_date = dividend.EffectiveDate,
|
||||
payment_interest = paymentInterest,
|
||||
paying_price = paymentInterest,
|
||||
create_time = dividend.OptDate,
|
||||
update_time = dividend.OptDate,
|
||||
IsCorporateActionCashDividend = true
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -132,24 +200,42 @@ namespace YLErp.Modules.EodModule
|
||||
/// <param name="longRatio">多空方向</param>
|
||||
/// <param name="payDirection">收支方向</param>
|
||||
/// <returns></returns>
|
||||
public decimal CalcPayment(string underlyingCode, DateTime startDate, DateTime endDate, decimal qty, decimal longRatio, decimal payDirection)
|
||||
public decimal CalcPayment(
|
||||
string underlyingCode,
|
||||
DateTime startDate,
|
||||
DateTime endDate,
|
||||
decimal qty,
|
||||
decimal longRatio,
|
||||
decimal payDirection)
|
||||
{
|
||||
var payments = GetBondPayments(underlyingCode, startDate, endDate);
|
||||
return CalcPayment(payments, qty, longRatio, payDirection);
|
||||
}
|
||||
/// <summary>
|
||||
/// 计算某债券期间付息
|
||||
/// 计算某标的期间现金流。债券期间付息与 Stock/Fund 公司行为现金分红可能同时命中,
|
||||
/// 必须按每条记录的来源单位分别计算,不能按标的类型对整个集合统一除以 10 或 100。
|
||||
/// </summary>
|
||||
/// <param name="payments">期间付息集合</param>
|
||||
/// <param name="qty">持仓数量</param>
|
||||
/// <param name="longRatio">多空方向</param>
|
||||
/// <param name="payDirection">收支方向</param>
|
||||
/// <returns></returns>
|
||||
public decimal CalcPayment(List<BondPayment> payments, decimal qty, decimal longRatio, decimal payDirection)
|
||||
public decimal CalcPayment(
|
||||
List<BondPayment> payments,
|
||||
decimal qty,
|
||||
decimal longRatio,
|
||||
decimal payDirection)
|
||||
{
|
||||
var interest = payments.Sum(s => s.payment_interest ?? 0);
|
||||
// interest 为每 100 元面值的票息,×qty 后需 ÷100 转为实际金额(与入库价格 bondPriceMultiple 同口径)
|
||||
return BondPriceConverter.ToStorage(interest * qty) * longRatio * payDirection;
|
||||
var actualAmount = (payments ?? new List<BondPayment>()).Sum(payment =>
|
||||
{
|
||||
var paymentAmount = (payment.payment_interest ?? 0m) * qty;
|
||||
// bond_payment_info 原生期间付息按每 100 份存储;由 ex_dividend_info 补充的
|
||||
// 公司行为现金分红按每 10 份存储。Fund 标的可能同时命中两类记录,故必须逐条分流。
|
||||
return payment.IsCorporateActionCashDividend
|
||||
? paymentAmount / 10m
|
||||
: BondPriceConverter.ToStorage(paymentAmount);
|
||||
});
|
||||
return actualAmount * longRatio * payDirection;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2032,6 +2032,7 @@ namespace YLErp.Modules.EodModule
|
||||
dic.Add("Gamma_r_1bp", OtcFormatExtensions.OtcFormat(item.Gamma_r_1bp, OtcFormatFlag.greek));
|
||||
dic.Add("Vega_r", OtcFormatExtensions.OtcFormat(item.Vega_r, OtcFormatFlag.greek));
|
||||
dic.Add("Vega_r_1bp", OtcFormatExtensions.OtcFormat(item.Vega_r_1bp, OtcFormatFlag.greek));
|
||||
dic.Add("Vega_1bp", OtcFormatExtensions.OtcFormat(item.Vega_1bp, OtcFormatFlag.greek));
|
||||
}
|
||||
|
||||
|
||||
@@ -2143,6 +2144,7 @@ namespace YLErp.Modules.EodModule
|
||||
dic.Add("Gamma_r_1bp", "");
|
||||
dic.Add("Vega_r", "");
|
||||
dic.Add("Vega_r_1bp", "");
|
||||
dic.Add("Vega_1bp", "");
|
||||
}
|
||||
results.Add(dic);
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@ namespace YLErp.Modules.EodModule
|
||||
dto.Dv01 = calcDto.Dv01;
|
||||
dto.Gamma_r_1bp = calcDto.Gamma_r_1bp;
|
||||
dto.Vega_r_1bp = calcDto.Vega_r_1bp;
|
||||
dto.Vega_1bp = calcDto.Vega_1bp;
|
||||
}
|
||||
|
||||
|
||||
@@ -183,6 +184,7 @@ namespace YLErp.Modules.EodModule
|
||||
calRes.Dv01 = calcDto.Dv01;
|
||||
calRes.Gamma_r_1bp = calcDto.Gamma_r_1bp;
|
||||
calRes.Vega_r_1bp = calcDto.Vega_r_1bp;
|
||||
calRes.Vega_1bp = calcDto.Vega_1bp;
|
||||
}
|
||||
|
||||
|
||||
@@ -267,6 +269,9 @@ namespace YLErp.Modules.EodModule
|
||||
|
||||
private void handle(GreeksCalcDto dto, underlying_manager um)
|
||||
{
|
||||
// 标准 Vega 的 1bp 变体:全资产计算,不受利率类过滤限制
|
||||
dto.Vega_1bp = dto.Vega * 0.0001;
|
||||
|
||||
if (!calcInstrumentTypes.Contains(um.UnderlyingInstrumentType))
|
||||
{
|
||||
return;
|
||||
@@ -353,6 +358,8 @@ namespace YLErp.Modules.EodModule
|
||||
|
||||
public double? Vega_r_1bp { get; set; }
|
||||
|
||||
public double? Vega_1bp { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ChinaBondIndexQuoteQueryDto
|
||||
|
||||
Reference in New Issue
Block a user