namespace YLErp.Modules.DataProviderModule { /// /// 日终货币汇率提供 /// public class EodCurrencyProvider { Dictionary _dic; /// /// 构造函数 /// /// 取值日期 /// 如果ValueDate未找到汇率是否找上日汇率数据 /// 是否反向查找 public EodCurrencyProvider(DateTime valueDate, bool seekPreDay, bool reverseFind = true) { ValueDate = valueDate.Date; IsSeekPreDay = seekPreDay; IsReverseFind = reverseFind; } /// /// 结算价取值日 /// public DateTime ValueDate { get; } /// /// 如果ValueDate未找到汇率是否找上日汇率数据 /// public bool IsSeekPreDay { get; } /// /// 是否反向查找(默认true) /// public bool IsReverseFind { get; } #region----初始化---- /// /// 初始化数据字典 /// 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(n => n.ValueDate >= minDate && n.ValueDate <= ValueDate) : PredicateBuilder.Create(n => n.ValueDate == ValueDate); var datas = db.eod_currency_rate.Where(predicate).ToArray(); if (_dic == null) { _dic = new Dictionary(); } 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 /// /// 获取汇率 /// /// 基础货币 /// 报价货币 /// /// 是否将CNY转换为CNH 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; } /// /// 获取汇率 /// /// 基础货币 /// 报价货币 /// public bool TryGetCurrencyRate(string baseCurrency, string quoteCurrency, out eod_currency_rate rate) { return TryGetCurrencyRate(baseCurrency, quoteCurrency, out rate, PS.Config.Company == Configuration.CompanyEnum.中金); } /// /// 使用人民币作为报价货币,获取缺失汇率的货币对(暂时适用于中金) /// /// public List GetCurrencyPairsOfMissingRate(IEnumerable currencyCodes) { if (currencyCodes is null) { throw new ArgumentNullException(nameof(currencyCodes)); } var missingList = new List(); 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() { 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() { 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() { 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() { ConsGlobal.Currency.CNH, ConsGlobal.Currency.CNY, ConsGlobal.Currency.USD })) { if (!TryGetCurrencyRate(code, ConsGlobal.Currency.USD, out _)) { missingList.Add(code + ConsGlobal.Currency.USD); } } } } return missingList; } } /// /// /// public class EodCurrencyProviderFactory { readonly bool _seekPreDay; readonly bool _reverseFind; readonly Dictionary _dic; public EodCurrencyProviderFactory(bool seekPreDay, bool reverseFind) { _seekPreDay = seekPreDay; _reverseFind = reverseFind; _dic = new Dictionary(); } 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; } } }