从山证v2.3.0拷贝

This commit is contained in:
吴方海
2024-05-09 14:06:26 +08:00
parent 566ff33259
commit f9d8a256a6
4471 changed files with 1203456 additions and 9 deletions
@@ -0,0 +1,10 @@
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
///
/// </summary>
public interface ITradeCashDataProvider
{
IEnumerable<trade_cash> GetTradeCashes(int tradeId);
}
}
@@ -0,0 +1,10 @@
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
///
/// </summary>
public interface ITradeCashPreDataProvider
{
IEnumerable<trade_cash_pre> GetTradeCashPres(int tradeId);
}
}
@@ -0,0 +1,38 @@
using YLErp.Abstract;
using YLErp.Abstract.DataProviders;
using YLErp.Modules.CalculationModule.Abstract;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// IOptionCalcDataProvider接口实现
/// </summary>
public class OptionCalcDataProvider : IOptionCalcDataProvider
{
public OptionCalcDataProvider()
{
}
public OptionCalcDataProvider(IOptionCalcDataProvider dataProvider)
{
if (dataProvider is null)
{
throw new System.ArgumentNullException(nameof(dataProvider));
}
UnderlyingPriceProvider = dataProvider.UnderlyingPriceProvider;
UnderlyingDataProvider = dataProvider.UnderlyingDataProvider;
TradeExtendDataProvider = dataProvider.TradeExtendDataProvider;
VolatilityDataProvider = dataProvider.VolatilityDataProvider;
}
public IPriceProvider UnderlyingPriceProvider { get; set; }
public IUnderlyingDataProvider UnderlyingDataProvider { get; set; }
public ITradeExtendDataProvider TradeExtendDataProvider { get; set; }
public IVolatilityDataProvider VolatilityDataProvider { get; set; }
}
}
@@ -0,0 +1,330 @@
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 日终货币汇率提供
/// </summary>
public class EodCurrencyProvider
{
Dictionary<string, eod_currency_rate> _dic;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="valueDate">取值日期</param>
/// <param name="seekPreDay">如果ValueDate未找到汇率是否找上日汇率数据</param>
/// <param name="reverseFind">是否反向查找</param>
public EodCurrencyProvider(DateTime valueDate, bool seekPreDay, bool reverseFind = true)
{
ValueDate = valueDate.Date;
IsSeekPreDay = seekPreDay;
IsReverseFind = reverseFind;
}
/// <summary>
/// 结算价取值日
/// </summary>
public DateTime ValueDate { get; }
/// <summary>
/// 如果ValueDate未找到汇率是否找上日汇率数据
/// </summary>
public bool IsSeekPreDay { get; }
/// <summary>
/// 是否反向查找(默认true)
/// </summary>
public bool IsReverseFind { get; }
#region--------
/// <summary>
/// 初始化数据字典
/// </summary>
private EodCurrencyProvider Initialize()
{
//多线程时只初始化一次
if (_dic == null)
{
lock (this)
{
if (_dic == null)
{
InnerInitialize();
}
}
}
return this;
}
private void InnerInitialize()
{
using (var db = DbContextFactory.GetYLDbContext())
{
var minDate = ValueDate.AddDays(-3);
var predicate = IsSeekPreDay
? PredicateBuilder.Create<eod_currency_rate>(n => n.ValueDate >= minDate && n.ValueDate <= ValueDate)
: PredicateBuilder.Create<eod_currency_rate>(n => n.ValueDate == ValueDate);
var datas = db.eod_currency_rate.Where(predicate).ToArray();
if (_dic == null)
{
_dic = new Dictionary<string, eod_currency_rate>();
}
var preDate = IsSeekPreDay
? datas.Where(n => n.ValueDate < ValueDate).Max(n => (DateTime?)n.ValueDate) ?? DateTime.MinValue
: DateTime.MinValue;
foreach (var item in datas)
{
string key = null;
if (item.ValueDate == ValueDate)
{
key = string.Concat(item.ForeignCurrency?.ToUpperInvariant(), "#", item.LocalCurrency?.ToUpperInvariant());
}
else if (item.ValueDate == preDate)
{
key = $"{item.ForeignCurrency?.ToUpperInvariant()}#{item.LocalCurrency?.ToUpperInvariant()}#pre";
}
if (key != null)
{
_dic[key] = item;
}
}
if (IsSeekPreDay && preDate < minDate)
{
preDate = db.eod_currency_rate.Where(n => n.ValueDate < minDate).Max(n => (DateTime?)n.ValueDate) ?? DateTime.MinValue;
if (preDate != DateTime.MinValue)
{
datas = db.eod_currency_rate.Where(n => n.ValueDate == preDate).ToArray();
foreach (var item in datas)
{
var key = $"{item.ForeignCurrency?.ToUpperInvariant()}#{item.LocalCurrency?.ToUpperInvariant()}#pre";
_dic[key] = item;
}
}
}
}
}
#endregion
/// <summary>
/// 获取汇率
/// </summary>
/// <param name="baseCurrency">基础货币</param>
/// <param name="quoteCurrency">报价货币</param>
/// <param name="rate"></param>
/// <param name="isCnyToCnh">是否将CNY转换为CNH</param>
public bool TryGetCurrencyRate(string baseCurrency, string quoteCurrency, out eod_currency_rate rate, bool isCnyToCnh)
{
Initialize();
baseCurrency = baseCurrency?.ToUpperInvariant();
quoteCurrency = quoteCurrency?.ToUpperInvariant();
if (string.IsNullOrEmpty(baseCurrency) || string.IsNullOrEmpty(quoteCurrency) || baseCurrency == quoteCurrency)
{
rate = new eod_currency_rate
{
ValueDate = ValueDate,
Rate = 1,
SellRate = 1,
BuyRate = 1,
ForeignCurrency = baseCurrency,
LocalCurrency = quoteCurrency,
};
return true;
}
//CNY to CNH
if (isCnyToCnh)
{
if (baseCurrency == ConsGlobal.Currency.CNY)
{
baseCurrency = ConsGlobal.Currency.CNH;
}
if (quoteCurrency == ConsGlobal.Currency.CNY)
{
quoteCurrency = ConsGlobal.Currency.CNH;
}
if (baseCurrency == quoteCurrency)
{
rate = new eod_currency_rate
{
ValueDate = ValueDate,
Rate = 1,
SellRate = 1,
BuyRate = 1,
ForeignCurrency = baseCurrency,
LocalCurrency = quoteCurrency,
};
return true;
}
}
//第一种货币对组合
var pair1 = string.Concat(baseCurrency, "#", quoteCurrency);
if (_dic.TryGetValue(pair1, out rate))
{
return true;
}
//第二种货币对组合
string pair2 = null;
if (IsReverseFind)
{
pair2 = string.Concat(quoteCurrency, "#", baseCurrency);
if (_dic.TryGetValue(pair2, out rate))
{
rate = rate.Reverse();
return true;
}
}
//查找上一日货币对汇率
if (IsSeekPreDay)
{
if (_dic.TryGetValue(pair1 + "#pre", out rate))
{
return true;
}
if (IsReverseFind && _dic.TryGetValue(pair2 + "#pre", out rate))
{
rate = rate.Reverse();
return true;
}
}
return false;
}
/// <summary>
/// 获取汇率
/// </summary>
/// <param name="baseCurrency">基础货币</param>
/// <param name="quoteCurrency">报价货币</param>
/// <param name="rate"></param>
public bool TryGetCurrencyRate(string baseCurrency, string quoteCurrency, out eod_currency_rate rate)
{
return TryGetCurrencyRate(baseCurrency, quoteCurrency, out rate, PS.Config.Company == Configuration.CompanyEnum.);
}
/// <summary>
/// 使用人民币作为报价货币,获取缺失汇率的货币对(暂时适用于中金)
/// </summary>
/// <param name="currencyCodes"></param>
public List<string> GetCurrencyPairsOfMissingRate(IEnumerable<string> currencyCodes)
{
if (currencyCodes is null)
{
throw new ArgumentNullException(nameof(currencyCodes));
}
var missingList = new List<string>();
if (PS.Config.Company == Configuration.CompanyEnum.)
{
//中金基础货币对为CNH和USD
foreach (var code in currencyCodes)
{
if (!ConsGlobal.Currency.IsCnCurrency(code) && !TryGetCurrencyRate(code, ConsGlobal.Currency.CNH, out _))
{
missingList.Add(code + ConsGlobal.Currency.CNH);
}
}
foreach (var code in currencyCodes.Except(new List<string>() { ConsGlobal.Currency.USD }))
{
if (!ConsGlobal.Currency.IsCnCurrency(code) && !TryGetCurrencyRate(code, ConsGlobal.Currency.USD, out _))
{
missingList.Add(code + ConsGlobal.Currency.USD);
}
}
}
else
{
//其他客户基础货币对为CNH和CNY和USD
if (currencyCodes.Contains(ConsGlobal.Currency.CNH))
{
foreach (var code in currencyCodes.Except(new List<string>() { ConsGlobal.Currency.CNH }))
{
if (!TryGetCurrencyRate(code, ConsGlobal.Currency.CNH, out _))
{
missingList.Add(code + ConsGlobal.Currency.CNH);
}
}
}
if (currencyCodes.Contains(ConsGlobal.Currency.CNY))
{
foreach (var code in currencyCodes.Except(new List<string>() { ConsGlobal.Currency.CNH, ConsGlobal.Currency.CNY }))
{
if (!TryGetCurrencyRate(code, ConsGlobal.Currency.CNY, out _))
{
missingList.Add(code + ConsGlobal.Currency.CNY);
}
}
}
if (currencyCodes.Contains(ConsGlobal.Currency.USD))
{
foreach (var code in currencyCodes.Except(new List<string>() { ConsGlobal.Currency.CNH, ConsGlobal.Currency.CNY, ConsGlobal.Currency.USD }))
{
if (!TryGetCurrencyRate(code, ConsGlobal.Currency.USD, out _))
{
missingList.Add(code + ConsGlobal.Currency.USD);
}
}
}
}
return missingList;
}
}
/// <summary>
///
/// </summary>
public class EodCurrencyProviderFactory
{
readonly bool _seekPreDay;
readonly bool _reverseFind;
readonly Dictionary<DateTime, EodCurrencyProvider> _dic;
public EodCurrencyProviderFactory(bool seekPreDay, bool reverseFind)
{
_seekPreDay = seekPreDay;
_reverseFind = reverseFind;
_dic = new Dictionary<DateTime, EodCurrencyProvider>();
}
public EodCurrencyProvider GetProvider(DateTime date)
{
date = date.Date;
if (!_dic.TryGetValue(date, out var provider))
{
_dic[date] = provider = new EodCurrencyProvider(date, _seekPreDay, _reverseFind);
}
return provider;
}
}
}
@@ -0,0 +1,237 @@
using YLErp.Abstract.DataProviders;
using YLErp.Models;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 日终场内期权价格提供
/// </summary>
public class EodExchangeOptionPriceProvider : IPriceProvider
{
private bool _allInitialized;
private readonly Dictionary<string, EodExchangeOptionPrice> _priceDic;
public EodExchangeOptionPriceProvider(DateTime valueDate, bool useClosePrice)
{
ValueDate = valueDate;
UseClosePrice = useClosePrice;
_priceDic = new Dictionary<string, EodExchangeOptionPrice>(StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// 取值日期
/// </summary>
public DateTime ValueDate { get; }
/// <summary>
/// 使用收盘价
/// </summary>
public bool UseClosePrice { get; }
public EodExchangeOptionPriceProvider InitializeAll()
{
var arr = GetDatasFromDB(null);
foreach (var item in arr)
{
_priceDic[item.OptionCode] = item;
}
_allInitialized = true;
return this;
}
/// <summary>
/// 根据场内期权代码初始化价格数据字典,
/// 调用后提升一定性能,不调用也无关系
/// </summary>
public EodExchangeOptionPriceProvider Initialize(string[] optionCodes)
{
if (_allInitialized)
{
return this;
}
var set = optionCodes.Where(n => !string.IsNullOrWhiteSpace(n)).ToHashSet(StringComparer.OrdinalIgnoreCase);
var list = GetDatasFromDB(set);
if (set.Any())
{
lock (_priceDic)
{
foreach (var code in set)
{
_priceDic[code] = null;
}
foreach (var item in list)
{
_priceDic[item.OptionCode] = item;
}
}
}
return this;
}
/// <summary>
/// 获取当前缓存中是否存在任一笔价格数据
/// </summary>
public bool HasAnyPrice()
{
return _priceDic.Values.Any(n => n != null);
}
/// <summary>
/// 获取价格
/// </summary>
public double GetPrice(string optionCode)
{
var data = InnerGetPrice(optionCode);
return data == null ? 0 : (UseClosePrice ? data.ClosePrice : data.SettlePrice);
}
/// <summary>
/// 尝试获取价格
/// </summary>
public bool TryGetPrice(string optionCode, out double price)
{
var data = InnerGetPrice(optionCode);
if (data != null)
{
price = UseClosePrice ? data.ClosePrice : data.SettlePrice;
return true;
}
else
{
price = 0;
return false;
}
}
/// <summary>
/// 获取价格对象
/// </summary>
public EodExchangeOptionPrice GetPriceModel(string optionCode)
{
return InnerGetPrice(optionCode);
}
/// <summary>
/// 尝试获取价格对象
/// </summary>
public bool TryGetPriceModel(string optionCode, out EodExchangeOptionPrice eodPrice)
{
return null != (eodPrice = InnerGetPrice(optionCode));
}
/// <summary>
/// 获取收盘价或结算价
/// </summary>
private EodExchangeOptionPrice InnerGetPrice(string optionCode)
{
if (string.IsNullOrWhiteSpace(optionCode))
{
return null;
}
lock (_priceDic)
{
if (_priceDic.TryGetValue(optionCode, out var data))
{
return data;
}
}
if (_allInitialized)
{
return null;
}
Initialize(new[] { optionCode });
lock (_priceDic)
{
if (_priceDic.TryGetValue(optionCode, out var data))
{
return data;
}
}
return null;
}
/// <summary>
/// 从数据库中获取初始化数据
/// </summary>
private EodExchangeOptionPrice[] GetDatasFromDB(HashSet<string> optionCodes)
{
var predicate = PredicateBuilder.Create<eod_exchange_option_price>(t => t.ValueDate == ValueDate);
if (optionCodes != null)
{
if (optionCodes.Count > 0)
{
predicate = predicate.And(t => optionCodes.Contains(t.ContractCode));
}
else
{
return Array.Empty<EodExchangeOptionPrice>();
}
}
using var db = DbContextFactory.GetYLDbContext();
return db.eod_exchange_option_price.Where(predicate)
.Select(n => new EodExchangeOptionPrice
{
OptionCode = n.ContractCode,
ClosePrice = n.ClosePrice,
HighPrice = n.HighPrice,
LowPrice = n.LowPrice,
SettlePrice = n.SettlePrice,
ValueDate = n.ValueDate
}).ToArray();
}
}
/// <summary>
/// 日终场内期权结算价
/// </summary>
public class EodExchangeOptionPrice
{
/// <summary>
/// 取值日
/// </summary>
public DateTime ValueDate { get; set; }
/// <summary>
/// 期权代码
/// </summary>
public string OptionCode { get; set; }
/// <summary>
/// 收盘价
/// </summary>
public double ClosePrice { get; set; }
/// <summary>
/// 结算价
/// </summary>
public double SettlePrice { get; set; }
/// <summary>
/// 最高价
/// </summary>
public double? HighPrice { get; set; }
/// <summary>
/// 最低价
/// </summary>
public double? LowPrice { get; set; }
}
}
@@ -0,0 +1,418 @@
using YLErp.Abstract.DataProviders;
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)
{
if (!PreValueDate.HasValue)
{
PreValueDate = QdpCalendarHelper.GetNonHoliday(ValueDate.AddDays(-1));
}
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 == PreValueDate);
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 = 0,
SettlePrice = 0,
HighPrice = 0,
LowPrice = 0,
UnderlyingStatus = "正常运行",
UnderlyingInstrumentType = "Bonds",
ReferencePrice =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")
{
item.SettlePrice = Convert.ToDouble(item.DeciSettlePrice*ConsGlobal.bondPriceMultiple);
item.ClosePrice = Convert.ToDouble(item.DeciClosePrice * ConsGlobal.bondPriceMultiple);
item.ReferencePrice = Convert.ToDouble(item.DeciReferencePrice * ConsGlobal.bondPriceMultiple);
}
_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;
}
}
}
@@ -0,0 +1,448 @@
using DocumentFormat.OpenXml.Drawing.Charts;
using System.Linq.Expressions;
using YLErp.Models;
using YLErp.QdpModule;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 收盘价查询服务
/// </summary>
public class EodPriceQueryService
{
/// <summary>
/// 检查数据库是否有数据
/// </summary>
public static bool CheckDbExists(DateTime valueDate,DateTime preSettleDate)
{
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== preSettleDate && n.dirty_price_close>0);
}
/// <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>
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(bondPrice.dirty_price_close*ConsGlobal.bondPriceMultiple),
SettlePrice = Convert.ToDouble(bondPrice.net_price * ConsGlobal.bondPriceMultiple),
ReferencePrice = Convert.ToDouble(bondPrice.yield * ConsGlobal.bondPriceMultiple)
};
}
/// <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 valuedate = QdpCalendarHelper.GetNonHolidayDefore(settleDate.AddDays(-1));
var eodBondPrice = GetBondPrice(valuedate, 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; }
}
}
}
@@ -0,0 +1,123 @@
using YLErp.Abstract.DataProviders;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 日终参考价数据提供(这个类只有特殊情况下用到)
/// </summary>
public class EodReferencePriceProvider : IPriceProvider
{
bool _initialized;
Dictionary<string, double?> _priceDic;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="valueDate">结算价取值日</param>
public EodReferencePriceProvider(DateTime valueDate)
{
ValueDate = valueDate.Date;
}
/// <summary>
/// 结算价取值日
/// </summary>
public DateTime ValueDate { get; }
/// <summary>
/// 初始化数据字典
/// (提前初始化可在大批量标的取结算价时提高一定性能)
/// </summary>
public EodReferencePriceProvider Initialize(string[] underlyingCodes = null)
{
//多线程时只初始化一次
if (!_initialized)
{
lock (this)
{
if (!_initialized)
{
InnerInitialize(underlyingCodes);
}
_initialized = true;
}
}
return this;
}
private void InnerInitialize(string[] underlyingCodes)
{
using (var db = DbContextFactory.GetYLDbContext())
{
var predicate1 = PredicateBuilder.Create<eod_commodity_future_price>(t => t.ValueDate == ValueDate);
var predicate2 = PredicateBuilder.Create<eod_stock_price>(t => t.ValueDate == ValueDate);
if (underlyingCodes != null && underlyingCodes.Any(n => !string.IsNullOrEmpty(n)))
{
predicate1 = predicate1.And(n => underlyingCodes.Contains(n.UnderlyingCode));
predicate2 = predicate2.And(n => underlyingCodes.Contains(n.UnderlyingCode));
}
var eodFutureQuery = db.eod_commodity_future_price.Where(predicate1).Select(n => new { n.UnderlyingCode, n.ReferencePrice });
var eodStockQuery = db.eod_stock_price.Where(predicate2).Select(n => new { n.UnderlyingCode, n.ReferencePrice });
//数据加载到字典中
var set = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
_priceDic = eodFutureQuery.Concat(eodStockQuery).ToArray()
.Where(n => n.UnderlyingCode != null && set.Add(n.UnderlyingCode))
.ToDictionary(n => n.UnderlyingCode, m => m.ReferencePrice, StringComparer.OrdinalIgnoreCase);
}
}
public double GetPrice(string instrumentCode)
{
return InnerTryGetPrice(instrumentCode, out var price) ? price : 0d;
}
public bool TryGetPrice(string instrumentCode, out double price)
{
return InnerTryGetPrice(instrumentCode, out price);
}
private bool InnerTryGetPrice(string instrumentCode, out double price)
{
price = 0;
if (string.IsNullOrWhiteSpace(instrumentCode))
{
return false;
}
lock (this)
{
if (_priceDic == null)
{
_priceDic = new Dictionary<string, double?>(StringComparer.OrdinalIgnoreCase);
}
else if (_priceDic.TryGetValue(instrumentCode, out var nPrice))
{
price = nPrice ?? 0;
return nPrice.HasValue;
}
else if (_initialized)
{
return false;
}
}
var exists = EodPriceQueryService.TryGetReferencePrice(ValueDate, instrumentCode, out price);
lock (this)
{
_priceDic[instrumentCode] = exists ? (double?)price : null;
}
return exists;
}
}
}
@@ -0,0 +1,49 @@
using YLErp.BLL;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 日终风险计算数据提供器
/// </summary>
public class EodRiskCalcDataProvider
{
private readonly EodPriceProvider _eodPriceProvider;
private readonly UnderlyingProvider _underlyingProvider;
public EodRiskCalcDataProvider(DateTime valueDate, DateTime? startDate = null)
{
_underlyingProvider = new UnderlyingProvider(OptUserInfo.SystemUser);
_underlyingProvider.Initialize(startDate);
_eodPriceProvider = new EodPriceProvider(valueDate);
}
/// <summary>
/// 根据代码获取标的信息
/// 涉及到历史标的所以不从缓存中获取
/// </summary>
public underlying_manager GetUnderlying(string underlyingCode)
{
if (underlyingCode is null)
{
throw new ArgumentNullException(nameof(underlyingCode));
}
return _underlyingProvider.GetUnderlying(underlyingCode);
}
/// <summary>
/// 获取标的收盘价或结算价(如果标的在取值日之前已到期,则取标的到期日的收盘价或结算价)
/// </summary>
public bool TryGetEodPrice(string underlyingCode, SettlementTypeEnum settlementType, out double price)
{
return _eodPriceProvider.TryGetPrice(underlyingCode, settlementType, out price);
}
/// <summary>
/// 返回数据查询接口(现在返回的是EF查询接口)
/// </summary>
public IQueryable<underlying_manager> GetUnderlyingQuery()
{
return underlying_managerBLL.GetQuery();
}
}
}
@@ -0,0 +1,56 @@
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 场内数据信息提供
/// </summary>
public static class ExchangeOptionDataProvider
{
/// <summary>
/// 尝试获取场内期权过期日
/// </summary>
public static bool TryGetMaturityDate(string optionCode, out DateTime date)
{
date = DateTime.MinValue;
if (string.IsNullOrEmpty(optionCode))
{
return false;
}
var data = DataCacheProvider.GetExchangeListOptionDataSource().GetData(optionCode);
if (data == null)
{
return false;
}
date = data.MaturityDate;
return true;
}
/// <summary>
/// 尝试获取行情价格
/// </summary>
public static bool TryGetPrice(string optionCode, out double price)
{
price = 0;
if (string.IsNullOrWhiteSpace(optionCode))
{
return false;
}
var data = DataCacheProvider.GetExchangeListOptionDataSource().GetData(optionCode);
if (data == null)
{
return false;
}
price = data.Price ?? 0;
return true;
}
}
}
@@ -0,0 +1,143 @@
using YieldChain.Commons;
using YLErp.Abstract.DataProviders;
using YLErp.Models;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 期权现价提供
/// </summary>
public class ExchangeOptionPriceProvider : IPriceProvider
{
readonly bool _initializeAll;
readonly IDictionary<string, PriceModel> _priceDic;
/// <summary>
///
/// </summary>
/// <param name="initializeAll">是否初始化全部数据</param>
public ExchangeOptionPriceProvider(bool initializeAll = true)
{
_initializeAll = initializeAll;
_priceDic = initializeAll
? InnerDataProvider.Default.GetPriceDic()
: new Dictionary<string, PriceModel>(StringComparer.OrdinalIgnoreCase);
}
/// <summary>
///
/// </summary>
public double GetPrice(string optionCode)
{
return (InnerGetPrice(optionCode)?.Price) ?? 0;
}
/// <summary>
///
/// </summary>
public bool TryGetPrice(string optionCode, out double price)
{
var data = InnerGetPrice(optionCode);
if (data != null)
{
price = data.Price;
return true;
}
price = 0;
return false;
}
/// <summary>
///
/// </summary>
public bool TryGetPriceModel(string optionCode, out PriceModel priceModel)
{
return null != (priceModel = InnerGetPrice(optionCode));
}
private PriceModel InnerGetPrice(string optionCode)
{
if (string.IsNullOrEmpty(optionCode))
{
return null;
}
if (_priceDic.TryGetValue(optionCode, out var data))
{
return data;
}
if (_initializeAll)
{
return null;
}
using var db = DbContextFactory.GetYLDbContext();
data = db.exchange_list_option.Where(n => n.ContractCode == optionCode)
.Select(n => new PriceModel
{
InstrumentCode = n.ContractCode,
Price = n.Price ?? 0,
PriceTime = n.PriceTime
}).FirstOrDefault();
_priceDic[optionCode] = data;
return data;
}
/// <summary>
/// 内部数据提供以保证行情可以及时更新
/// </summary>
class InnerDataProvider
{
readonly ThrottleAction _updateThrottle;
readonly Dictionary<string, PriceModel> _priceDic;
private InnerDataProvider()
{
_updateThrottle = new ThrottleAction(UpdatePrice, 10);
_priceDic = new Dictionary<string, PriceModel>();
}
private void UpdatePrice()
{
using var db = DbContextFactory.GetYLDbContext();
var date = DateTime.Today.AddDays(-10);
var arr = db.exchange_list_option.Where(n => n.MaturityDate > date && n.ContractCode != null)
.Select(n => new PriceModel
{
InstrumentCode = n.ContractCode,
Price = n.Price ?? 0,
PriceTime = n.PriceTime
}).ToArray();
foreach (var item in arr)
{
_priceDic[item.InstrumentCode] = item;
}
}
public IDictionary<string, PriceModel> GetPriceDic()
{
_updateThrottle.Execute();
return new Dictionary<string, PriceModel>(_priceDic);
}
/// <summary>
/// 单例
/// </summary>
public static readonly InnerDataProvider Default;
static InnerDataProvider()
{
Default = new InnerDataProvider();
}
}
}
}
@@ -0,0 +1,113 @@
using YLErp.Abstract.DataProviders;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 价格提供接口实现(数据来自手动添加)
/// </summary>
public class ManualPriceProvider : IPriceProvider
{
readonly Dictionary<string, double> _priceDic;
public ManualPriceProvider(IDictionary<string, double> priceDic = null)
{
_priceDic = priceDic == null
? new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase)
: new Dictionary<string, double>(priceDic, StringComparer.OrdinalIgnoreCase);
}
public ManualPriceProvider SetPrice(string instrumentId, double price)
{
if (!string.IsNullOrEmpty(instrumentId))
{
_priceDic[instrumentId] = price;
}
return this;
}
public double GetPrice(string instrumentId)
{
return !string.IsNullOrEmpty(instrumentId) && _priceDic.TryGetValue(instrumentId, out var price) ? price : 0;
}
public bool TryGetPrice(string instrumentId, out double price)
{
price = 0;
return !string.IsNullOrEmpty(instrumentId) && _priceDic.TryGetValue(instrumentId, out price);
}
public bool Contains(string instrumentId)
{
return _priceDic.ContainsKey(instrumentId);
}
public static implicit operator ManualPriceProvider(Dictionary<string, double> priceDic)
{
return new ManualPriceProvider(priceDic);
}
}
/// <summary>
/// 单个UnderlyingID对应的价格提供接口实现
/// </summary>
public class SinglePriceProvider : IPriceProvider
{
readonly double _price;
readonly string _instrumentId;
public SinglePriceProvider(string instrumentId, double price)
{
_instrumentId = instrumentId ?? throw new ArgumentNullException(nameof(instrumentId));
_price = price;
}
public double GetPrice(string instrumentId)
{
return _instrumentId.Equals(instrumentId, StringComparison.OrdinalIgnoreCase) ? _price : 0;
}
public bool TryGetPrice(string instrumentId, out double price)
{
if (_instrumentId.Equals(instrumentId, StringComparison.OrdinalIgnoreCase))
{
price = _price;
return true;
}
price = 0;
return false;
}
}
/// <summary>
/// 多个价格提供接口聚合提供价格
/// </summary>
public class AggregatePriceProvider : IPriceProvider, IAggregatePriceProvider
{
readonly IEnumerable<IPriceProvider> _priceProviders;
public AggregatePriceProvider(params IPriceProvider[] priceProviders)
{
_priceProviders = priceProviders ?? Enumerable.Empty<IPriceProvider>();
}
public double GetPrice(string instrumentCode)
{
return TryGetPrice(instrumentCode, out var price) ? price : 0;
}
public bool TryGetPrice(string instrumentCode, out double price)
{
foreach (var provider in _priceProviders)
{
if (provider != null && provider.TryGetPrice(instrumentCode, out price))
{
return true;
}
}
price = 0;
return false;
}
}
}
@@ -0,0 +1,85 @@
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 交易资金流水数据提供
/// </summary>
public class TradeCashDataProvider : ITradeCashDataProvider
{
readonly Dictionary<int, trade_cash[]> _dic;
public TradeCashDataProvider()
{
_dic = new Dictionary<int, trade_cash[]>();
}
public TradeCashDataProvider Initialize(IEnumerable<int> tradeIds)
{
if (tradeIds == null || !tradeIds.Any(n => n > 0))
{
return this;
}
var set = new HashSet<int>(110);
foreach (var id in tradeIds)
{
set.Add(id);
if (set.Count > 100)
{
QueryTradeCash(set);
}
}
if (set.Any())
{
QueryTradeCash(set);
}
return this;
}
private void QueryTradeCash(HashSet<int> idSet)
{
using (var db = DbContextFactory.GetYLDbContext())
{
var groups = db.trade_cash.AsNoTracking()
.Where(t => idSet.Contains(t.TradeId) && t.ValidState != ConsGlobal.InValid && !t.IsDeleted)
.OrderBy(t => t.TradeId).ThenBy(t => t.ValueDate).ToArray().GroupBy(n => n.TradeId);
foreach (var group in groups)
{
idSet.Remove(group.Key);
_dic[group.Key] = group.ToArray();
}
foreach (var id in idSet)
{
_dic[id] = Array.Empty<trade_cash>();
}
idSet.Clear();
}
}
/// <summary>
/// 获取交易资金数据(数据已按照ValueDate正序排序)
/// </summary>
public IEnumerable<trade_cash> GetTradeCashes(int tradeId)
{
if (tradeId < 1)
{
return Array.Empty<trade_cash>();
}
if (_dic.TryGetValue(tradeId, out var tcs))
{
return tcs;
}
QueryTradeCash(new HashSet<int> { tradeId });
return _dic[tradeId];
}
}
}
@@ -0,0 +1,85 @@
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 交易资金流水数据提供
/// </summary>
public class TradeCashPreDataProvider : ITradeCashPreDataProvider
{
readonly Dictionary<int, trade_cash_pre[]> _dic;
public TradeCashPreDataProvider()
{
_dic = new Dictionary<int, trade_cash_pre[]>();
}
public TradeCashPreDataProvider Initialize(IEnumerable<int> tradeIds)
{
if (tradeIds == null || !tradeIds.Any(n => n > 0))
{
return this;
}
var set = new HashSet<int>(110);
foreach (var id in tradeIds)
{
set.Add(id);
if (set.Count > 100)
{
QueryTradeCashPre(set);
}
}
if (set.Any())
{
QueryTradeCashPre(set);
}
return this;
}
private void QueryTradeCashPre(HashSet<int> idSet)
{
using (var db = DbContextFactory.GetYLDbContext())
{
var groups = db.trade_cash_pre.AsNoTracking()
.Where(t => idSet.Contains(t.TradeId) && t.ValidState != ConsGlobal.InValid && !t.IsDeleted)
.OrderBy(t => t.TradeId).ThenBy(t => t.ValueDate).ToArray().GroupBy(n => n.TradeId);
foreach (var group in groups)
{
idSet.Remove(group.Key);
_dic[group.Key] = group.ToArray();
}
foreach (var id in idSet)
{
_dic[id] = Array.Empty<trade_cash_pre>();
}
idSet.Clear();
}
}
/// <summary>
/// 获取交易资金数据(数据已按照ValueDate正序排序)
/// </summary>
public IEnumerable<trade_cash_pre> GetTradeCashPres(int tradeId)
{
if (tradeId < 1)
{
return Array.Empty<trade_cash_pre>();
}
if (_dic.TryGetValue(tradeId, out var tcs))
{
return tcs;
}
QueryTradeCashPre(new HashSet<int> { tradeId });
return _dic[tradeId];
}
}
}
@@ -0,0 +1,167 @@
using YLErp.Abstract;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 交易扩展数据数据提供
/// </summary>
public class TradeExtendDataProvider : YLBaseService, ITradeExtendDataProvider
{
public TradeExtendDataProvider(OptUserInfo userInfo) : base(userInfo)
{
}
public TradeExtendDataProvider(YLBaseService baseService) : base(baseService)
{
}
/// <summary>
///
/// </summary>
public trade_asian_option GetTrade_Asian_Option(int tradeId)
{
return DbContext.trade_asian_option.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
///
/// </summary>
public trade_barrier_option GetTrade_Barrier_Option(int tradeId)
{
return DbContext.trade_barrier_option.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
///
/// </summary>
public trade_double_sharkfin_option GetTrade_Double_SharkFin_Option(int tradeId)
{
return DbContext.trade_double_sharkfin_option.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
///
/// </summary>
public trade_binary_option GetTrade_Binary_Option(int tradeId)
{
return DbContext.trade_binary_option.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
///
/// </summary>
public trade_rainbow_option GetTrade_Rainbow_Option(int tradeId)
{
return DbContext.trade_rainbow_option.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
///
/// </summary>
public trade_spread_option GetTrade_Spread_Option(int tradeId)
{
return DbContext.trade_spread_option.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
///
/// </summary>
public trade_autocall GetTrade_Autocall_Option(int tradeId)
{
return DbContext.trade_autocall.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
/// 凤凰期权--累积票息
/// </summary>
public List<autocall_observation> GetTrade_HappenedObservations(int tradeId)
{
return DbContext.autocall_observation.AsNoTracking().Where(n => n.TradeId == tradeId).ToList();
}
/// <summary>
///
/// </summary>
public trade_snowball GetTrade_Snowball_Option(int tradeId)
{
return DbContext.trade_snowball.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
///
/// </summary>
public trade_rangeaccrual GetTrade_RangeAccrual(int tradeId)
{
return DbContext.trade_rangeaccrual.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
///
/// </summary>
public trade_cashflow GetTrade_CashFlow(int tradeId)
{
return DbContext.trade_cashflow.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
///
/// </summary>
public trade_airbag GetTrade_Airbag(int tradeId)
{
return DbContext.trade_airbag.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
/// 收益互换
/// </summary>
public trade_swap GetTrade_Swap(int tradeId)
{
return DbContext.trade_swap.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
/// 多空组合收益互换详情
/// </summary>
public List<trade_swap_detail> GetTrade_Swap_Details(int tradeId)
{
return DbContext.trade_swap_detail.AsNoTracking().Where(n => n.TradeId == tradeId && n.ValidState != "InValid").ToList();
}
/// <summary>
///
/// </summary>
public trade_underlying_enhance GetTrade_UnderlyingEnhance(int tradeId)
{
return DbContext.trade_underlying_enhance.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
/// 累计期权
/// </summary>
public trade_accumulator_option GetTrade_Accumulator_Option(int tradeId)
{
return DbContext.trade_accumulator_option.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
/// 远期
/// </summary>
/// <param name="tradeId"></param>
/// <returns></returns>
public trade_forward GetTrade_Forward(int tradeId)
{
return DbContext.trade_forward.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
/// <summary>
/// Risky期权
/// </summary>
/// <param name="tradeId"></param>
/// <returns></returns>
public trade_risky_option GetTrade_Risky_Option(int tradeId)
{
return DbContext.trade_risky_option.AsNoTracking().FirstOrDefault(n => n.TradeId == tradeId);
}
}
}
@@ -0,0 +1,182 @@
using System.Collections.Concurrent;
using YLErp.Abstract;
using YLErp.DBModels.Consts;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 交易历史数据提供
/// </summary>
public class TradeHisDataProvider : ITradeHisDataProvider
{
readonly DateTime _valueDate;
//key:tradeId
readonly ConcurrentDictionary<int, InnerTradeHisData> _dic;
public TradeHisDataProvider(DateTime valueDate)
{
_valueDate = valueDate;
_dic = new ConcurrentDictionary<int, InnerTradeHisData>();
}
/// <summary>
/// 加载最近三个月的数据做初始化
/// </summary>
public TradeHisDataProvider Initialize()
{
if (_dic.Count > 0)
{
return this;
}
lock (this)
{
if (_dic.Count > 0)
{
return this;
}
//只取3个月以内的
var startDate = _valueDate.AddMonths(-3);
using (var db = DbContextFactory.GetYLDbContext())
{
var query1 = from a in db.TradeHisData
where a.ValueDate > startDate && a.ValueDate <= _valueDate
group a by new { a.TradeId, a.ValueType } into g
select new
{
g.Key.TradeId,
g.Key.ValueType,
ValueDate = g.Max(n => n.ValueDate)
};
var query2 = from a in query1
join b in db.TradeHisData on a equals new { b.TradeId, b.ValueType, b.ValueDate }
select new
{
b.TradeId,
b.ValueType,
b.Value
};
var datas = query2.ToArray();
foreach (var data in datas)
{
if (!_dic.TryGetValue(data.TradeId, out var idata))
{
_dic[data.TradeId] = idata = new InnerTradeHisData();
}
if (ConsTradeField.NoRiskRate.Equals(data.ValueType, StringComparison.OrdinalIgnoreCase))
{
idata.NoRiskRate = data.Value;
idata.Flag |= ValueFlag.NoRiskRate;
}
else if (ConsTradeField.DividendRate.Equals(data.ValueType, StringComparison.OrdinalIgnoreCase))
{
idata.DividendRate = data.Value;
idata.Flag |= ValueFlag.DividendRate;
}
}
}
}
return this;
}
private double? GetValue(int tradeId, ValueFlag valueFlag)
{
if (_dic.TryGetValue(tradeId, out var data))
{
if ((data.Flag & valueFlag) == valueFlag)
{
switch (valueFlag)
{
case ValueFlag.NoRiskRate: return data.NoRiskRate;
case ValueFlag.DividendRate: return data.DividendRate;
default: throw new InvalidOperationException();
}
}
}
else
{
_dic[tradeId] = data = new InnerTradeHisData();
}
string valueType;
switch (valueFlag)
{
case ValueFlag.NoRiskRate:
valueType = ConsTradeField.NoRiskRate; break;
case ValueFlag.DividendRate:
valueType = ConsTradeField.DividendRate; break;
default: throw new InvalidOperationException();
}
using (var db = DbContextFactory.GetYLDbContext())
{
var query = from n in db.TradeHisData
where n.TradeId == tradeId && n.ValueDate <= _valueDate && n.ValueType == valueType
orderby n.ValueDate descending
select (double?)n.Value;
var value = query.FirstOrDefault();
switch (valueFlag)
{
case ValueFlag.NoRiskRate:
data.NoRiskRate = value; break;
case ValueFlag.DividendRate:
data.DividendRate = value; break;
default: throw new InvalidOperationException();
}
data.Flag |= valueFlag;
return value;
}
}
/// <summary>
/// 获取无风险利率
/// </summary>
public double? GetNoRiskRate(int tradeId)
{
return GetValue(tradeId, ValueFlag.NoRiskRate);
}
/// <summary>
/// 获取分红率
/// </summary>
public double? GetDividendRate(int tradeId)
{
return GetValue(tradeId, ValueFlag.DividendRate);
}
class InnerTradeHisData
{
/// <summary>
/// 无风险利率
/// </summary>
public double? NoRiskRate;
/// <summary>
/// 分红率
/// </summary>
public double? DividendRate;
public ValueFlag Flag;
}
enum ValueFlag
{
None = 0,
NoRiskRate = 1 << 0,
DividendRate = 1 << 1
}
}
}
@@ -0,0 +1,125 @@
using YLErp.BLL;
using YLErp.Modules.EodModule;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 获取历史交易累计盈亏统计盈亏统计信息
/// </summary>
public class TradePnlStaticsDataProvider
{
InnerProvider _provider;
bool _IncludeExchangeTrades;
readonly SortedList<DateTime, InnerProvider> _map;
private TradePnlStaticsDataProvider()
{
_map = new SortedList<DateTime, InnerProvider>();
}
public bool IncludeExchangeTrades
{
get
{
return _IncludeExchangeTrades;
}
set
{
if (_IncludeExchangeTrades != value)
{
_IncludeExchangeTrades = value;
Reset();
}
}
}
public void Reset()
{
_provider = null;
lock (_map)
{
_map.Clear();
}
}
/// <summary>
/// 获取历史交易累计盈亏统计信息
/// </summary>
public IEnumerable<TradePnlStatics> GetDatas(DateTime valueDate)
{
valueDate = valueDate.Date;
if (_provider?.ValueDate == valueDate)
{
return _provider.GetDatas(IncludeExchangeTrades);
}
lock (_map)
{
if (!_map.TryGetValue(valueDate, out _provider))
{
foreach (var item in _map.Values.ToArray())
{
if (item.LastRequestTime.AddHours(1) < DateTime.Now)
{
_map.Remove(item.ValueDate);
}
}
_map.Add(valueDate, _provider = new InnerProvider(valueDate));
}
return _provider.GetDatas(IncludeExchangeTrades);
}
}
/// <summary>
/// 单一实例
/// </summary>
public static readonly TradePnlStaticsDataProvider Default;
static TradePnlStaticsDataProvider()
{
Default = new TradePnlStaticsDataProvider();
}
class InnerProvider
{
IEnumerable<TradePnlStatics> _list;
public InnerProvider(DateTime valueDate)
{
ValueDate = valueDate.Date;
_list = Enumerable.Empty<TradePnlStatics>();
}
public DateTime ValueDate { get; }
/// <summary>
/// 最后一次请求时间
/// </summary>
public DateTime LastRequestTime { get; private set; }
/// <summary>
/// 获取数据
/// </summary>
public IEnumerable<TradePnlStatics> GetDatas(bool includeExchangeTrades)
{
LastRequestTime = DateTime.Now;
if (!_list.Any())
{
var startDate = valuedateBLL.SystemDate.AccruedTotalPnlStartDate ?? DateTime.MinValue;
_list = new AccruedTotalPnlService<eod_trade_position_hedgevol>(OptUserInfo.SystemUser)
.GetFinishedTradePnls(startDate, ValueDate, includeExchangeTrades);
}
//防止缓存数据被污染
return _list.Select(n => n.Clone()).ToArray();
}
}
}
}
@@ -0,0 +1,80 @@
using BaseOUDAL;
using YLErp.BLL;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 交易权限服务
/// </summary>
public class TradeRightProvider
{
/// <summary>
/// 获取用户授信权限
/// </summary>
public static List<int> GetClientVarietyIds(int clientId)
{
var allVarietyIds = DataCacheProvider.GetVarietyDataSource().AsQueryable().Select(v => v.id).ToList();
//如果不用没有要限制交易品种
if (!PS.Config.ClientElement.CanSelectCreditVariety)
{
return allVarietyIds;
}
var credits = DbContextFactory.GetYLDbContext().credit.Where(c => c.ClientId == clientId)
.Select(n => new { n.LimitVariety, n.IsFeelingWhiteList, n.VarietyId }).ToList();
if (credits.Any(c => !c.LimitVariety))
{
return allVarietyIds;
}
var varietyids = new List<int>();
foreach (var c in credits)
{
var VarietyIdsInt = DataConvert.ConvertCommaValuesToInt32Array(c.VarietyId);
if (c.IsFeelingWhiteList)
{
varietyids.AddRange(VarietyIdsInt);
}
else
{
varietyids.AddRange(allVarietyIds.Except(VarietyIdsInt));
}
}
return varietyids.Distinct().ToList();
}
/// <summary>
/// 获取客户授信
/// </summary>
public static List<CreditTable> GetClientCredits(int clientId)
{
var curDate = valuedateBLL.ValueDate;
var predicate = PredicateBuilder.Create<CreditTable>(c =>
c.ClientId == clientId && c.ProcessStatus == "已审批"
&& (!c.CreditStartDate.HasValue || c.CreditStartDate <= curDate)
&& (!c.CreditDeadLine.HasValue || c.CreditDeadLine >= curDate)
&& c.Type == CreditTable.ClientType);
return DbContextFactory.GetYLDbContext().credit.Where(predicate).ToList();
}
public static IEnumerable<int> GetUserVarietyIds(int userId)
{
return UserBLL.GetUserVarietyIds(userId);
}
/// <summary>
/// 获取交易权限配置
/// </summary>
public static IEnumerable<CreditTable> GetRoleCredits(IEnumerable<int> roleIds)
{
var predicate = PredicateBuilder.Create<CreditTable>(c => c.Type == CreditTable.RoleType && c.RoleId != null && roleIds.Contains(c.RoleId.Value));
return DbContextFactory.GetYLDbContext().credit.Where(predicate).ToArray();
}
}
}
@@ -0,0 +1,134 @@
using YLErp.Abstract.DataProviders;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 标的信息提供接口实现
/// </summary>
public class UnderlyingDataProvider : IUnderlyingDataProvider, IPriceProvider
{
/// <summary>
/// 获取标的数据
/// </summary>
public underlying_manager GetUnderlying(int underlyingId)
{
return DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingId);
}
/// <summary>
/// 获取标的数据
/// </summary>
public underlying_manager GetUnderlying(string underlyingCode)
{
return DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
}
/// <summary>
///
/// </summary>
public underlying_manager GetUnderlying(string underlyingCode, out double contractSize)
{
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
contractSize = um?.ContractSize ?? 1;
return um;
}
/// <summary>
/// 获取品种数据
/// </summary>
public Variety GetVariety(int varietyId)
{
return DataCacheProvider.GetVarietyDataSource().GetData(varietyId);
}
/// <summary>
/// 获取品种信息
/// </summary>
public Variety GetVariety(string underlyingCode, out double contractSize)
{
var um = GetUnderlying(underlyingCode);
contractSize = um?.ContractSize ?? 1;
return DataCacheProvider.GetVarietyDataSource().GetData(um?.UnderlyingTypeId ?? 0);
}
/// <summary>
/// 获取品种数据
/// </summary>
/// <param name="underlyingCode">标的代码</param>
public Variety GetVariety(string underlyingCode)
{
var um = GetUnderlying(underlyingCode);
return DataCacheProvider.GetVarietyDataSource().GetData(um?.UnderlyingTypeId ?? 0);
}
/// <summary>
/// 根据标的代码获取份额和数量的乘积因子
/// </summary>
public int GetCountRatio(string underlyingCode)
{
return DataCacheProvider.GetUnderlyingDataSource().GetCountRatio(underlyingCode);
}
/// <summary>
/// 尝试获取标的过期日(股票:2099-01-01)
/// </summary>
public bool TryGetMaturityDate(string underlyingCode, out DateTime date)
{
date = DateTime.MinValue;
if (string.IsNullOrEmpty(underlyingCode))
{
return false;
}
var data = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
if (data == null) return false;
date = data.UnderlyingInstrumentType == "Stock" ? DateTime.Now.AddYears(3) : data.MaturityDate ?? DateTime.MinValue;
return true;
}
/// <summary>
/// 根据标的代码获取当前价格
/// </summary>
public double GetPrice(string underlyingCode)
{
return DataCacheProvider.GetUnderlyingDataSource().TryGetPrice(underlyingCode, out var price) ? price : 0;
}
/// <summary>
/// 根据标的代码获取当前价格
/// </summary>
public bool TryGetPrice(string underlyingCode, out double price)
{
return DataCacheProvider.GetUnderlyingDataSource().TryGetPrice(underlyingCode, out price);
}
/// <summary>
/// 获取相关性
/// </summary>
public virtual CorrelationTable GetCorrelation(int underlyingId1, int underlyingId2)
{
return DataCacheProvider.GetCorrelationDataSource().AsQueryable().FirstOrDefault(
n => (n.UnderlyingId1 == underlyingId1 && n.UnderlyingId2 == underlyingId2) || (n.UnderlyingId1 == underlyingId2 && n.UnderlyingId2 == underlyingId1));
}
/// <summary>
/// 获取场外期权标的信息
/// </summary>
public virtual ExchangeListOption GetExchange_List_Option(string ContractCode)
{
return DataCacheProvider.GetExchangeListOptionDataSource().GetData(ContractCode);
}
/// <summary>
/// 获取组合标的
/// </summary>
public SyntheticUnderlying GetSyntheticUnderlying(string underlyingCode)
{
return DataCacheProvider.GetUnderlyingDataSource().GetSyntheticUnderlying(underlyingCode);
}
}
}
@@ -0,0 +1,69 @@
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 标的信息提供(这个类一般用于结算和涉及到历史数据时的业务)
/// </summary>
public class UnderlyingProvider : YLBaseService
{
private Dictionary<string, underlying_manager> _underlyingDic;
public UnderlyingProvider(OptUserInfo userInfo) : base(userInfo)
{
}
public UnderlyingProvider(YLBaseService baseService) : base(baseService)
{
}
/// <summary>
/// 初始化基础缓存,可以不调用,
/// 如果涉及到批量处理时调用后提升一定的数据访问性能
/// </summary>
public UnderlyingProvider Initialize(DateTime? minMaturityDate)
{
var date = (minMaturityDate ?? DateTime.Today).AddDays(-30);
_underlyingDic = DbContext.underlying_manager.AsNoTracking()
.Where(n => n.MaturityDate >= date && n.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommodityFutures)
.ToDictionary(n => n.UnderlyingCode, StringComparer.OrdinalIgnoreCase);
return this;
}
/// <summary>
/// 数据字典(初始化缓存后累加方式继续积累缓存)
/// </summary>
private Dictionary<string, underlying_manager> UnderlyingDic
{
get
{
return _underlyingDic ?? (_underlyingDic = new Dictionary<string, underlying_manager>(StringComparer.OrdinalIgnoreCase));
}
}
/// <summary>
/// 根据代码获取标的信息
/// </summary>
public underlying_manager GetUnderlying(string underlyingCode)
{
if (underlyingCode is null)
{
throw new ArgumentNullException(nameof(underlyingCode));
}
if (!UnderlyingDic.TryGetValue(underlyingCode, out var underlying))
{
UnderlyingDic[underlyingCode] = underlying = DbContext.underlying_manager.AsNoTracking().FirstOrDefault(n => n.UnderlyingCode == underlyingCode);
}
return underlying;
}
/// <summary>
/// 返回数据查询接口(现在返回的是EF查询接口)
/// </summary>
public IQueryable<underlying_manager> GetUnderlyingQuery()
{
return DbContext.underlying_manager.AsNoTracking();
}
}
}
@@ -0,0 +1,64 @@
using System.Collections.Concurrent;
using YLErp.Abstract;
using YLErp.Modules.ExchangeOptionTradeModule;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 场内期权保存波动率提供
/// </summary>
public class ExOptionSavedVolProvider : IDataUpdater, IJsonSerializable
{
readonly DateTime _valueDate;
//使用场内期权代码做为主键
readonly ConcurrentDictionary<string, double?> _dic;
//业务操作上来说,旧的波动率不会再变更
readonly ConcurrentDictionary<string, double?> _dicOld;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="valueDate">当前结算日期</param>
public ExOptionSavedVolProvider(DateTime valueDate)
{
_valueDate = valueDate;
_dic = new ConcurrentDictionary<string, double?>();
_dicOld = new ConcurrentDictionary<string, double?>();
}
public string TableName => nameof(ExchangeOptionVol);
/// <summary>
/// 获取交易波动率
/// </summary>
public double? GetSavedVol(string optionCode, DateTime valueDate)
{
var dic = valueDate < _valueDate ? _dicOld : _dic;
if (!dic.TryGetValue(optionCode, out var vol))
{
vol = new ExchangeOptionVolQueryService(OptUserInfo.SystemUser).GetSavedVol(optionCode, valueDate);
dic.AddOrUpdate(optionCode, vol, (n, m) => vol);
}
return vol;
}
/// <summary>
/// 更新数据--keyid为optionCode
/// </summary>
public void UpdateData(IEnumerable<string> updateKeyIds)
{
foreach (var optionCode in updateKeyIds)
{
if (optionCode != null)
{
_dic.TryRemove(optionCode, out _);
}
}
}
public string ToJson()
{
return new { _valueDate, _dic, _dicOld }.ToJson();
}
}
}
@@ -0,0 +1,66 @@
using System.Collections.Concurrent;
using YLErp.Abstract;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 场外期权结算波动率提供
/// </summary>
public class OtcEodOverrideVolProvider : IDataUpdater, IJsonSerializable
{
readonly DateTime _valueDate;
//数据ID做为KEY
readonly ConcurrentDictionary<int, double?> _dic;
/// <summary>
/// 构造函数
/// </summary>
public OtcEodOverrideVolProvider(DateTime valueDate)
{
_valueDate = valueDate;
_dic = new ConcurrentDictionary<int, double?>();
}
public string TableName => nameof(eod_trade_vol_override);
/// <summary>
/// 获取交易波动率
/// </summary>
public double? GetVol(int tradeId, DateTime valueDate)
{
System.Diagnostics.Debug.Assert(_valueDate == valueDate);
if (!_dic.TryGetValue(tradeId, out double? vol))
{
vol = DbContextFactory.GetYLDbContext().eod_trade_vol_override
.Where(n => n.valuedate == valueDate && n.tradeid == tradeId)
.Select(n => (double?)n.vol).FirstOrDefault();
_dic.AddOrUpdate(tradeId, vol, (n, m) => vol);
}
if (vol == null)
{
return null;
}
return Convert.ToDouble(vol.Value);
}
/// <summary>
/// 更新数据
/// </summary>
public void UpdateData(IEnumerable<string> updateKeyIds)
{
var tradeIds = DataConvert.ConvertToInt32Array(updateKeyIds);
foreach (var tradeId in tradeIds)
{
_dic.TryRemove(tradeId, out _);
}
}
public string ToJson()
{
return new { _valueDate, _dic }.ToJson();
}
}
}
@@ -0,0 +1,64 @@
using System.Collections.Concurrent;
using YLErp.Abstract;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 场外期权对冲波动率提供
/// </summary>
public class OtcHedgingVolProvider : IDataUpdater, IJsonSerializable
{
readonly DateTime _valueDate;
//使用tradeid做为主键
readonly ConcurrentDictionary<int, double?> _dic;
//业务操作上来说,旧的波动率不会再变更
readonly ConcurrentDictionary<int, double?> _dicOld;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="valueDate">当前结算日期</param>
public OtcHedgingVolProvider(DateTime valueDate)
{
_valueDate = valueDate;
_dic = new ConcurrentDictionary<int, double?>();
_dicOld = new ConcurrentDictionary<int, double?>();
}
public string TableName => nameof(trade_hedge_vol);
/// <summary>
/// 获取交易波动率
/// </summary>
public double? GetVol(int tradeId, DateTime valueDate)
{
var dic = valueDate < _valueDate ? _dicOld : _dic;
if (!dic.TryGetValue(tradeId, out double? vol))
{
vol = DbContextFactory.GetYLDbContext().trade_hedge_vol
.Where(n => n.TradeId == tradeId && n.ValueDate <= valueDate)
.OrderByDescending(n => n.ValueDate)
.Select(n => (double?)n.TradeSavedVol).FirstOrDefault();
dic.AddOrUpdate(tradeId, vol, (n, m) => vol);
}
return vol;
}
/// <summary>
/// 更新数据
/// </summary>
public void UpdateData(IEnumerable<string> updateKeyIds)
{
var tradeIds = DataConvert.ConvertToInt32Array(updateKeyIds);
foreach (var tradeId in tradeIds)
{
_dic.TryRemove(tradeId, out _);
}
}
public string ToJson()
{
return new { _valueDate, _dic, _dicOld }.ToJson();
}
}
}
@@ -0,0 +1,84 @@
using System.Collections.Concurrent;
using YLErp.Abstract;
using YLErp.Models;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 场外期权开仓平仓波动率提供
/// </summary>
public class OtcPositionVolProvider : IDataUpdater, IJsonSerializable
{
readonly DateTime _valueDate;
//使用tradeid做为主键,为当日取波动率提供服务
readonly ConcurrentDictionary<int, IOtcTradeVolatility> _dic;
//业务操作上来说,旧的波动率不会再变更,为上一交易日取波动率提供服务
readonly ConcurrentDictionary<int, IOtcTradeVolatility> _dicOld;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="valueDate">当前结算日期</param>
public OtcPositionVolProvider(DateTime valueDate)
{
_valueDate = valueDate;
_dic = new ConcurrentDictionary<int, IOtcTradeVolatility>();
_dicOld = new ConcurrentDictionary<int, IOtcTradeVolatility>();
}
public string TableName => nameof(TradeVolatility);
/// <summary>
/// 获取交易波动率
/// </summary>
public IOtcTradeVolatility GetVol(int tradeId, DateTime valueDate)
{
var dic = valueDate < _valueDate ? _dicOld : _dic;
if (!dic.TryGetValue(tradeId, out var vol))
{
var tradVol = DbContextFactory.GetYLDbContext().TradeVolatility
.Where(n => n.TradeId == tradeId && n.ValueDate <= valueDate)
.OrderByDescending(n => n.ValueDate)
.Select(n => new
{
n.NumOfSmoothingDays,
n.TradePositionVolatility,
n.TradeCloseVolatility,
n.IsFromTradeAdd,
n.ValueDate
}).FirstOrDefault();
if (tradVol != null)
{
vol = new OtcTradeVolatility
{
ValueDate = tradVol.ValueDate,
OpenVol = tradVol.TradePositionVolatility ?? 0,
CloseVol = tradVol.TradeCloseVolatility ?? 0,
SmoothingDays = tradVol.NumOfSmoothingDays ?? 0,
IsFirst = tradVol.IsFromTradeAdd == true
};
}
dic.AddOrUpdate(tradeId, vol, (n, m) => vol);
}
return vol;
}
public string ToJson()
{
return new { _valueDate, _dic, _dicOld }.ToJson();
}
/// <summary>
/// 更新数据
/// </summary>
public void UpdateData(IEnumerable<string> updateKeyIds)
{
var tradeIds = DataConvert.ConvertToInt32Array(updateKeyIds);
foreach (var tradeId in tradeIds)
{
_dic.TryRemove(tradeId, out IOtcTradeVolatility vol);
}
}
}
}
@@ -0,0 +1,158 @@
using YLErp.Abstract;
using YLErp.DBModels.Consts;
using YLErp.Models;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 标的波动率数据提供
/// </summary>
class UnderlyingVolProvider : IDataUpdater, IJsonSerializable
{
const string KeySeparator = "[|]";
/// <summary>
///
/// </summary>
public DateTime ValueDate { get; }
//波动率类型+合约代码做为KEY
readonly Dictionary<string, InnerVolatility> _dic;
static readonly InnerVolatility _removed;
public UnderlyingVolProvider(DateTime valueDate)
{
ValueDate = valueDate;
_dic = new Dictionary<string, InnerVolatility>(StringComparer.OrdinalIgnoreCase);
}
static UnderlyingVolProvider()
{
_removed = new InnerVolatility();
}
public string TableName => nameof(volatility);
/// <summary>
/// 根据请求参数获取波动率
/// </summary>
public IVolatility GetVolatility(string voltype, string contractCode, string userGroup)
{
if (!ConsUserGroup.HasGroup)
{
userGroup = string.Empty;
}
else if (string.IsNullOrEmpty(userGroup))
{
return null;
}
if (string.IsNullOrWhiteSpace(voltype) || string.IsNullOrWhiteSpace(contractCode))
{
return null;
}
var keyStr = string.Join(KeySeparator, new[] { contractCode, voltype, userGroup });
lock (_dic)
{
if (_dic.TryGetValue(keyStr, out var dicItem) && dicItem != _removed)
{
return dicItem;
}
}
volatility volData = null;
using (var db = DbContextFactory.GetYLDbContext())
{
volData = db.volatility.AsNoTracking()
.Where(n => n.UserGroup == userGroup && n.ContractCode == contractCode && n.VolType == voltype && n.QuotationDate <= ValueDate)
.OrderByDescending(n => n.QuotationDate).FirstOrDefault();
if (volData == null)
{
lock (_dic)
{
_dic[keyStr] = null;
}
return null;
}
}
var innerVol = new InnerVolatility
{
VolSurfaceMode = volData.VolSurfaceMode,
InterpolationMethod = volData.InterpolationMethod,
VolTable = volData.VolTable ?? new List<SingleVol>(0)
};
lock (_dic)
{
_dic[keyStr] = innerVol;
}
return innerVol;
}
public string ToJson()
{
lock (_dic)
{
return new { ValueDate, _dic }.ToJson();
}
}
/// <summary>
/// 更新数据--使用直接删除的方式
/// </summary>
public void UpdateData(IEnumerable<string> updateKeyIds)
{
lock (_dic)
{
var removeArr = _dic.Where(n => n.Value == _removed);
foreach (var kv in removeArr)
{
_dic.Remove(kv.Key);
}
var set = new HashSet<string>(10, StringComparer.OrdinalIgnoreCase);
foreach (var keyId in updateKeyIds)
{
if (!string.IsNullOrWhiteSpace(keyId))
{
var strArr = keyId.Split(','); //id,ContractCode,VolType
if (strArr.Length > 2)
{
set.Add(string.Concat(strArr[1], KeySeparator, strArr[2]));
}
}
}
foreach (var k in _dic.Keys)
{
var index = k.LastIndexOf(KeySeparator);
if (index > 0 && set.Contains(k.Substring(0, index)))
{
_dic[k] = _removed;
}
}
}
}
class InnerVolatility : IVolatility
{
public string VolSurfaceMode { get; set; }
public string InterpolationMethod { get; set; }
public List<SingleVol> VolTable { get; set; }
}
}
}
@@ -0,0 +1,68 @@
using YLErp.Abstract;
using YLErp.Modules.CalculationModule.Abstract;
namespace YLErp.Modules.DataProviderModule
{
/// <summary>
/// 波动率数据提供
/// </summary>
public class VolatilityDataProvider : IVolatilityDataProvider
{
readonly UnderlyingVolProvider _UnderlyingVolProvider;
readonly OtcPositionVolProvider _OtcPositionVolProvider;
readonly OtcHedgingVolProvider _OtcHedgingVolProvider;
readonly OtcEodOverrideVolProvider _OtcEodOverrideVolProvider;
readonly ExOptionSavedVolProvider _ExOptionSavedVolProvider;
public VolatilityDataProvider(DateTime valueDate)
{
_UnderlyingVolProvider = new UnderlyingVolProvider(valueDate);
_OtcPositionVolProvider = new OtcPositionVolProvider(valueDate);
_OtcHedgingVolProvider = new OtcHedgingVolProvider(valueDate);
_OtcEodOverrideVolProvider = new OtcEodOverrideVolProvider(valueDate);
_ExOptionSavedVolProvider = new ExOptionSavedVolProvider(valueDate);
}
/// <summary>
/// 场内期权保存的波动率
/// </summary>
public double? GetExOptionSavedVol(string optionCode, DateTime valueDate)
{
return _ExOptionSavedVolProvider.GetSavedVol(optionCode, valueDate);
}
/// <summary>
/// 场外期权对冲波动率
/// </summary>
public double? GetOtcHedgingVol(int tradeId, DateTime valueDate)
{
return _OtcHedgingVolProvider.GetVol(tradeId, valueDate);
}
/// <summary>
/// 标的波动率
/// </summary>
public IVolatility GetUnderlyingVol(DateTime valueDate, string voltype, string contractCode, string userGroup)
{
return _UnderlyingVolProvider.GetVolatility(voltype, contractCode, userGroup);
}
/// <summary>
/// 场外期权结算波动率
/// </summary>
public double? GetOtcEodOverrideVol(int tradeId, DateTime valueDate)
{
return _OtcEodOverrideVolProvider.GetVol(tradeId, valueDate);
}
/// <summary>
/// 场外期权持仓波动率
/// </summary>
public IOtcTradeVolatility GetOtcPositionVol(int tradeId, DateTime valueDate)
{
return _OtcPositionVolProvider.GetVol(tradeId, valueDate);
}
}
}