Merge branch 'glms/feature/0812_zmr_divPower' into glms/feature/1.4.2
This commit is contained in:
@@ -39,14 +39,15 @@ namespace YLErp.Modules.EodModule
|
||||
predicate = PredicateBuilder.Create<T>(n => n.ValueDate == settleDate).And(predicate);
|
||||
}
|
||||
|
||||
// 除权数据不在这里做 SQL 左连接:同一标的一天只允许一条有效除权记录,
|
||||
// 但历史脏数据可能存在重复行。左连接会把一条 EOD 持仓扩成多行,进而重复
|
||||
// 参与后续风险/结算计算。先取得 EOD+BOD 的唯一持仓结果,再按标的代码匹配
|
||||
// 除权记录,可以把重复业务键暴露为 ToDictionary 异常,而不是静默扩行。
|
||||
var query = from eod in DbContext.Set<T>().Where(predicate)
|
||||
join bod in DbContext.BodTradePosition.Where(n => n.ValueDate == bodDate)
|
||||
on new { eod.BookId, eod.TradeType, eod.PositionType, eod.UnderlyingCode, ExchangeOptionCode = eod.ExchangeOptionCode ?? string.Empty }
|
||||
equals new { bod.BookId, bod.TradeType, bod.PositionType, bod.UnderlyingCode, ExchangeOptionCode = bod.ExchangeOptionCode ?? string.Empty } into t_bod
|
||||
from bod in t_bod.DefaultIfEmpty()
|
||||
join dividend in DbContext.ex_dividend_info.Where(O => O.ExDividendDate == settleDate && O.ValidStatus)
|
||||
on eod.UnderlyingCode equals dividend.UnderlyingCode into t_dividend
|
||||
from dividend in t_dividend.DefaultIfEmpty()
|
||||
select new
|
||||
{
|
||||
eod,
|
||||
@@ -55,24 +56,31 @@ namespace YLErp.Modules.EodModule
|
||||
bod.Amount,
|
||||
bod.Cost,
|
||||
//bod.AveragePrice
|
||||
},
|
||||
dividend
|
||||
}
|
||||
};
|
||||
|
||||
var datas = query.ToArray();
|
||||
var diviService = new TradeModule.DealModule.DividendService(OptUser);
|
||||
// 除权查询集中复用 DividendService 的有效记录条件。字典使用不区分大小写的
|
||||
// UnderlyingCode 匹配,兼容 EOD 与除权表代码大小写差异;如果同日同代码仍有
|
||||
// 多条有效记录,ToDictionary 会失败,提示迁移/结算前先清理重复数据。
|
||||
var dividendDict = diviService.GetExDividendQuery(settleDate)
|
||||
.ToDictionary(O => O.UnderlyingCode, O => O, StringComparer.OrdinalIgnoreCase);
|
||||
var eodPriceProvider = new EodPriceProvider(settleDate);
|
||||
return datas.Select(data =>
|
||||
{
|
||||
var eod = data.eod;
|
||||
var bod = data.bod;
|
||||
if (data.dividend != null)
|
||||
// 命中除权数据后仍沿用原有股票结算分支:只重算除权后的收盘价和数量,
|
||||
// 并保留原 Pv 的正负方向。其他 TradeType 当前不进入该分支,避免扩大
|
||||
// 本次查询重构的业务范围。
|
||||
if (dividendDict.TryGetValue(eod.UnderlyingCode, out var dividend))
|
||||
{
|
||||
if (data.eod.TradeType == "股票")
|
||||
{
|
||||
var SettlePrice = eodPriceProvider.GetPrice(data.eod.UnderlyingCode, SettlementTypeEnum.ClosePrice);
|
||||
SettlePrice = diviService.GetPrice(SettlePrice, data.dividend);
|
||||
var amount = diviService.GetPositionAmount(data.eod.Amount, data.dividend);
|
||||
SettlePrice = diviService.GetPrice(SettlePrice, dividend);
|
||||
var amount = diviService.GetPositionAmount(data.eod.Amount, dividend);
|
||||
eod.Pv = eod.Pv > 0 ? Math.Abs(amount * SettlePrice) : -Math.Abs(amount * SettlePrice);
|
||||
}
|
||||
}
|
||||
@@ -104,14 +112,14 @@ namespace YLErp.Modules.EodModule
|
||||
predicate = PredicateBuilder.Create<TPos>(n => n.ValueDate == settleDate).And(predicate);
|
||||
}
|
||||
|
||||
// 带风险数据的重载与上面的持仓重载采用相同策略:除权记录不参与 SQL 左连接,
|
||||
// 先完成 EOD、BOD、Risk 的行级关联,再在内存中按标的代码查找唯一除权记录,
|
||||
// 防止除权表重复行复制风险记录。
|
||||
var query = from eod in DbContext.Set<TPos>().AsNoTracking().Where(predicate)
|
||||
join bod in DbContext.BodTradePosition.Where(n => n.ValueDate == bodDate)
|
||||
on new { eod.BookId, eod.TradeType, eod.PositionType, eod.UnderlyingCode, ExchangeOptionCode = eod.ExchangeOptionCode ?? string.Empty }
|
||||
equals new { bod.BookId, bod.TradeType, bod.PositionType, bod.UnderlyingCode, ExchangeOptionCode = bod.ExchangeOptionCode ?? string.Empty } into t_bod
|
||||
from bod in t_bod.DefaultIfEmpty()
|
||||
join dividend in DbContext.ex_dividend_info.AsNoTracking().Where(O => O.ExDividendDate == settleDate && O.ValidStatus)
|
||||
on eod.UnderlyingCode equals dividend.UnderlyingCode into t_dividend
|
||||
from dividend in t_dividend.DefaultIfEmpty()
|
||||
join risk in DbContext.Set<TRisk>().AsNoTracking().Where(n => n.ValueDate == settleDate && n.TradeId > 0) on new { eod.ValueDate, eod.TradeId } equals new { risk.ValueDate, risk.TradeId } into risk_t
|
||||
from risk in risk_t.DefaultIfEmpty()
|
||||
select new
|
||||
@@ -123,24 +131,28 @@ namespace YLErp.Modules.EodModule
|
||||
bod.Cost,
|
||||
//bod.AveragePrice
|
||||
},
|
||||
dividend,
|
||||
risk
|
||||
};
|
||||
|
||||
var datas = query.ToArray();
|
||||
var diviService = new TradeModule.DealModule.DividendService(OptUser);
|
||||
// 与无风险重载保持同一数据来源、日期条件和大小写无关的代码匹配规则;重复
|
||||
// 有效记录会在这里显式失败,而不是让一条持仓对应多条风险结果。
|
||||
var dividendDict = diviService.GetExDividendQuery(settleDate)
|
||||
.ToDictionary(O => O.UnderlyingCode, O => O, StringComparer.OrdinalIgnoreCase);
|
||||
var eodPriceProvider = new EodPriceProvider(settleDate);
|
||||
return datas.Select(data =>
|
||||
{
|
||||
var pos = data.eod;
|
||||
var bod = data.bod;
|
||||
if (data.dividend != null)
|
||||
// 风险对象的除权 Pv 重算规则与上一个重载保持一致,仅在股票交易类型下执行。
|
||||
if (dividendDict.TryGetValue(pos.UnderlyingCode, out var dividend))
|
||||
{
|
||||
if (data.eod.TradeType == "股票")
|
||||
{
|
||||
var settlePrice = eodPriceProvider.GetPrice(data.eod.UnderlyingCode, SettlementTypeEnum.ClosePrice);
|
||||
settlePrice = diviService.GetPrice(settlePrice, data.dividend);
|
||||
var amount = diviService.GetPositionAmount(data.eod.Amount, data.dividend);
|
||||
settlePrice = diviService.GetPrice(settlePrice, dividend);
|
||||
var amount = diviService.GetPositionAmount(data.eod.Amount, dividend);
|
||||
pos.Pv = pos.Pv > 0 ? Math.Abs(amount * settlePrice) : -Math.Abs(amount * settlePrice);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user