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