using DocumentFormat.OpenXml.Drawing.Charts; using System.Linq.Expressions; using YLErp.Helpers; using YLErp.Models; using YLErp.QdpModule; namespace YLErp.Modules.DataProviderModule { /// /// 收盘价查询服务 /// public class EodPriceQueryService { /// /// 检查数据库是否有数据 /// public static bool CheckDbExists(DateTime valueDate) { using var db = DbContextFactory.GetYLDbContext(); return db.eod_commodity_future_price.Any(n => n.ValueDate == valueDate) || db.eod_stock_price.Any(n => n.ValueDate == valueDate) || db.china_bond_valuation.Any(n => n.valuation_date == valueDate && n.dirty_price_close > 0); } /// /// 校验FR007价格 /// /// /// public static bool CheckFR007Price(DateTime valueDate) { using var db = DbContextFactory.GetYLDbContext(); return db.eod_commodity_future_price.Any(n => n.ValueDate == valueDate && n.UnderlyingCode == "FR007"); } /// /// 检查是否存在收盘价 /// public static bool CheckDbExists(DateTime startDate, DateTime valueDate, string instrumentType, string underlyingCode) { using var db = DbContextFactory.GetYLDbContext(); if (ConsGlobal.InstrumentType.IsStock(instrumentType)) { var query = from e in db.eod_stock_price where e.UnderlyingCode == underlyingCode && e.ValueDate >= startDate && e.ValueDate <= valueDate select e; return query.Any(); } else if (ConsGlobal.InstrumentType.IsBond(instrumentType)) { //日终估值全价必须有值才算 var query = from e in db.china_bond_valuation where e.bond_id == underlyingCode && e.valuation_date >= startDate && e.valuation_date <= valueDate && e.dirty_price_close > 0 select e; return query.Any(); } else { var query = from e in db.eod_commodity_future_price where e.UnderlyingCode == underlyingCode && e.ValueDate >= startDate && e.ValueDate <= valueDate select e; return query.Any(); } } /// /// 获取标的某日的收盘价 /// public static bool TryGetClosePrice(DateTime valueDate, string underlyingCode, out double price) { if (underlyingCode is null) { throw new ArgumentNullException(nameof(underlyingCode)); } var ep = GetEodPrice(valueDate, underlyingCode); if (ep != null) { price = ep.ClosePrice; return true; } price = 0; return false; } /// /// 获取标的某日的收盘价 /// public static double GetClosePrice(DateTime valueDate, string underlyingCode) { return TryGetClosePrice(valueDate, underlyingCode, out var price) ? price : 0; } /// /// 尝试获取标的某日的日终价 /// public static bool TryGetEodPrice(DateTime valueDate, string underlyingCode, out EodPrice eodPrice) { return (eodPrice = GetEodPrice(valueDate, underlyingCode)) != null; } /// /// 尝试获取某日债券价格 /// /// /// /// /// public static bool TryGetBondEodPrice(DateTime valueDate, string underlyingCode, out EodPrice eodPrice) { return (eodPrice = GetBondPrice(valueDate, underlyingCode)) != null; } /// /// 统一日终结算取价(债券感知)。 /// 用于交易/期权到期结算:债券标的走中债估值表(TryGetBondEodPrice),期货/股票走原 InnerGetEodPrice。 /// 解决到期路径(tradeExpireInner / MultipleTradeExpireConfirm)漏查债券表导致"结算价未找到"的问题。 /// 注:债券 ClosePrice/SettlePrice 映射沿用 GetBondPrice 口径(ClosePrice=全价 dirty_price_close,SettlePrice=净价 net_price), /// 与 EodPriceProvider 的映射(ClosePrice=净价,SettlePrice=全价)相反——属历史不一致(见 EodPriceProvider.Initialize 与 GetBondPrice 的注释), /// 本方法保持与系统既有"债券现价"约定(UnderlyingCodePrice)一致,不引入新口径。 /// public static bool TryGetSettlementEodPrice(DateTime valueDate, string underlyingCode, out EodPrice eodPrice) { var um = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode); if (um != null && ConsGlobal.InstrumentType.IsBond(um.UnderlyingInstrumentType)) { return TryGetBondEodPrice(valueDate, underlyingCode, out eodPrice); } return TryGetEodPrice(valueDate, underlyingCode, out eodPrice); } /// /// 尝试获取标的某日的日终价 /// public static bool TryGetEodPrice(DateTime valueDate, int underlyingId, out EodPrice eodPrice) { return (eodPrice = GetEodPrice(valueDate, underlyingId)) != null; } /// /// 获取某日之前最新价格 /// /// /// /// /// public static bool TryGetPrice(DateTime valueDate, string underlyingCode, out double price) { price = 0; valueDate = valueDate.Date; using var db = DbContextFactory.GetYLDbContext(); var data = db.eod_commodity_future_price.Where(x => x.ValueDate == valueDate && x.UnderlyingCode == underlyingCode).OrderByDescending(o => o.ValueDate).FirstOrDefault(); if (data != null) { // FR007 行 ReferencePrice 已是小数口径(无论 bond-sync 自动同步还是界面手工录入,写入时均已 ÷100), // 利息腿计算直接作为 floatRate 参与 principal*(fixedRate+floatRate)/annualDays,无需再 ÷100。 price = data.ReferencePrice ?? 0; return true; } return false; } /// /// 尝试获取标的某日的日终价 /// public static bool TryGetReferencePrice(DateTime valueDate, string underlyingCode, out double price) { price = 0; valueDate = valueDate.Date; //传进来的可能是非交易日期 valueDate = PS.Config.IsGuoJun ? QdpCalendarHelper.GetNonHolidayDefore(valueDate) : QdpCalendarHelper.GetNonHoliday(valueDate); using var db = DbContextFactory.GetYLDbContext(); var umQuery = db.underlying_manager.Where(n => n.UnderlyingCode == underlyingCode) .Select(u => new UnderlyingDto { id = u.id, UnderlyingCode = u.UnderlyingCode, ValueDate = u.UnderlyingInstrumentType != ConsGlobal.InstrumentType.CommodityFutures || u.MaturityDate > valueDate ? valueDate : u.MaturityDate.Value }); var eodQuery = from um in umQuery join epCommodity in db.eod_commodity_future_price on new { um.ValueDate, um.UnderlyingCode } equals new { ValueDate = epCommodity.ValueDate, UnderlyingCode = epCommodity.UnderlyingCode } into t_epCommodity from epCommodity in t_epCommodity.DefaultIfEmpty() join epStock in db.eod_stock_price on new { um.ValueDate, um.UnderlyingCode } equals new { ValueDate = epStock.ValueDate, UnderlyingCode = epStock.UnderlyingCode } into t_epStock from epStock in t_epStock.DefaultIfEmpty() join epBond in db.china_bond_valuation on new { um.ValueDate, um.UnderlyingCode } equals new { ValueDate = epBond.valuation_date, UnderlyingCode = epBond.bond_id } into t_epBond from epBond in t_epBond.DefaultIfEmpty() select new { rp1 = epCommodity.ReferencePrice, rp2 = epStock.ReferencePrice, rp3 = epBond.dirty_price_close }; var data = eodQuery.FirstOrDefault(); if (data != null && (data.rp1 != null || data.rp2 != null || data.rp3 != null)) { price = data.rp1 ?? data.rp2 ?? Convert.ToDouble((data.rp3 ?? 0) * ConsGlobal.bondPriceMultiple); return true; } return false; } /// /// 获取标的某日的日终价,如果未找到返回null /// public static EodPrice GetEodPrice(DateTime valueDate, int underlyingId) { return underlyingId < 1 ? null : InnerGetEodPrice(valueDate, n => n.id == underlyingId); } /// /// 获取标的某日的日终价,如果未找到返回null /// public static EodPrice GetEodPrice(DateTime valueDate, string underlyingCode) { return string.IsNullOrWhiteSpace(underlyingCode) ? null : InnerGetEodPrice(valueDate, n => n.UnderlyingCode == underlyingCode); } /// /// 获取债券某日日终价格,如果未找到返回null /// /// /// /// public static EodPrice GetBondPrice(DateTime valueDate, string underlyingCode) { using var db = DbContextFactory.GetYLDbContext(); var bondPrice = db.china_bond_valuation.Where(x => x.bond_id == underlyingCode && x.valuation_date <= valueDate).OrderByDescending(o => o.credibility).ThenByDescending(o => o.valuation_date).FirstOrDefault(); if (bondPrice == null) { return null; } return new EodPrice { Vobp = bondPrice.vobp, ValueDate = valueDate, UnderlyingCode = underlyingCode, // [Layer2-待统一] 债券映射口径:ClosePrice=全价(dirty_price_close),SettlePrice=净价(net_price)。 // 注意:这与 EodPriceProvider.Initialize 的映射【完全相反】(EodPriceProvider: ClosePrice=净价,SettlePrice=全价)。 // 两处对"债券收盘价/结算价"的净全价定义不一致属历史遗留,请勿随意改动单侧,需业务先定调后统一(见 TryGetSettlementEodPrice 注释)。 ClosePrice = Convert.ToDouble(BondPriceConverter.ToStorage(bondPrice.dirty_price_close)), SettlePrice = Convert.ToDouble(BondPriceConverter.ToStorage(bondPrice.net_price)), ReferencePrice = Convert.ToDouble(BondPriceConverter.ToStorage(bondPrice.yield)) }; } /// /// 获取中债估值最新价格 /// /// /// /// public static ChinaBondValuation GetChinaBondPrice(DateTime valueDate, string underlyingCode) { using var db = DbContextFactory.GetYLDbContext(); var bondPrice = db.china_bond_valuation.Where(x => x.bond_id == underlyingCode && x.valuation_date <= valueDate).OrderByDescending(o => o.credibility).ThenByDescending(o => o.valuation_date).FirstOrDefault(); return bondPrice; } /// /// 获取标的收盘价格 /// /// 标的代码 /// 收盘日 /// public static double UnderlyingCodePrice(string code, DateTime settleDate) { var data = DataCacheProvider.GetUnderlyingDataSource().GetData(code); if (data == null) { return 0; } if (data.IsBond()) { var eodBondPrice = GetBondPrice(settleDate, code); return eodBondPrice?.ClosePrice ?? 0; } var price = data.Price ?? 0; if (TryGetEodPrice(settleDate, code, out var eodPrice)) { price = eodPrice.GetPrice(SettlementTypeEnum.ClosePrice); } return price; } /// /// 获取标的某日的日终价,如果未找到返回null /// private static EodPrice InnerGetEodPrice(DateTime valueDate, Expression> umPredicate) { if (umPredicate is null) { return null; } valueDate = valueDate.Date; //传进来的可能是非交易日期 valueDate = PS.Config.IsGuoJun ? QdpCalendarHelper.GetNonHolidayDefore(valueDate) : QdpCalendarHelper.GetNonHoliday(valueDate); using var db = DbContextFactory.GetYLDbContext(); var umQuery = db.underlying_manager.Where(umPredicate) .Select(u => new UnderlyingDto { id = u.id, UnderlyingCode = u.UnderlyingCode, ValueDate = u.UnderlyingInstrumentType != ConsGlobal.InstrumentType.CommodityFutures || u.MaturityDate > valueDate || u.MaturityDate == null ? valueDate : u.MaturityDate.Value }); var eodQuery = from um in umQuery join epCommodity in db.eod_commodity_future_price on new { um.ValueDate, um.UnderlyingCode } equals new { ValueDate = epCommodity.ValueDate, UnderlyingCode = epCommodity.UnderlyingCode } into t_epCommodity from epCommodity in t_epCommodity.DefaultIfEmpty() join epStock in db.eod_stock_price on new { um.ValueDate, um.UnderlyingCode } equals new { ValueDate = epStock.ValueDate, UnderlyingCode = epStock.UnderlyingCode } into t_epStock from epStock in t_epStock.DefaultIfEmpty() select new { um.ValueDate, UnderlyingId = um.id, um.UnderlyingCode, unPrice1 = epCommodity == null ? null : new { epCommodity.ClosePrice, epCommodity.SettlePrice, epCommodity.ReferencePrice, epCommodity.HighPrice, epCommodity.LowPrice, }, unPrice2 = epStock == null ? null : new { epStock.ClosePrice, SettlePrice = epStock.ClosePrice, ReferencePrice = epStock.ReferencePrice, epStock.HighPrice, epStock.LowPrice, epStock.UnderlyingStatus, } }; //db.SetDebugLog(); var data = eodQuery.FirstOrDefault(); if (data != null) { if (data.unPrice1 != null) { var up = data.unPrice1; return new EodPrice { ValueDate = data.ValueDate, UnderlyingId = data.UnderlyingId, UnderlyingCode = data.UnderlyingCode, ClosePrice = up.ClosePrice, SettlePrice = up.SettlePrice, ReferencePrice = up.ReferencePrice, HighPrice = up.HighPrice, LowPrice = up.LowPrice }; } else if (data.unPrice2 != null) { var up = data.unPrice2; return new EodPrice { IsStock = true, ValueDate = data.ValueDate, UnderlyingId = data.UnderlyingId, UnderlyingCode = data.UnderlyingCode, ClosePrice = up.ClosePrice, SettlePrice = up.SettlePrice, ReferencePrice = up.ReferencePrice, HighPrice = up.HighPrice, LowPrice = up.LowPrice, UnderlyingStatus = up.UnderlyingStatus }; } } return null; } /// /// /// /// /// /// public static List GetEodPriceByUnserialDates(List unserialDates, int underlyingId) { var um = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingId); if (um == null) { throw new ServiceException("未找到对应标的"); } using var DbContext = DbContextFactory.GetYLDbContext(); if (ConsGlobal.InstrumentType.IsStock(um.UnderlyingInstrumentType)) { var query = from eod in DbContext.eod_stock_price where eod.UnderlyingCode == um.UnderlyingCode && unserialDates.Contains(eod.ValueDate) select new EodPrice { ValueDate = eod.ValueDate, UnderlyingCode = eod.UnderlyingCode, ClosePrice = eod.ClosePrice, HighPrice = eod.HighPrice, LowPrice = eod.LowPrice, ReferencePrice = eod.ReferencePrice, SettlePrice = eod.ClosePrice }; return query.ToList(); } else { var query = from eod in DbContext.eod_commodity_future_price where eod.UnderlyingCode == um.UnderlyingCode && unserialDates.Contains(eod.ValueDate) select new EodPrice { ValueDate = eod.ValueDate, UnderlyingCode = eod.UnderlyingCode, ClosePrice = eod.ClosePrice, SettlePrice = eod.SettlePrice, HighPrice = eod.HighPrice, LowPrice = eod.LowPrice, ReferencePrice = eod.ReferencePrice }; return query.ToList(); } } /// /// /// /// /// /// public static List GetEodPriceByUnserialDateRange(DateTime startDate, DateTime valueDate, string underlyingCode, bool throwIfNotFoundUnderlying = false) { var um = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode); if (um == null) { if (throwIfNotFoundUnderlying) { throw new ServiceException("未找到对应标的"); } return new List(); } using var DbContext = DbContextFactory.GetYLDbContext(); if (ConsGlobal.InstrumentType.IsStock(um.UnderlyingInstrumentType)) { var query = from eod in DbContext.eod_stock_price where eod.UnderlyingCode == um.UnderlyingCode && eod.HighPrice.HasValue && eod.LowPrice.HasValue && eod.ValueDate >= startDate && eod.ValueDate <= valueDate select new EodPrice { ValueDate = eod.ValueDate, UnderlyingCode = eod.UnderlyingCode, ClosePrice = eod.ClosePrice, HighPrice = eod.HighPrice, LowPrice = eod.LowPrice, ReferencePrice = eod.ReferencePrice, SettlePrice = eod.ClosePrice }; return query.ToList(); } else { var query = from eod in DbContext.eod_commodity_future_price where eod.UnderlyingCode == um.UnderlyingCode && eod.HighPrice.HasValue && eod.LowPrice.HasValue && eod.ValueDate >= startDate && eod.ValueDate <= valueDate select new EodPrice { ValueDate = eod.ValueDate, UnderlyingCode = eod.UnderlyingCode, ClosePrice = eod.ClosePrice, SettlePrice = eod.SettlePrice, HighPrice = eod.HighPrice, LowPrice = eod.LowPrice, ReferencePrice = eod.ReferencePrice }; return query.ToList(); } } class UnderlyingDto { public int id { get; set; } public string UnderlyingCode { get; set; } public DateTime ValueDate { get; set; } } } }