Files
zszq-trs/YLErpDAL/Modules/DataProviderModule/EodPriceQueryService.cs
T

545 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using DocumentFormat.OpenXml.Drawing.Charts;
using System.Linq.Expressions;
using YLErp.Helpers;
using YLErp.Models;
using YLErp.QdpModule;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 收盘价查询服务
/// </summary>
public class EodPriceQueryService
{
/// <summary>
/// 检查数据库是否有数据
/// </summary>
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);
}
/// <summary>
/// 校验FR007价格
/// </summary>
/// <param name="valueDate"></param>
/// <returns></returns>
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");
}
/// <summary>
/// 检查是否存在收盘价
/// </summary>
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();
}
}
/// <summary>
/// 获取标的某日的收盘价
/// </summary>
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;
}
/// <summary>
/// 获取标的某日的收盘价
/// </summary>
public static double GetClosePrice(DateTime valueDate, string underlyingCode)
{
return TryGetClosePrice(valueDate, underlyingCode, out var price) ? price : 0;
}
/// <summary>
/// 尝试获取标的某日的日终价
/// </summary>
public static bool TryGetEodPrice(DateTime valueDate, string underlyingCode, out EodPrice eodPrice)
{
return (eodPrice = GetEodPrice(valueDate, underlyingCode)) != null;
}
/// <summary>
/// 尝试获取某日债券价格
/// </summary>
/// <param name="valueDate"></param>
/// <param name="underlyingCode"></param>
/// <param name="eodPrice"></param>
/// <returns></returns>
public static bool TryGetBondEodPrice(DateTime valueDate, string underlyingCode, out EodPrice eodPrice)
{
return (eodPrice = GetBondPrice(valueDate, underlyingCode)) != null;
}
/// <summary>
/// 统一日终结算取价(债券感知)。
/// 用于交易/期权到期结算:债券标的走中债估值表(TryGetBondEodPrice),期货/股票走原 InnerGetEodPrice。
/// 解决到期路径(tradeExpireInner / MultipleTradeExpireConfirm)漏查债券表导致"结算价未找到"的问题。
/// 注:债券 ClosePrice/SettlePrice 映射沿用 GetBondPrice 口径(ClosePrice=全价 dirty_price_closeSettlePrice=净价 net_price),
/// 与 EodPriceProvider 的映射(ClosePrice=净价,SettlePrice=全价)相反——属历史不一致(见 EodPriceProvider.Initialize 与 GetBondPrice 的注释),
/// 本方法保持与系统既有"债券现价"约定(UnderlyingCodePrice)一致,不引入新口径。
/// </summary>
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);
}
/// <summary>
/// 尝试获取标的某日的日终价
/// </summary>
public static bool TryGetEodPrice(DateTime valueDate, int underlyingId, out EodPrice eodPrice)
{
return (eodPrice = GetEodPrice(valueDate, underlyingId)) != null;
}
/// <summary>
/// 获取某日之前最新价格
/// </summary>
/// <param name="valueDate"></param>
/// <param name="underlyingCode"></param>
/// <param name="price"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 尝试获取标的某日的日终价
/// </summary>
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;
}
/// <summary>
/// 获取标的某日的日终价,如果未找到返回null
/// </summary>
public static EodPrice GetEodPrice(DateTime valueDate, int underlyingId)
{
return underlyingId < 1 ? null : InnerGetEodPrice(valueDate, n => n.id == underlyingId);
}
/// <summary>
/// 获取标的某日的日终价,如果未找到返回null
/// </summary>
public static EodPrice GetEodPrice(DateTime valueDate, string underlyingCode)
{
return string.IsNullOrWhiteSpace(underlyingCode) ? null : InnerGetEodPrice(valueDate, n => n.UnderlyingCode == underlyingCode);
}
/// <summary>
/// 获取债券某日日终价格,如果未找到返回null
/// </summary>
/// <param name="valueDate"></param>
/// <param name="underlyingCode"></param>
/// <returns></returns>
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))
};
}
/// <summary>
/// 获取中债估值最新价格
/// </summary>
/// <param name="valueDate"></param>
/// <param name="underlyingCode"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取债券借贷费率最新行情
/// </summary>
/// <param name="valueDate"></param>
/// <param name="underlyingSecurityId"></param>
/// <returns></returns>
public static eod_bond_lending_rate GetBondLendingRate(DateTime valueDate, string underlyingSecurityId)
{
if (string.IsNullOrWhiteSpace(underlyingSecurityId))
{
return null;
}
using var db = DbContextFactory.GetYLDbContext();
return db.eod_bond_lending_rate
.Where(x => x.UnderlyingSecurityId == underlyingSecurityId && x.ValueDate <= valueDate.Date)
.OrderByDescending(x => x.ValueDate)
.FirstOrDefault();
}
/// <summary>
/// 尝试获取债券借贷费率最新行情
/// </summary>
/// <param name="valueDate"></param>
/// <param name="underlyingSecurityId"></param>
/// <param name="bondLendingRate"></param>
/// <returns></returns>
public static bool TryGetBondLendingRate(DateTime valueDate, string underlyingSecurityId, out eod_bond_lending_rate bondLendingRate)
{
return (bondLendingRate = GetBondLendingRate(valueDate, underlyingSecurityId)) != null;
}
/// <summary>
/// 获取标的收盘价格
/// </summary>
/// <param name="code">标的代码</param>
/// <param name="settleDate">收盘日</param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取标的某日的日终价,如果未找到返回null
/// </summary>
private static EodPrice InnerGetEodPrice(DateTime valueDate, Expression<Func<underlying_manager, bool>> 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;
}
/// <summary>
///
/// </summary>
/// <param name="unserialDates"></param>
/// <param name="underlyingId"></param>
/// <returns></returns>
public static List<EodPrice> GetEodPriceByUnserialDates(List<DateTime> 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();
}
}
/// <summary>
///
/// </summary>
/// <param name="unserialDates"></param>
/// <param name="underlyingId"></param>
/// <returns></returns>
public static List<EodPrice> 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<EodPrice>();
}
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; }
}
}
}