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

645 lines
25 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BaseOUDAL;
using System.Data;
using System.Data.SqlTypes;
using YLErp.Commons;
using YLErp.Enums;
using YLErp.Model;
using YLErp.Modules.DataProviderModule;
namespace YLErp.Modules.EodModule
{
/// <summary>
/// 日终汇率数据服务
/// </summary>
public class EodCurrencyRateService : YLBaseService
{
public EodCurrencyRateService(OptUserInfo userInfo) : base(userInfo)
{
}
public SearchListResult<eod_currency_rate> SearchEodCurrencyRateList(EodCurrencyRateReq req)
{
if (string.IsNullOrEmpty(req.sidx))
{
req.sidx = "ValueDate";
req.sord = "desc";
}
var query = from ecr in DbContext.eod_currency_rate
select ecr;
if (req.ValueDateStart != DateTime.MinValue && req.ValueDateStart != SqlDateTime.MinValue)
{
query = query.Where(O => O.ValueDate >= req.ValueDateStart);
}
if (req.ValueDateEnd != DateTime.MinValue && req.ValueDateEnd != SqlDateTime.MinValue)
{
query = query.Where(O => O.ValueDate <= req.ValueDateEnd);
}
var result = query.ToSearchList(req);
return result;
}
/// <summary>
/// 导入xlsx数据
/// </summary>
public ImportResultModel ImportxlsxDatas(Stream stream)
{
var importModels = Enumerable.Empty<eod_currency_rate>();
var rowIndex = 0;
try
{
var ds = Office.ExcelHelper.ReadExcelAsDataSet(stream);
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 1)
{
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
}
var table = ds.Tables[0];
var reader = new DataRowReader(table);
var list = new List<eod_currency_rate>();
rowIndex = 1;
var currencies = DbContextFactory.GetYLDbContext().currency.Select(x => x.CurrencyCode).ToList();
foreach (DataRow row in table.Rows)
{
rowIndex++;
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
{
continue;
}
reader.SetDataRow(row);
var date = reader.GetDate("日期", true);
var currencyPair = reader.GetString("货币对", true);
var leftcurrency = currencyPair.Substring(0, 3);
var rightcurrency = currencyPair.Substring(3);
var currencys = currencyPair.Split('/');
if (currencys.Length != 2 && currencyPair.Length != 6)
{
throw new ServiceException("货币对 不符合格式要求,必须为6位字符(CNYUSD)或者使用/分隔(CNY/USD:" + currencyPair);
}
else if (currencys.Length == 2)
{
leftcurrency = currencys[0];
rightcurrency = currencys[1];
}
if (!currencies.Contains(leftcurrency))
{
throw new ServiceException("货币不存在,请设置系统货币:" + leftcurrency);
}
if (!currencies.Contains(rightcurrency))
{
throw new ServiceException("货币不存在,请设置系统货币:" + rightcurrency);
}
var rate = reader.GetDouble("汇率", true) ?? 0;
var buyRate = reader.GetDouble("购汇", false);
var sellRate = reader.GetDouble("结汇", false);
if (rate < 1e-8)
{
throw new ServiceException("汇率 必须大于0:" + currencyPair);
}
if (buyRate.HasValue)
{
if (buyRate < 0)
{
throw new ServiceException("购汇 必须大于0:" + currencyPair);
}
if (buyRate == 0)
{
buyRate = rate;
}
}
if (sellRate.HasValue)
{
if (sellRate < 0)
{
throw new ServiceException("结汇 必须大于0:" + currencyPair);
}
if (sellRate == 0)
{
sellRate = rate;
}
}
var eodRate = new eod_currency_rate
{
ValueDate = date.Value,
ForeignCurrency = leftcurrency,
LocalCurrency = rightcurrency,
Rate = rate,
BuyRate = buyRate,
SellRate = sellRate,
};
var index = list.FindIndex(x => x.ValueDate == date && (leftcurrency + rightcurrency).Equals(x.ForeignCurrency + x.LocalCurrency, StringComparison.OrdinalIgnoreCase));
if (index < 0)
{
list.Add(eodRate);
}
else
{
list[index] = eodRate;
}
}
importModels = list.ToArray();
}
catch (ServiceException se)
{
if (se.Tag != null) throw;
throw new ServiceException($"第{rowIndex}行,发生错误:{se.Message}");
}
catch (Exception ex)
{
LogFactory.GetLogger("导入场内交易").Error(ex);
throw new ServiceException($"第{rowIndex}行,发生错误:{ex.Message}", ex);
}
if (!importModels.Any())
{
throw new ServiceException("没有可导入的数据");
}
var result = new ImportResultModel
{
TotalCount = importModels.Count()
};
var factory = new EodCurrencyProviderFactory(false, false);
foreach (var item in importModels)
{
if (factory.GetProvider(item.ValueDate).TryGetCurrencyRate(item.ForeignCurrency, item.LocalCurrency, out var record, false))
{
DbContext.eod_currency_rate.Attach(record);
record.Rate = item.Rate;
record.BuyRate = item.BuyRate ?? item.Rate;
record.SellRate = item.SellRate ?? item.Rate;
}
else
{
if (!item.BuyRate.HasValue)
{
item.BuyRate = item.Rate;
}
if (!item.SellRate.HasValue)
{
item.SellRate = item.Rate;
}
DbContext.eod_currency_rate.Add(record = item);
}
record.OptId = UserId;
record.OptName = UserName;
record.OptDate = DateTime.Now;
result.SuccessCount++;
}
DbContext.SaveChanges();
return result;
}
/// <summary>
/// 获取货币对汇率
/// </summary>
/// <param name="quoteCurrency">计价货币</param>
/// <param name="settlementCurrency">结算货币</param>
/// <param name="valueDate">取值日期</param>
/// <param name="seekPreday">如果取值日期未找到汇率是否向前日继续查找</param>
/// <returns></returns>
public double GetCurrencyRate(string quoteCurrency, string settlementCurrency,
DateTime valueDate, bool seekPreday = false, CurrencyRateType currencyRateType = CurrencyRateType.Mid)
{
var r1 = GetEodCurrencyRate(quoteCurrency, settlementCurrency, valueDate, seekPreday);
if (r1 == null)
{
if (PS.Config.Company == Configuration.CompanyEnum.中金)
{
if (quoteCurrency == ConsGlobal.Currency.CNY)
{
quoteCurrency = ConsGlobal.Currency.CNH;
}
if (settlementCurrency == ConsGlobal.Currency.CNY)
{
settlementCurrency = ConsGlobal.Currency.CNH;
}
}
throw new ServiceException($"请先维护货币对'{quoteCurrency}{settlementCurrency}'在日期'{valueDate:yyyy-MM-dd}'的汇率");
}
else
{
return r1.GetRate(currencyRateType);
}
}
/// <summary>
/// 获取货币对汇率
/// </summary>
/// <param name="quoteCurrency">计价货币</param>
/// <param name="settlementCurrency">结算货币</param>
/// <param name="valueDate">取值日期</param>
/// <param name="seekPreday">如果取值日期未找到汇率是否向前日继续查找</param>
public eod_currency_rate GetEodCurrencyRate(string quoteCurrency, string settlementCurrency, DateTime valueDate, bool seekPreday = false)
{
if (string.IsNullOrEmpty(quoteCurrency) || string.IsNullOrEmpty(settlementCurrency)
|| quoteCurrency.Equals(settlementCurrency, StringComparison.OrdinalIgnoreCase)
|| ConsGlobal.Currency.IsCnCurrency(quoteCurrency) && ConsGlobal.Currency.IsCnCurrency(settlementCurrency))
{
return new eod_currency_rate
{
ValueDate = valueDate,
Rate = 1,
SellRate = 1,
BuyRate = 1,
ForeignCurrency = quoteCurrency,
LocalCurrency = settlementCurrency,
};
}
quoteCurrency = quoteCurrency.ToUpperInvariant();
settlementCurrency = settlementCurrency.ToUpperInvariant();
//中金特殊处理
if (PS.Config.Company == Configuration.CompanyEnum.中金)
{
if (quoteCurrency == ConsGlobal.Currency.CNY)
{
quoteCurrency = ConsGlobal.Currency.CNH;
}
if (settlementCurrency == ConsGlobal.Currency.CNY)
{
settlementCurrency = ConsGlobal.Currency.CNH;
}
if (quoteCurrency == settlementCurrency)
{
return new eod_currency_rate
{
ValueDate = valueDate,
Rate = 1,
SellRate = 1,
BuyRate = 1,
ForeignCurrency = quoteCurrency,
LocalCurrency = settlementCurrency,
};
}
}
var predicateBase = PredicateBuilder.Create<eod_currency_rate>(x =>
x.ForeignCurrency == quoteCurrency && x.LocalCurrency == settlementCurrency
|| x.ForeignCurrency == settlementCurrency && x.LocalCurrency == quoteCurrency);
var predicate1 = PredicateBuilder.Create<eod_currency_rate>(x => x.ValueDate == valueDate.Date).And(predicateBase);
var datas = DbContext.eod_currency_rate.Where(predicate1).ToArray();
if (seekPreday && !datas.Any())
{
var preDay = DbContext.eod_currency_rate.Where(n => n.ValueDate < valueDate.Date).Max(n => (DateTime?)n.ValueDate);
if (preDay.HasValue)
{
predicate1 = PredicateBuilder.Create<eod_currency_rate>(x => x.ValueDate == preDay).And(predicateBase);
datas = DbContext.eod_currency_rate.Where(predicate1).ToArray();
}
}
if (datas.Any())
{
var r1 = datas.Where(x => x.ForeignCurrency.Equals(quoteCurrency, StringComparison.OrdinalIgnoreCase) && x.LocalCurrency.Equals(settlementCurrency, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
return r1 ?? datas[0].Reverse();
}
return null;
}
public void HandleAmountByCurrencyRate(DateTime settleDate, IEnumerable<int> clientIds)
{
#region 客户筛选 根据客户反向筛选tradeCashIds tw
var trades = new List<trade>();
var tradeCashs = DbContext.trade_cash.Where(x => x.ValueDate == settleDate && x.ValidState != "InValid" && x.CurrencyRate > 0).ToList();
if (PS.Config.IsGuoJun)
{
tradeCashs = (from tc in DbContext.trade_cash.Where(x => x.ValueDate == settleDate && x.ValidState != "InValid" && x.CurrencyRate > 0)
join td in DbContext.trade on tc.TradeId equals td.id into td
from t in td.DefaultIfEmpty()
where t.TradeType != "收益互换"
select tc).ToList();
}
var tradeIds = new List<int>();
var tradeCashIds = new List<int>();
if (clientIds != null)
{
trades = DbContext.trade.Where(x => clientIds.ToList().Contains(x.ClientId)).ToList();
tradeIds = trades.Select(x => x.id).ToList();
tradeCashs = tradeCashs.Where(x => tradeIds.Contains(x.TradeId)).ToList();
tradeCashIds = tradeCashs.Select(x => x.id).ToList();
}
else
{
tradeCashIds = tradeCashs.Select(x => x.id).ToList();
tradeIds = tradeCashs.Select(x => x.TradeId).ToList();
trades = DbContext.trade.Where(x => tradeIds.Contains(x.id)).ToList();
}
#endregion
var currencyRates = DbContext.eod_currency_rate.Where(x => x.ValueDate == settleDate).ToList();
var tradeSwapCashs = DbContext.trade_cash_swap.Where(x => tradeCashIds.Contains(x.TradeCashId)).ToList();
var tradeCashDetails = DbContext.trade_cash_detail.Where(x => tradeCashIds.Contains(x.TradeCashId)).ToList();
var clientCashInCashOuts = DbContext.ClientCashInCashOut.Where(x => tradeCashIds.Contains(x.TradeCashId)).ToList();
tradeCashs.ForEach(x =>
{
var trade = trades.FirstOrDefault(y => y.id == x.TradeId);
if (trade == null)
{
throw new Exception($"trade表未找到id[{x.TradeId}]的交易");
}
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
var rate = 1.0;
var rateTradeDate = 1.0;
if (!string.IsNullOrWhiteSpace(trade.QuoteCurrency) && !string.IsNullOrWhiteSpace(trade.SettlementCurrency) && trade.QuoteCurrency != trade.SettlementCurrency)
{
rate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(trade.QuoteCurrency, trade.SettlementCurrency, settleDate);
rateTradeDate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(trade.QuoteCurrency, trade.SettlementCurrency, trade.TradeDate.Value);
}
if (PS.Config.Company == Configuration.CompanyEnum.中粮 && x.Action != ClientCashInCashOut.系统操作_期权费)
{
rate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(trade.QuoteCurrency, trade.SettlementCurrency, settleDate, currencyRateType: x.Amount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
}
var rateChange = rate / x.CurrencyRate.Value;
x.CurrencyRate = rate;
var tcds = tradeCashDetails.Where(y => y.TradeCashId == x.id).ToList();
double extraAmountGet = 0.0;
double amount = 0.0;
tcds.ForEach(y =>
{
if (y.QuoteAmount != null)
{
if (y.TradeCashType == TradeCashTypeEnum.利息.ToString())
{
if (PS.Config.Company == Configuration.CompanyEnum.中金 && client.BoundSide == BoundSideEnum.南向)
{
y.Amount = y.QuoteAmount * rateTradeDate;
}
else
{
y.Amount = y.QuoteAmount * rate;
}
extraAmountGet = y.Amount ?? 0;
}
else
{
y.Amount = y.QuoteAmount * rate;
}
y.ExtraAmount *= rateChange;
y.InitialAmount *= rateChange;
}
amount += y.Amount ?? 0;
});
x.Amount = amount;
if (x.Action == ClientCashInCashOut.系统操作_期权费)
{
trade.TradePrice = amount * (trade.BuySell == "买入" ? -1 : 1);
}
var tradeSwapCash = tradeSwapCashs.FirstOrDefault(y => y.TradeCashId == x.id);
if (tradeSwapCash != null)
{
tradeSwapCash.GetAmount *= rateChange;
tradeSwapCash.GetCostFee *= rateChange;
tradeSwapCash.GetInitialAmount *= rateChange;
if (extraAmountGet > 0)
{
tradeSwapCash.GetExtraAmount = extraAmountGet;
}
else
{
tradeSwapCash.GetExtraAmount *= rateChange;
}
tradeSwapCash.PayAmount *= rateChange;
tradeSwapCash.PayCostFee *= rateChange;
tradeSwapCash.PayInitialAmount *= rateChange;
tradeSwapCash.PayExtraAmount *= rateChange;
}
var ccicos = clientCashInCashOuts.Where(y => y.TradeCashId == x.id).ToList();
ccicos.ForEach(y =>
{
y.Money = -x.Amount;
});
});
DbContext.SaveChanges();
}
/// <summary>
/// 检查汇率缺失(暂时适用于中金)
/// </summary>
public EodCurrencyCheckResult CheckEodCurrencyRateMissing(DateTime date)
{
var result = new EodCurrencyCheckResult { CurDate = date.OtcFormatDate() };
switch (date.DayOfWeek)
{
case DayOfWeek.Saturday:
case DayOfWeek.Sunday:
result.Error = "周末日期不需要检查";
return result;
}
date = date.Date;
var currencyCodes = DbContext.currency.Where(n => n.StartDate == null || n.StartDate <= date).Select(n => n.CurrencyCode).AsEnumerable()
.Select(n => n.ToUpperInvariant()).Where(n => !ConsGlobal.Currency.CNCurrencies.Contains(n)).ToArray();
result.Items = new List<EodCurrencyCheckResultItem>();
var curProvider = new EodCurrencyProvider(date, false);
foreach (var code in currencyCodes)
{
var item = new EodCurrencyCheckResultItem { CurrencyPair = code + ConsGlobal.Currency.CNH };
if (curProvider.TryGetCurrencyRate(code, ConsGlobal.Currency.CNH, out var cur))
{
item.CurRate = cur.Rate.ToString("0.00#");
}
result.Items.Add(item);
}
foreach (var code in currencyCodes.Except(new List<string>() { ConsGlobal.Currency.USD }))
{
var item = new EodCurrencyCheckResultItem { CurrencyPair = code + ConsGlobal.Currency.USD };
if (curProvider.TryGetCurrencyRate(code, ConsGlobal.Currency.USD, out var cur))
{
item.CurRate = cur.Rate.ToString("0.00#");
}
result.Items.Add(item);
}
result.HasMissing = result.Items.Any(n => n.CurRate == null);
//检查上日汇率缺失情况,以便判断是否可以复制前日
if (result.HasMissing)
{
var predate = date.AddDays(-1);
switch (predate.DayOfWeek)
{
case DayOfWeek.Saturday:
predate = predate.AddDays(-1);
break;
case DayOfWeek.Sunday:
predate = predate.AddDays(-2);
break;
}
result.PreDate = predate.OtcFormatDate();
var preProvider = new EodCurrencyProvider(predate, false);
foreach (var code in currencyCodes)
{
var item = result.Items.Find(n => n.CurrencyPair == code + ConsGlobal.Currency.CNH);
if (preProvider.TryGetCurrencyRate(code, ConsGlobal.Currency.CNH, out var cur))
{
item.PreRate = cur.Rate.ToString("0.00#");
}
}
foreach (var code in currencyCodes.Except(new List<string>() { ConsGlobal.Currency.USD }))
{
var item = result.Items.Find(n => n.CurrencyPair == code + ConsGlobal.Currency.USD);
if (preProvider.TryGetCurrencyRate(code, ConsGlobal.Currency.USD, out var cur))
{
item.PreRate = cur.Rate.ToString("0.00#");
}
}
result.CanCopyPre = result.Items.All(n => n.PreRate != null);
}
return result;
}
/// <summary>
/// 复制上日汇率
/// </summary>
public int CopyPreCurrencyRate(DateTime date, out DateTime preDate)
{
preDate = date.AddDays(-1);
switch (preDate.DayOfWeek)
{
case DayOfWeek.Saturday:
preDate = preDate.AddDays(-1);
break;
case DayOfWeek.Sunday:
preDate = preDate.AddDays(-2);
break;
}
var preDate2 = preDate;
var lookup = DbContext.eod_currency_rate.AsNoTracking()
.Where(n => n.ValueDate == date || n.ValueDate == preDate2)
.ToLookup(n => n.ForeignCurrency + n.LocalCurrency);
foreach (var lp in lookup)
{
var arr = lp.ToArray();
if (arr.Length == 1 && arr[0].ValueDate == preDate)
{
var clone = arr[0].Clone();
clone.id = 0;
clone.ValueDate = date;
DbContext.eod_currency_rate.Add(clone);
}
}
return DbContext.SaveChanges();
}
public bool HadCurrencyUsed(string currencyCode)
{
return DataCacheProvider.GetClientDataSource().AsQueryable().Any(o => o.SettlementCurrency == currencyCode) || DataCacheProvider.GetVarietyDataSource().AsQueryable().Any(o => o.QuoteCurrency == currencyCode);
}
}
/// <summary>
///
/// </summary>
public class EodCurrencyCheckResult
{
/// <summary>
/// 错误信息
/// </summary>
public string Error { get; set; }
/// <summary>
/// 当前交易日
/// </summary>
public string CurDate { get; set; }
/// <summary>
/// 上个交易日
/// </summary>
public string PreDate { get; set; }
/// <summary>
/// 是否缺失
/// </summary>
public bool HasMissing { get; set; }
/// <summary>
/// 是否可以复制上日
/// </summary>
public bool CanCopyPre { get; set; }
/// <summary>
/// 详细项目列表
/// </summary>
public List<EodCurrencyCheckResultItem> Items { get; set; }
}
public class EodCurrencyCheckResultItem
{
public string CurrencyPair { get; set; }
public string CurRate { get; set; }
public string PreRate { get; set; }
}
}