Files
zszq-trs/YLErpDAL/Modules/DataProviderModule/EodCurrencyProvider.cs
T
2024-05-09 14:06:26 +08:00

331 lines
11 KiB
C#

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;
}
}
}