从山证v2.3.0拷贝
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user