Files
zszq-trs/YLErpDAL/Modules/EodModule/SettlementModule/EodSyntheticPriceSaveService.cs
T
hjhan 75988a33eb fix: eod_commodity_future_price 入库前以 UnderlyingCode 重派生 UnderlyingId,防止 FR007 等价格行 UnderlyingId 与 FutureContractId 失同步
- 新增 EodPriceService.SyncUnderlyingIdFromCode:入库前以 UnderlyingCode(FutureContractId) 为准反查真实 UnderlyingId,不一致则告警并自动校正
- SaveEodFuturePrice(web编辑/新增)、SettlementPriceImportService(xlsx上传)、EodSyntheticPriceSaveService(系统合成价) 写入前调用
- 根治'网页端能查到、EOD结算查不到'的失同步问题
2026-07-17 10:32:57 +08:00

243 lines
9.1 KiB
C#

using System.ComponentModel.DataAnnotations.Schema;
using YLErp.Modules.DataProviderModule;
namespace YLErp.Modules.EodModule.SettlementModule
{
/// <summary>
/// 合成组合标的价格服务
/// </summary>
class EodSyntheticPriceSaveService : EodSettleServiceBase
{
public const string Step = "合成组合标的价格";
public EodSyntheticPriceSaveService(EodSettlementContextBase context) : base(context)
{
}
//todo:还没有经过单元测试
/// <summary>
/// 保存组合标的日终结算价格
/// </summary>
public void Execute()
{
_context?.LogInfo("开始执行,获取组合标的数据");
//-------------------------------
//组合标的获取
//-------------------------------
var query = from a in DbContext.synthetic_underlying
join b in DbContext.underlying_manager on a.Name equals b.UnderlyingCode
join c in DbContext.eod_commodity_future_price.Where(n => n.ValueDate == SettleDate)
on b.UnderlyingCode equals c.UnderlyingCode into c_t
from c in c_t.DefaultIfEmpty()
join d in DbContext.eod_stock_price.Where(n => n.ValueDate == SettleDate)
on b.UnderlyingCode equals d.UnderlyingCode into d_t
from d in d_t.DefaultIfEmpty()
where b.CommodityCode == "组合标的" && b.MaturityDate >= SettleDate
select new synthetic_underlyingDto
{
id = a.id,
Name = a.Name,
Constant = a.Constant,
Coefficient1 = a.Coefficient1,
Coefficient3 = a.Coefficient3,
Coefficient2 = a.Coefficient2,
Coefficient4 = a.Coefficient4,
UnderlyingCode1 = a.UnderlyingCode1,
UnderlyingCode2 = a.UnderlyingCode2,
UnderlyingCode3 = a.UnderlyingCode3,
UnderlyingCode4 = a.UnderlyingCode4,
RelUnderlyingId = b.id,
RelUnderlyingInstrumentType = b.UnderlyingInstrumentType,
CommodityPrice = c,
StockPrice = d,
};
var synArr = query.ToArray();
var synLen = synArr.Length;
if (synLen < 1)
{
_context?.LogInfo("未获取到组合标的数据");
return;
}
_context?.LogInfo("获取到的组合标的数量:" + synLen);
//-------------------------------
//更新组合标的价格
//-------------------------------
var eodPriceProvider = _context.GetEodPriceProvider();
foreach (var item in synArr)
{
GetCombinClosePrice(item, eodPriceProvider);
}
var changes = DbContext.SaveChanges();
_context?.LogInfo($"组合标的合成价格后保存到数据库,组合标的数量:{synLen},更新数量:{changes}");
}
/// <summary>
/// 获取组合标的收盘价
/// </summary>
private void GetCombinClosePrice(synthetic_underlyingDto dto, EodPriceProvider eodPriceProvider)
{
double closePrice = 0;
double settlePrice = 0;
var arr = new (string, double)[] {
(dto.UnderlyingCode1,dto.Coefficient1??0),
(dto.UnderlyingCode2,dto.Coefficient2??0),
(dto.UnderlyingCode3,dto.Coefficient3??0),
(dto.UnderlyingCode4,dto.Coefficient4??0)
};
_context?.LogInfo($"[组合标的:{dto.Name}]开始合成收盘价");
if (ConsGlobal.InstrumentType.CalcTypeIsFutures(dto.RelUnderlyingInstrumentType))
{
foreach ((var underlyingcode, var coefficient) in arr)
{
if (string.IsNullOrWhiteSpace(underlyingcode))
{
continue;
}
if (eodPriceProvider.TryGetEodPrice(underlyingcode, out var price))
{
closePrice += price.ClosePrice * coefficient;
settlePrice += price.SettlePrice * coefficient;
}
else
{
_context?.LogError($"[组合标的:{dto.Name}]未取到标的收盘价,标的代码:{underlyingcode}");
return;
}
}
closePrice += dto.Constant ?? 0;
settlePrice += dto.Constant ?? 0;
_context?.LogInfo($"[组合标的:{dto.Name}]收盘价:{closePrice}");
if (dto.CommodityPrice != null)
{
DbContext.Entry(dto.CommodityPrice).State = EntityState.Unchanged;
if (Math.Abs(dto.CommodityPrice.ClosePrice - closePrice) > 0.0001
|| Math.Abs(dto.CommodityPrice.SettlePrice - settlePrice) > 0.0001)
{
dto.CommodityPrice.OptDate = DateTime.Now;
dto.CommodityPrice.ClosePrice = closePrice;
dto.CommodityPrice.SettlePrice = settlePrice;
dto.CommodityPrice.DataSource = EodPriceBase.系统;
}
}
else
{
dto.CommodityPrice = new eod_commodity_future_price
{
UnderlyingCode = dto.Name,
ValueDate = SettleDate,
OptDate = DateTime.Now,
UnderlyingId = dto.RelUnderlyingId,
ClosePrice = closePrice,
SettlePrice = settlePrice,
DataSource = EodPriceBase.系统
};
// 入库前强制 UnderlyingId 与 UnderlyingCode(FutureContractId) 一致,避免网页/结算两套 JOIN 失同步。
EodPriceService.SyncUnderlyingIdFromCode(DbContext, dto.CommodityPrice);
DbContext.eod_commodity_future_price.Add(dto.CommodityPrice);
}
SetDBModelOpt(dto.CommodityPrice);
}
else if ("Stock".Equals(dto.RelUnderlyingInstrumentType, StringComparison.OrdinalIgnoreCase))
{
foreach ((var underlyingcode, var coefficient) in arr)
{
if (string.IsNullOrWhiteSpace(underlyingcode))
{
continue;
}
if (eodPriceProvider.TryGetEodPrice(underlyingcode, out var price))
{
closePrice += price.ClosePrice * coefficient;
}
else
{
_context?.LogError($"[组合标的:{dto.Name}]未取到标的收盘价,标的代码:{underlyingcode}");
return;
}
}
closePrice += dto.Constant ?? 0;
_context?.LogInfo($"[组合标的:{dto.Name}]收盘价:{closePrice}");
if (dto.StockPrice != null)
{
DbContext.Entry(dto.StockPrice).State = EntityState.Unchanged;
if (Math.Abs(dto.StockPrice.ClosePrice - closePrice) > 0.0001)
{
dto.StockPrice.OptDate = DateTime.Now;
dto.StockPrice.ClosePrice = closePrice;
}
}
else
{
dto.StockPrice = new eod_stock_price
{
UnderlyingCode = dto.Name,
ValueDate = DateTime.Today,
OptDate = DateTime.Now,
ClosePrice = closePrice,
SettlePrice = closePrice,
DataSource = EodPriceBase.系统,
};
DbContext.eod_stock_price.Add(dto.StockPrice);
}
SetDBModelOpt(dto.StockPrice);
}
else
{
_context?.LogInfo($"[组合标的:{dto.Name},未处理]标的类型不支持:" + dto.RelUnderlyingInstrumentType);
}
}
/// <summary>
/// DTO
/// </summary>
[NotMapped]
private class synthetic_underlyingDto : SyntheticUnderlying
{
public int RelUnderlyingId { get; set; }
public string RelUnderlyingInstrumentType { get; set; }
public eod_stock_price StockPrice { get; set; }
public eod_commodity_future_price CommodityPrice { get; set; }
}
}
}