消除9处价格转换字面量(*0.01m/*100),统一走BondPriceConverter.ToStorage/ToDisplay。 - 新增YLErpDAL/Helpers/BondPriceConverter.cs(含可空重载) - 批次1(危险字面量): BondPaymentService/RealtimePnlCalc/RealTimeClientBanlanceService/SwapTradeAutoService - 批次2-4(调用收敛): SwapFlowService/SwapFlowImportService/SwapEndConfirmService/EodPriceProvider/EodPriceQueryService - RealtimePnlCalc:601/602价格×数量维度交织处加注释,不机械合并 不改bondPriceMultiple常量值,纯调用方式收敛。SwapModule 155测试全绿,行为不变。
493 lines
21 KiB
C#
493 lines
21 KiB
C#
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>
|
|
/// 尝试获取标的某日的日终价
|
|
/// </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)
|
|
{
|
|
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,
|
|
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="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; }
|
|
}
|
|
}
|
|
}
|