feat(swap): 添加日志记录并修复数值计算精度问题

- 添加了静态日志记录器用于跟踪方法执行
- 在SwapPositionCompose和SwapEodCompose方法中添加详细的执行参数日志
- 为合约处理流程添加开始和结束状态日志
- 在利息腿归档逻辑中添加处理状态和参数的日志输出
- 将decimal类型的字面量从整数改为带m后缀以确保精度
- 修复了RealizedPnl计算公式,加入利息费用的影响
- 调整了名义金额计算方式,在关闭处理中排除平仓金额
- 修正了利息收入计算中的绝对值问题
- 在数据库操作前后添加详细的实体状态日志
This commit is contained in:
hjhan
2026-02-13 14:52:34 +08:00
parent 0fa526bffb
commit 5ba3618bca
@@ -18,6 +18,7 @@ namespace YLErp.Modules.SwapModule
public class SwapEodPositionService : SwapTradeBaseService
{
private List<int> marginTypes = new List<int>() { (int)InterestModeEnum., (int)InterestModeEnum. };
private static readonly IYcLogger Log = LogFactory.GetLogger(typeof(SwapEodPositionService).FullName);
public SwapEodPositionService(OptUserInfo optUser) : base(optUser)
{
@@ -61,6 +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));
var tradePredicate = PredicateBuilder.Create<trade>(n => n.ValidState != ConsGlobal.InValid
&& n.TradeType == "收益互换"
&& n.TradeDate <= settleDate
@@ -164,6 +166,7 @@ namespace YLErp.Modules.SwapModule
/// <param name="ClientIds"></param>
public void SwapEodCompose(DateTime settleDate, DateTime preSettleDate, IEnumerable<int> ClientIds)
{
Log.Info("SwapEodCompose:" + "settleDate:" + settleDate + " preSettleDate:" + preSettleDate + " ClientIds:" + JsonHelper.Serialize(ClientIds));
var tradePredicate = PredicateBuilder.Create<trade>(n => n.ValidState != ConsGlobal.InValid
&& n.TradeType == "收益互换"
&& n.TradeDate <= settleDate
@@ -177,7 +180,9 @@ namespace YLErp.Modules.SwapModule
var tradeQueryList = DbContext.trade.Where(tradePredicate).ToList();
foreach (var td in tradeQueryList)
{
Log.Info("【框架合约汇总】处理合约ID为:[" + td.id + "]的数据,收盘时间为:[" + settleDate + "]。开始");
SaveEodSwap(td, settleDate, preSettleDate);
Log.Info("【框架合约汇总】处理合约ID为:[" + td.id + "]的数据,收盘时间为:[" + settleDate + "]。结束");
}
DbContext.SaveChanges();
}
@@ -207,10 +212,12 @@ namespace YLErp.Modules.SwapModule
decimal grossPrice,
decimal orginPv)
{
Log.Info("===================处理利息腿归档====================");
var hasClose = flowEvents.Any(x => x.EventType == (int)SwapEventTypeEnum.);
var hasSwap = flowEvents.Any(x => x.EventType == (int)SwapEventTypeEnum.);
foreach (var interest in interestList)
{
Log.Info($"InterestMode is {interest.InterestMode},HappenDate is {interest.HappenDate},settleDate is {settleDate}");
if (interest.InterestMode == (int)InterestModeEnum. && interest.HappenDate > settleDate)
{
continue;
@@ -223,6 +230,7 @@ namespace YLErp.Modules.SwapModule
var dealInterest = dealInterests.FirstOrDefault(n => n.PositionId == interest.id);//当日是否做过互换或平仓
var swapEvents = flowEvents.Where(x => (x.EventType == (int)SwapEventTypeEnum. || x.EventType == (int)SwapEventTypeEnum.) && x.PositionId == interest.id).ToList();
//如果当日有互换/当日有平仓 不再重新生成或更新
Log.Info($"insterval is {insterval},hasSwap is {hasSwap},hasClose is {hasClose}");
if (insterval != null && !hasSwap)
{
if (!hasClose)//当日无平仓
@@ -276,9 +284,22 @@ namespace YLErp.Modules.SwapModule
DateTime preSettleDate,
List<swap_flow_event> flowEvents)
{
string settleDateStr = settleDate.ToString("yyyy-MM-dd");
string preSettleDateStr = preSettleDate.ToString("yyyy-MM-dd");
Log.Info($"================开始处理{settleDateStr}浮动腿归档==================");
List<eod_swap_position> list = new List<eod_swap_position>();
Log.Info($"浮动腿归档各项参数如下:\n " +
$"settleDate为:{settleDateStr} \n" +
$"preSettleDate为:{preSettleDateStr} \n " +
$"td为:{td.id} \n " +
$"posiList为:{JsonHelper.Serialize(posiList)} \n " +
$"realPosiList为:{JsonHelper.Serialize(realPosiList)} \n " +
$"eodPositions为:{JsonHelper.Serialize(eodPositions)} \n " +
$"todyEodPositions为:{JsonHelper.Serialize(todyEodPositions)} \n " +
$"flowEvents为:{JsonHelper.Serialize(flowEvents)} \n ");
foreach (var posi in posiList)
{
Log.Info($"posi为:{JsonHelper.Serialize(posi, false)}");
var eodPosition = eodPositions.Where(x => x.PositionId == posi.id).FirstOrDefault();//上一日日终持仓信息
var tdEodPosition = todyEodPositions.FirstOrDefault(x => x.PositionId == posi.id);//当前结算日日终持仓信息
var unwindEvents = flowEvents.Where(x => x.PositionId == posi.id).ToList();//当前日平仓信息
@@ -296,8 +317,10 @@ namespace YLErp.Modules.SwapModule
{
eodPosi = UpdateEodPosition(posi, eodPosition, tdEodPosition, td, settleDate, preSettleDate, unwindEvents);
}
Log.Info($"eodPosi为:{JsonHelper.Serialize(eodPosi, false)}");
list.Add(eodPosi);
}
Log.Info($"================{settleDateStr}浮动腿归档结束==================");
return list;
}
/// <summary>
@@ -570,6 +593,7 @@ namespace YLErp.Modules.SwapModule
DateTime valueDate,
List<swap_flow_event> flowEvents)
{
Log.Info($"eodPayPosition is {JsonHelper.Serialize(eodPayPosition, false)},newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}");
if (eodPayPosition == null)
{
eodPayPosition = new eod_swap_position();
@@ -579,7 +603,7 @@ namespace YLErp.Modules.SwapModule
eodPayPosition.PosiMatuirityDate = td.ExerciseDate.Value;
}
var tradeExtend = td.trade_extend.ExtendObj;
decimal ratio = position.InterestDirection == (int)SwapDirectionEnum. ? 1 : -1;//收取为正,支付为负
decimal ratio = position.InterestDirection == (int)SwapDirectionEnum. ? 1m : -1m;//收取为正,支付为负
if (marginTypes.Contains(position.InterestMode))
{
ratio = -ratio;
@@ -655,7 +679,7 @@ namespace YLErp.Modules.SwapModule
/// <param name="lastEodSwap">上一日终框架合约估值</param>
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($"eodPayPosition is {JsonHelper.Serialize(eodPayPosition, false)},newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}");
var tradeExtend = td.trade_extend.ExtendObj;
decimal oriPosiNotionalValue = posiLongNotional + posiShortNational;
decimal posiNotionalValue = oriPosiNotionalValue;
@@ -665,7 +689,7 @@ namespace YLErp.Modules.SwapModule
posiNotionalValue = lastEodSwap.NotionalValue;
}
decimal closePercent = 1;
decimal ratio = position.InterestDirection == (int)SwapDirectionEnum. ? 1 : -1;//收取为正,支付为负
decimal ratio = position.InterestDirection == (int)SwapDirectionEnum. ? 1m : -1m;//收取为正,支付为负
if (marginTypes.Contains(position.InterestMode))
{
ratio = -ratio;
@@ -723,6 +747,7 @@ namespace YLErp.Modules.SwapModule
// newEodPayPosition.TdCloseInterestFee = newEodPayPosition.TdInterestFee;
//持仓内容-利息腿-损益统计(本方视角)
newEodPayPosition.TdInterestIncome = TdInterestAmount;
Log.Info($"InterestFeeSum is {eodPayPosition.InterestFeeSum},TdInterestFee is {newEodPayPosition.TdInterestFee},TdCloseInterestFee is {newEodPayPosition.TdCloseInterestFee}");
newEodPayPosition.InterestIncomeSum = 0;
newEodPayPosition.InterestFeeSum = eodPayPosition.InterestFeeSum + newEodPayPosition.TdInterestFee - newEodPayPosition.TdCloseInterestFee;
newEodPayPosition.InterestProfitSum = newEodPayPosition.InterestIncomeSum + newEodPayPosition.InterestFeeSum;
@@ -732,7 +757,7 @@ namespace YLErp.Modules.SwapModule
//累计已实现
newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio;
newEodPayPosition.RealizedInterestFee = eodPayPosition.RealizedInterestFee + newEodPayPosition.TdCloseInterestFee;
newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest;
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);
@@ -740,6 +765,7 @@ namespace YLErp.Modules.SwapModule
{
DbContext.eod_swap_position.Add(newEodPayPosition);
}
Log.Info($"the last newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}");
return interests;
}
@@ -758,11 +784,11 @@ namespace YLErp.Modules.SwapModule
/// <param name="unwintotal">平仓主信息</param>
private List<swap_flow_event> SaveAutoEodWithCloseInterestPosition(eod_swap_position eodPayPosition, eod_swap_position newEodPayPosition, swap_position position, trade td, DateTime valueDate, IntervalModel interval, decimal posiLongNotional, decimal posiShortNational, List<swap_flow_event> flowEvents, decimal closeNational, bool autoSwap, decimal grossPrice, decimal orginPv)
{
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 ratio = position.InterestDirection == (int)SwapDirectionEnum. ? 1 : -1;//收取为正,支付为负
decimal posiNotionalValue = posiLongNotional + posiShortNational;
decimal ratio = position.InterestDirection == (int)SwapDirectionEnum. ? 1m : -1m;//收取为正,支付为负
if (marginTypes.Contains(position.InterestMode))
{
ratio = -ratio;
@@ -837,13 +863,17 @@ namespace YLErp.Modules.SwapModule
newEodPayPosition.TdInterestFee = flowEvents.Sum(s => s.InterestFee);
newEodPayPosition.TdCloseInterestFee = newEodPayPosition.TdInterestFee;
newEodPayPosition.TdCloseInterest = flowEvents.Sum(s => s.InterestClosePnL);
Log.Info($"InterestIncomeSum is {eodPayPosition.InterestIncomeSum},TdInterestIncome is {newEodPayPosition.TdInterestIncome}" +
$",TdCloseInterest is {newEodPayPosition.TdCloseInterest}");
Log.Info($"InterestFeeSum is {eodPayPosition.InterestFeeSum},TdInterestFee is {newEodPayPosition.TdInterestFee}" +
$",TdCloseInterestFee is {newEodPayPosition.TdCloseInterestFee}");
if (closePercent == 1)
{
newEodPayPosition.InterestIncomeSum = 0;
}
else
{
newEodPayPosition.InterestIncomeSum = eodPayPosition.InterestIncomeSum + TdInterestAmount - Math.Abs(newEodPayPosition.TdCloseInterest);
newEodPayPosition.InterestIncomeSum = eodPayPosition.InterestIncomeSum + TdInterestAmount - newEodPayPosition.TdCloseInterest;
}
//持仓内容-利息腿-损益统计(本方视角)
newEodPayPosition.TdInterestIncome = TdInterestAmount * (1 - closePercent);
@@ -852,13 +882,18 @@ namespace YLErp.Modules.SwapModule
//持仓价值
newEodPayPosition.SwapPositionValue = newEodPayPosition.InterestProfitSum * ratio + newEodPayPosition.PosiProfitSum;
Log.Info($"InterestIncomeSum is {eodPayPosition.InterestIncomeSum},TdInterestIncome is {newEodPayPosition.TdInterestIncome}" +
$",TdCloseInterest is {newEodPayPosition.TdCloseInterest}");
Log.Info($"InterestFeeSum is {eodPayPosition.InterestFeeSum},TdInterestFee is {newEodPayPosition.TdInterestFee}" +
$",TdCloseInterestFee is {newEodPayPosition.TdCloseInterestFee}");
//累计已实现
newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio ;
newEodPayPosition.RealizedInterestFee = eodPayPosition.RealizedInterestFee + newEodPayPosition.TdCloseInterestFee;
newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest;
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);
Log.Info($"即将插入数据库的 newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}");
if (newEodPayPosition.id == 0)
{
DbContext.eod_swap_position.Add(newEodPayPosition);
@@ -876,6 +911,7 @@ namespace YLErp.Modules.SwapModule
/// <param name="td">互换交易主干</param>
private void SaveEodInterestPositionCopy(eod_swap_position eodPayPosition, eod_swap_position newEodPayPosition, DateTime valueDate, trade td, swap_position position, eod_swap lastEodSwap, bool needPrice, decimal posiLongNational, decimal posiShortNational, decimal grossPrice, decimal orginPv)
{
Log.Info($"eodPayPosition is {JsonHelper.Serialize(eodPayPosition, false)},newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}");
List<IntervalModel> intervals = position.SwapIntervalList;
var tradeExtend = td.trade_extend.ExtendObj;
if (eodPayPosition == null)
@@ -931,7 +967,7 @@ namespace YLErp.Modules.SwapModule
{
closePercent = 1;
}
decimal ratio = eodPayPosition.InterestDirection == (int)SwapDirectionEnum. ? 1 : -1;//收取为正,支付为负
decimal ratio = eodPayPosition.InterestDirection == (int)SwapDirectionEnum. ? 1m : -1m;//收取为正,支付为负
if (marginTypes.Contains(position.InterestMode))
{
ratio = -ratio;
@@ -963,6 +999,10 @@ namespace YLErp.Modules.SwapModule
//持仓内容-利息腿-损益统计(本方视角)
newEodPayPosition.TdInterestIncome = TdInterestAmount;
newEodPayPosition.TdInterestFee = 0;
Log.Info($"InterestIncomeSum is {eodPayPosition.InterestIncomeSum},TdInterestIncome is {newEodPayPosition.TdInterestIncome}" +
$",TdCloseInterest is {newEodPayPosition.TdCloseInterest}");
Log.Info($"InterestFeeSum is {eodPayPosition.InterestFeeSum},TdInterestFee is {newEodPayPosition.TdInterestFee}" +
$",TdCloseInterestFee is {newEodPayPosition.TdCloseInterestFee}");
newEodPayPosition.InterestIncomeSum = eodPayPosition.InterestIncomeSum + newEodPayPosition.TdInterestIncome - newEodPayPosition.TdCloseInterest;
newEodPayPosition.InterestFeeSum = eodPayPosition.InterestFeeSum + newEodPayPosition.TdInterestFee - newEodPayPosition.TdCloseInterestFee;
newEodPayPosition.InterestProfitSum = newEodPayPosition.InterestIncomeSum + newEodPayPosition.InterestFeeSum;
@@ -972,10 +1012,11 @@ namespace YLErp.Modules.SwapModule
//累计已实现
newEodPayPosition.RealizedInterest = eodPayPosition.RealizedInterest + newEodPayPosition.TdCloseInterest * ratio;
newEodPayPosition.RealizedInterestFee = eodPayPosition.RealizedInterestFee + newEodPayPosition.TdCloseInterestFee;
newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest;
newEodPayPosition.RealizedPnl = newEodPayPosition.RealizedInterest + newEodPayPosition.RealizedInterestFee;
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, valueDate
, seekPreday: true, currencyRateType: eodPayPosition.InterestDirection == (int)SwapDirectionEnum. ? CurrencyRateType.Buy : CurrencyRateType.Sell);
newEodPayPosition.TdCurrency = Convert.ToDecimal(currencyRate);
Log.Info($"the last newEodPayPosition is {JsonHelper.Serialize(newEodPayPosition, false)}");
if (newEodPayPosition.id == 0)
{
DbContext.eod_swap_position.Add(newEodPayPosition);