331 lines
11 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|