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

419 lines
16 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 YLErp.Abstract.DataProviders;
using YLErp.Helpers;
using YLErp.Models;
using YLErp.Modules.TradeModule.DealModule;
using YLErp.QdpModule;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 收盘结算价数据服务(不包括场内期权结算价)
/// </summary>
public class EodPriceProvider : IEodPriceProvider, IEodPriceProviderV2, IBasketPriceProvider
{
readonly Dictionary<string, EodPrice> _priceDic;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="valueDate">结算价取值日</param>
/// <param name="isDiviendPrice">是否需要前复权价</param>
public EodPriceProvider(DateTime valueDate, bool isDiviendPrice = false)
{
ValueDate = valueDate.Date;
IsDiviendPrice = isDiviendPrice;
_priceDic = new Dictionary<string, EodPrice>(StringComparer.OrdinalIgnoreCase);
}
public void SetPreValueDate(DateTime date)
{
PreValueDate = date;
}
/// <summary>
/// 结算价取值日
/// </summary>
public DateTime ValueDate { get; }
/// <summary>
/// 上一个结算日
/// </summary>
public DateTime? PreValueDate { get; set; }
/// <summary>
/// 是否价格除权
/// </summary>
public bool IsDiviendPrice { get; }
/// <summary>
/// 当前缓存中的价格数量
/// </summary>
public int Count => _priceDic.Count;
#region----初始化----
/// <summary>
/// 初始化数据字典
/// (提前初始化可在大批量标的取结算价时提高一定性能)
/// </summary>
public EodPriceProvider Initialize(IEnumerable<string> underlyingCodes = null)
{
using var db = DbContextFactory.GetYLDbContext();
var predicate1 = PredicateBuilder.Create<eod_commodity_future_price>(eodprice => eodprice.ValueDate == ValueDate);
var predicate2 = PredicateBuilder.Create<eod_stock_price>(eodprice => eodprice.ValueDate == ValueDate);
var predicate3 = PredicateBuilder.Create<ChinaBondValuation>(eodprice => eodprice.valuation_date == ValueDate);
if (underlyingCodes != null && underlyingCodes.Any(n => !string.IsNullOrEmpty(n)))
{
var set = underlyingCodes.Where(n => n != null && !_priceDic.ContainsKey(n)).ToHashSet();
if (set.Count < 1)
{
return this;
}
predicate1 = predicate1.And(n => set.Contains(n.UnderlyingCode));
predicate2 = predicate2.And(n => set.Contains(n.UnderlyingCode));
}
var eodFutureQuery = from eodprice in db.eod_commodity_future_price.Where(predicate1)
join um in db.underlying_manager on eodprice.UnderlyingCode equals um.UnderlyingCode
select new EodPrice
{
IsStock = false,
ValueDate = ValueDate,
UnderlyingId = um.id,
UnderlyingCode = um.UnderlyingCode,
ClosePrice = eodprice.ClosePrice,
SettlePrice = eodprice.SettlePrice,
HighPrice = eodprice.HighPrice,
LowPrice = eodprice.LowPrice,
UnderlyingStatus = "正常运行",
UnderlyingInstrumentType = "CommodityFutures",
ReferencePrice = eodprice.ReferencePrice,
DeciSettlePrice = 0,
DeciClosePrice = 0,
DeciReferencePrice = 0,
};
var eodStockQuery = from eodprice in db.eod_stock_price.Where(predicate2)
join um in db.underlying_manager on eodprice.UnderlyingCode equals um.UnderlyingCode
select new EodPrice
{
IsStock = true,
ValueDate = ValueDate,
UnderlyingId = um.id,
UnderlyingCode = um.UnderlyingCode,
ClosePrice = eodprice.ClosePrice,
SettlePrice = eodprice.ClosePrice,
HighPrice = eodprice.HighPrice,
LowPrice = eodprice.LowPrice,
UnderlyingStatus = eodprice.UnderlyingStatus,
UnderlyingInstrumentType = "Stock",
ReferencePrice = eodprice.ReferencePrice,
DeciSettlePrice = 0,
DeciClosePrice = 0,
DeciReferencePrice = 0,
};
var eodBondQuery = from eodprice in db.china_bond_valuation.Where(predicate3)
join um in db.underlying_manager on eodprice.bond_id equals um.UnderlyingCode
select new EodPrice
{
IsStock = false,
ValueDate = ValueDate,
UnderlyingId = um.id,
UnderlyingCode = um.UnderlyingCode,
ClosePrice = (double)(eodprice.dirty_price_close ?? 0) / 100,
SettlePrice = (double)(eodprice.net_price ?? 0) / 100,
HighPrice = 0,
LowPrice = 0,
UnderlyingStatus = "正常运行",
UnderlyingInstrumentType = "Bonds",
ReferencePrice = (double)(eodprice.yield ?? 0),
DeciSettlePrice = eodprice.dirty_price_close,
DeciClosePrice = eodprice.net_price,
DeciReferencePrice = eodprice.yield,
};
//数据加载到字典中
var list = eodFutureQuery.Concat(eodStockQuery).Concat(eodBondQuery).ToArray();
lock (_priceDic)
{
foreach (var item in list)
{
if (item.UnderlyingCode != null)
{
//if (item.UnderlyingInstrumentType == "Bonds")
//{
// // [Layer2-待统一] 债券映射口径:SettlePrice=全价(dirty_price_close)ClosePrice=净价(net_price)。
// // 注意:这与 EodPriceQueryService.GetBondPrice 的映射【完全相反】(GetBondPrice: ClosePrice=全价,SettlePrice=净价)。
// // 两处对"债券收盘价/结算价"的净全价定义不一致属历史遗留,请勿随意改动单侧,需业务先定调后统一(见 TryGetSettlementEodPrice 注释)。
// item.SettlePrice = Convert.ToDouble(BondPriceConverter.ToStorage(item.DeciSettlePrice));
// item.ClosePrice = Convert.ToDouble(BondPriceConverter.ToStorage(item.DeciClosePrice));
// item.ReferencePrice = Convert.ToDouble(BondPriceConverter.ToStorage(item.DeciReferencePrice));
//}
_priceDic[item.UnderlyingCode] = item;
}
}
if (underlyingCodes != null)
{
foreach (var code in underlyingCodes)
{
if (!string.IsNullOrWhiteSpace(code) && !_priceDic.ContainsKey(code))
{
_priceDic[code] = null;
}
}
}
}
if (IsDiviendPrice)
{
DividendPrice(ValueDate, _priceDic.Values);
}
return this;
}
#endregion
#region----IPriceProvider+IEodPriceProvider-----
public double GetPrice(string instrumentCode, SettlementTypeEnum settlementType)
{
return TryGetEodPrice(instrumentCode, out var ep) ? ep.GetPrice(settlementType) : 0;
}
public bool TryGetPrice(string instrumentCode, SettlementTypeEnum settlementType, out double price)
{
if (TryGetEodPrice(instrumentCode, out var ep))
{
price = ep.GetPrice(settlementType);
return true;
}
price = 0;
return false;
}
/// <summary>
/// 获取标的收盘价或结算价(如果标的在取值日之前已到期,则取标的到期日的收盘价或结算价)
/// </summary>
public bool TryGetEodPrice(string underlyingCode, out EodPrice eodPrice)
{
eodPrice = null;
if (string.IsNullOrWhiteSpace(underlyingCode))
{
return false;
}
lock (_priceDic)
{
if (_priceDic.TryGetValue(underlyingCode, out eodPrice))
{
return eodPrice != null;
}
}
if (EodPriceQueryService.TryGetEodPrice(ValueDate, underlyingCode, out eodPrice))
{
if (eodPrice.IsStock && IsDiviendPrice)
{
//根据标的ID或标的代码从数据源中查出来以后进行除权并缓存
DividendPrice(ValueDate, new[] { eodPrice });
}
}
else
{
eodPrice = null; //使用标的代码查找结算价未找到数据时也缓存起来
}
lock (_priceDic)
{
_priceDic[underlyingCode] = eodPrice;
}
return eodPrice != null;
}
private static void DividendPrice(DateTime valueDate, IEnumerable<EodPrice> eodPrices)
{
int[] unids = null;
var stockQuery = eodPrices.Where(n => n.IsStock);
var stockCount = stockQuery.Count();
if (stockCount < 1)
{
return;
}
if (stockCount < 10)
{
unids = stockQuery.Select(n => n.UnderlyingId).ToArray();
}
var dividendService = new DividendService(OptUserInfo.SystemUser);
var dividends = dividendService.GetExDividends(valueDate, unids).ToArray();
foreach (var ep in stockQuery)
{
var dividend = dividends.FirstOrDefault(n => n.UnderlyingId == ep.UnderlyingId);
if (dividend != null)
{
ep.ClosePrice = ep.SettlePrice = dividendService.GetPrice(ep.ClosePrice, dividend);
}
}
}
/// <summary>
///
/// </summary>
public IEodPriceProviderWrap GetPriceProvider(SettlementTypeEnum settlementType = SettlementTypeEnum.ClosePrice)
{
return new EodPriceProviderWrap(this, settlementType);
}
#endregion
/// <summary>
/// 获取当前已缓存的日终价格数据列表(返回数据中一定不存在重复的标的代码)
/// </summary>
public IEnumerable<EodPrice> GetEodPriceList()
{
lock (_priceDic)
{
return _priceDic.Values.ToArray();
}
}
#region----IBasketPriceProvider----
/// <summary>
/// 获取篮子的子标的价格
/// </summary>
public bool TryGetSubPrice(string underlyingCode, out double price, out double settlePrice)
{
if (TryGetEodPrice(underlyingCode, out var eodPrice))
{
price = eodPrice.ClosePrice;
settlePrice = eodPrice.SettlePrice;
return true;
}
price = settlePrice = 0;
return false;
}
#endregion
/// <summary>
/// 检查给定的标的是否在当前缓存中有值
/// </summary>
public bool HasValue(string underlyingCode)
{
if (string.IsNullOrEmpty(underlyingCode))
{
return false;
}
lock (_priceDic)
{
return _priceDic.TryGetValue(underlyingCode, out var value) && value != null;
}
}
/// <summary>
/// 手动设置日终价格
/// </summary>
public void SetPrice(EodPrice eodPrice)
{
if (!string.IsNullOrWhiteSpace(eodPrice?.UnderlyingCode))
{
lock (_priceDic)
{
_priceDic[eodPrice.UnderlyingCode] = eodPrice;
}
}
}
}
/// <summary>
/// IEodPriceProvider接口对象包装成IPriceProvider接口
/// </summary>
public class EodPriceProviderWrap : IPriceProvider, IEodPriceProviderWrap
{
public IEodPriceProvider EodPriceProvider { get; }
public SettlementTypeEnum SettlementType { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="eodPriceProvider"></param>
/// <param name="settlementType"></param>
public EodPriceProviderWrap(IEodPriceProvider eodPriceProvider, SettlementTypeEnum settlementType)
{
SettlementType = settlementType;
EodPriceProvider = eodPriceProvider ?? throw new ArgumentNullException(nameof(eodPriceProvider));
}
public double GetPrice(string instrumentCode)
{
return EodPriceProvider.GetPrice(instrumentCode, SettlementType);
}
public bool TryGetPrice(string instrumentCode, out double price)
{
return EodPriceProvider.TryGetPrice(instrumentCode, SettlementType, out price);
}
public override string ToString()
{
return SettlementType.ToString();
}
}
/// <summary>
/// 将IPriceProvider接口对象包装成IEodPriceProvider接口
/// </summary>
public class EodPriceProviderAs : IEodPriceProvider
{
public IPriceProvider PriceProvider { get; }
/// <summary>
///
/// </summary>
/// <param name="priceProvider"></param>
public EodPriceProviderAs(IPriceProvider priceProvider)
{
PriceProvider = priceProvider ?? throw new ArgumentNullException(nameof(priceProvider));
}
public double GetPrice(string instrumentCode, SettlementTypeEnum settlementType)
{
return PriceProvider.GetPrice(instrumentCode);
}
public bool TryGetPrice(string instrumentCode, SettlementTypeEnum settlementType, out double price)
{
return PriceProvider.TryGetPrice(instrumentCode, out price);
}
}
/// <summary>
///
/// </summary>
public static class EodPriceProviderFactory
{
/// <summary>
/// 使用缓存(10分钟更新一次)
/// </summary>
public static EodPriceProvider Get(DateTime valueDate)
{
var key = "EodPriceProviderFactory" + valueDate.ToString("yyyyMMdd");
var priceProvider = Providers.MemoryCacheProvider.Default.Get<EodPriceProvider>(key);
if (priceProvider != null)
{
return priceProvider;
}
priceProvider = new EodPriceProvider(valueDate);
Providers.MemoryCacheProvider.Default.Set(key, priceProvider, DateTimeOffset.Now.AddMinutes(10));
return priceProvider;
}
}
}