using System.Data; using YLErp.BLL; using YLErp.Commons; using YLErp.DBModels.Enums; using YLErp.Modules.CalculationModule; namespace YLErp.Modules.ExchangeTradeModule { /// /// 场内交易导入服务 /// public class ExchangeTradeImportService : ExchangeTradeSaveServiceBase { public ExchangeTradeImportService(OptUserInfo userInfo) : base(userInfo) { } /// /// 导入交易 /// public int ImportExcel(Stream streamIn, out int TotalNum, out int SuccessNum) { var rowIndex = 0; try { var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 1); 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); rowIndex = 1; TotalNum = table.Rows.Count; var tradePositions = new List(); foreach (var row in table.Rows.Cast()) { rowIndex++; if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString()))) { continue; } reader.SetDataRow(row); var dto = MapTrade(reader); var td = PrepareSave(dto); DbContext.ExchangeTrade.Add(td); ExchangeTrade tdp; if (string.IsNullOrWhiteSpace(td.OptionCode)) { tdp = tradePositions.Where(o => o.AssetBookId == td.AssetBookId && o.TradeType == td.TradeType && o.OptionCode == null && o.UnderlyingCode == td.UnderlyingCode && o.TradeSide.Substring(0, 2) == td.TradeSide.Substring(0, 2)).FirstOrDefault(); } else { tdp = tradePositions.Where(o => o.AssetBookId == td.AssetBookId && o.TradeType == td.TradeType && td.OptionCode == o.OptionCode && o.UnderlyingCode == td.UnderlyingCode && o.TradeSide.Substring(0, 2) == td.TradeSide.Substring(0, 2)).FirstOrDefault(); } var sign = TradeCalcHelper.GetSign(td.TradeSide); //汇总exchangeTrade if (tdp != null) { tdp.TradeLots = td.TradeLots * sign + tdp.TradeLots; tdp.Notional = td.Notional * sign + tdp.Notional; tdp.TradeSinglePrice += td.TradeLots * td.TradeSinglePrice * sign; tdp.Commission += td.Commission; } else { tdp = td.Clone(); tdp.TradeSide = td.TradeSide.StartsWith("多头") ? "多头开仓" : "空头平仓"; tdp.TradeLots *= sign; tdp.Notional *= sign; tdp.TradeSinglePrice *= tdp.TradeLots; tradePositions.Add(tdp); } } foreach (var td in tradePositions) { td.TradeSinglePrice = Math.Abs(td.TradeLots) > 1e-5 ? td.TradeSinglePrice / td.TradeLots : 0; SaveExchangeTradePosition(td); } SuccessNum = TotalNum; return DbContext.SaveChanges(); } 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); } } //将req转换交易对象 private ExchangeTrade PrepareSave(ExchangeTradeDto dto) { SetDBModelOpt(dto); var contractSize = 0d; if (dto.TradeType == "场内期权") { SetTradeOptionInfo(dto, dto.UnderlyingCode, out var option); contractSize = option.ContractSize; } //标的信息 SetTradeUnderlyingInfo(dto, dto.UnderlyingCode, out var um); //验证股票结构类型,只能股票标的,商品期货只能期货 switch (dto.TradeType) { case "股票": if (!um.CalcTypeIsStock()) { throw new ServiceException("股票交易类型必须使用股票标的"); } break; case "商品期货": if (!um.IsFutures()) { throw new ServiceException("商品期货交易类型必须填写期货标的"); } break; case "商品现货": if (!um.IsCommoditySpot()) { throw new ServiceException("商品现货交易类型必须填写商品现货标的"); } break; case "信用债": case "利率债": case "其它债券": if (!um.IsBond()) { throw new ServiceException(dto.TradeType+"交易类型必须填写债券标的"); } dto.TradeSinglePrice /= 100; break; } //交易数量 SetTradeLotsInfo(dto, dto.TradeLots, contractSize < 1 ? um.ContractSize : contractSize, um.UnderlyingTypeId); //簿记和对冲账户 SetAssetAndExchangeAccount(dto, dto.AssetBookName, dto.ExchangeAccountCode, um.UnderlyingTypeId); //交易员信息 dto.TraderId = UserId; dto.TraderName = UserName; dto.TradeSource = "导入交易"; dto.IsValid = true; dto.CreateTime = DateTime.Now; return YLAutoMapper.Map(dto); } private ExchangeTradeDto MapTrade(DataRowReader reader) { var dto = new ExchangeTradeDto { TradeType = reader.GetString("交易类型", true) }; dto.TradeType = CheckTradeType(dto.TradeType); dto.TradeNumber = reader.GetString("交易编号", false); if (string.IsNullOrWhiteSpace(dto.TradeNumber)) { dto.TradeNumber = DateTime.Now.ToString("yyyyMMddHHmmssfff"); } dto.AssetBookName = reader.GetString("簿记账户", false); dto.ExchangeAccountCode = reader.GetString("对冲账户", false); if (string.IsNullOrWhiteSpace(dto.AssetBookName) && string.IsNullOrWhiteSpace(dto.ExchangeAccountCode)) { throw new ServiceException("簿记账户和对冲账户 至少填写一个"); } dto.UnderlyingCode = reader.GetString("交易标的", true).ToUpperInvariant(); dto.TradeSide = reader.GetString("交易方向", true); if (!ConsGlobal.TradeSide.IsValid(dto.TradeSide)) { throw new ServiceException("交易方向未能识别:" + dto.TradeSide); } dto.TradeDate = reader.GetDate("交易日期", true).Value; if (dto.TradeDate > valuedateBLL.ValueDate) { throw new ServiceException("交易日期 不能大于系统日期:" + valuedateBLL.ValueDate.ToString("yyyy-MM-dd")); } dto.TradeLots = Math.Abs(reader.GetDouble("成交手数", true).Value); dto.TradeSinglePrice = reader.GetDouble("成交单价", true).Value; if (dto.TradeLots < 1e-5) { throw new ServiceException("成交手数 必须大于0:" + dto.TradeLots); } var commission = reader.GetDouble("手续费", false); if (commission.HasValue) { dto.Commission = commission.Value; dto.CommissionType = CommissionType.手动录入; } else { dto.CommissionType = CommissionType.系统计算; } dto.Comments = reader.GetString("备注", false); return dto; } } }