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 { /// /// 日终汇率数据服务 /// public class EodCurrencyRateService : YLBaseService { public EodCurrencyRateService(OptUserInfo userInfo) : base(userInfo) { } public SearchListResult 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; } /// /// 导入xlsx数据 /// public ImportResultModel ImportxlsxDatas(Stream stream) { var importModels = Enumerable.Empty(); 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(); 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; } /// /// 获取货币对汇率 /// /// 计价货币 /// 结算货币 /// 取值日期 /// 如果取值日期未找到汇率是否向前日继续查找 /// 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); } } /// /// 获取货币对汇率 /// /// 计价货币 /// 结算货币 /// 取值日期 /// 如果取值日期未找到汇率是否向前日继续查找 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(x => x.ForeignCurrency == quoteCurrency && x.LocalCurrency == settlementCurrency || x.ForeignCurrency == settlementCurrency && x.LocalCurrency == quoteCurrency); var predicate1 = PredicateBuilder.Create(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(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 clientIds) { #region 客户筛选 根据客户反向筛选tradeCashIds tw var trades = new List(); 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(); var tradeCashIds = new List(); 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(); } /// /// 检查汇率缺失(暂时适用于中金) /// 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(); 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() { 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() { 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; } /// /// 复制上日汇率 /// 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); } } /// /// /// public class EodCurrencyCheckResult { /// /// 错误信息 /// public string Error { get; set; } /// /// 当前交易日 /// public string CurDate { get; set; } /// /// 上个交易日 /// public string PreDate { get; set; } /// /// 是否缺失 /// public bool HasMissing { get; set; } /// /// 是否可以复制上日 /// public bool CanCopyPre { get; set; } /// /// 详细项目列表 /// public List Items { get; set; } } public class EodCurrencyCheckResultItem { public string CurrencyPair { get; set; } public string CurRate { get; set; } public string PreRate { get; set; } } }