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; }
}
}
}