using BaseOUDAL; using DotNetDBF; using YLErp.BLL; using YLErp.Commons; using YLErp.Models; using YLErp.Modules.TradeRiskCalcModule; namespace YLErp.Modules.ExchangeTradeModule { /// /// 对冲交易(股票、商品期货)的系统合成持仓和读取的持仓回报数据进行比对 /// public class HedgePositionCheckService : YLBaseService { public HedgePositionCheckService(OptUserInfo userInfo) : base(userInfo) { } public List CheckAndAddHedgePosition(UploadFileModel[] files, out List diffAccounts, out List unexistUmds) { var result = CheckHedgePosition(files, out diffAccounts, out unexistUmds); var tradeList = new List(); foreach (var item in result) { var diffNotional = item.CURQTY - item.SystemNotional; var diffTradePrice = item.DbfTradePrice - item.SystemTradePrice; if (diffNotional != 0) { var hedgeTrade = new trade() { UnderlyingCode = item.Underlying.UnderlyingCode, UnderlyingAssetClass = item.Underlying.UnderlyingType, UnderlyingAssetName = item.Underlying.UnderlyingName, UnderlyingId = item.Underlying.id, UnderlyingInstrumentType = item.Underlying.UnderlyingInstrumentType, TradeNumber = UniqueTimeId.GetStr(), TradeDate = valuedateBLL.ValueDate, StartDate = valuedateBLL.ValueDate, MaturityDate = item.Underlying.MaturityDate, ExerciseDate = item.Underlying.MaturityDate, TradeStatus = ConsTrade.确认成交, ValidState = "Valid", AssetId = item.AssetUnit.id, AssetBookName = item.AssetUnit.Name, TradeType = "股票", TradeUnit = "100股/手", TraderId = item.AssetUnit.TraderIdsInt.FirstOrDefault(), TraderName = UserBLL.GetNameById(item.AssetUnit.TraderIdsInt.FirstOrDefault()), Comments = "持仓差异处理", SpotPrice = item.Underlying.Price, OptId = UserId, OptName = UserName, OptDate = DateTime.Now, CreatorId = UserId, CreatorName = UserName, CreateDate = DateTime.Now }; hedgeTrade.OriginalNotional = Math.Abs(diffNotional); hedgeTrade.Notional = Math.Abs(diffNotional); hedgeTrade.TradeAmount = Math.Abs(diffNotional); hedgeTrade.Lots = Math.Abs(diffNotional) / 100; //正常情况下diffTradePrice和diffNotional应该同号, 此时TradePrice和TradeSinglePrice均为正 //当diffTradePrice和diffNotional不同号时,说明系统原数据存在脏数据情况,此时需要补一笔TradePrice和TradeSinglePrice均为负的特殊交易,用来保持持仓成本一致 hedgeTrade.TradePrice = (diffNotional > 0 ? 1 : -1) * diffTradePrice; hedgeTrade.TradeSinglePrice = diffTradePrice / diffNotional; hedgeTrade.BuySell = diffNotional > 0 ? "买入" : "卖出"; tradeList.Add(hedgeTrade); } } DbContext.trade.AddRange(tradeList); DbContext.SaveChanges(); return result; } public List CheckHedgePosition(UploadFileModel[] files, out List diffAccounts, out List unexistUmds) { unexistUmds = new List(); var diffResults = new List(); var dbfHedgePositions = GetHedgePositionDbfFiles(files, out diffAccounts); var dbfHedgePositionGroups = dbfHedgePositions.GroupBy(x => new { x.BookId, x.BookName, x.SYMBOL }).Select(x => new DbfHedgePosition { BookId = x.Key.BookId, SYMBOL = x.Key.SYMBOL, BookName = x.Key.BookName, CURQTY = x.Sum(y => y.CURQTY), DbfTradePrice = x.Sum(y => y.CURQTY * y.COSTPRICE), AssetUnit = x.Select(y => y.AssetUnit).FirstOrDefault() }); var umProvider = DataCacheModule.DataCacheManager.GetUnderlyingDataSource(); foreach (var group in dbfHedgePositionGroups) { var req = new TradingRiskReqModel { Stock = true, AssetTypes = new[] { "股票" }, BookIds = new List { group.BookId ?? 0 } }; if (unexistUmds.Contains(group.SYMBOL)) { continue; } var um = umProvider.GetData(group.SYMBOL); if (um != null) { group.Underlying = um; req.UnderlyingIds = new[] { um.id }; var result = new TradingRiskReqService(OptUser).GetResult(req); if (result != null) { var totalNotional = result.TradeRiskList.Sum(x => x.Notional); var totalTradePrice = result.TradeRiskList.Sum(x => x.TradePrice); if (group.CURQTY != totalNotional) { group.SystemNotional = totalNotional; group.SystemTradePrice = totalTradePrice; diffResults.Add(group); } } else { group.SystemNotional = 0; group.SystemTradePrice = 0; diffResults.Add(group); } } else { unexistUmds.Add(group.SYMBOL); } } return diffResults; } public List CompareExchangedOptionPosition(out string message) { message = string.Empty; var valueDate = valuedateBLL.ValueDate; var diffResults = new List(); var exchangedOptionPositions = new List(); var eodTradePositionStatics = DbContext.eod_trade_position_static2.Where(x => x.ValueDate == valueDate && x.TradeType == "场内期权").ToList(); var exchangeAccounts = DataCacheProvider.GetExchangeAccountDataSource().AsQueryable(); var assetUnits = DataCacheProvider.GetAssetUnitDataSource(); var underlyings = DataCacheModule.DataCacheManager.GetUnderlyingDataSource(); var exoptions = DataCacheModule.DataCacheManager.GetExchangeListOptionDataSource(); eodTradePositionStatics.ForEach(x => { var exchangeAccount = exchangeAccounts.FirstOrDefault(y => y.AccountCode == x.AccountCode); if (exchangeAccount != null) { var exoption = exoptions.GetData(x.UnderlyingCode); var underlying = underlyings.GetData(exoption?.UnderlyingCode); if (underlying != null) { var assetUnit = assetUnits.GetData(exchangeAccount.DefaultBookId ?? 0); exchangedOptionPositions.Add(new DbfHedgePosition() { ACCT = x.AccountCode, CURQTY = x.Volume * underlying.ContractSize * (x.PositionType == "long" ? 1 : -1), SYMBOL = x.OptionCode, BookId = exchangeAccount.DefaultBookId, BookName = assetUnit != null ? assetUnit.Name : string.Empty }); } } }); var exchangedOptionPositionsGroups = exchangedOptionPositions.GroupBy(x => new { x.BookId, x.BookName, x.SYMBOL }).Select(x => new DbfHedgePosition { BookId = x.Key.BookId, SYMBOL = x.Key.SYMBOL, BookName = x.Key.BookName, CURQTY = x.Sum(y => y.CURQTY) }); if (!exchangedOptionPositionsGroups.Any()) { message = "未发现场内期权持仓数据"; } var req = new TradingRiskReqModel { Stock = false, AssetTypes = new[] { "场内期权" } }; var result = new TradingRiskReqService(OptUser).GetResult(req); foreach (var group in exchangedOptionPositionsGroups) { var tradeRiskList = result.TradeRiskList.Where(x => x.BookId == group.BookId && x.ExchangeOptionCode == group.SYMBOL); if (tradeRiskList != null) { var totalNotional = tradeRiskList.Sum(x => x.Notional); if (group.CURQTY != totalNotional) { group.SystemNotional = totalNotional; diffResults.Add(group); } } else { group.SystemNotional = 0; diffResults.Add(group); } } return diffResults; } public List CompareCommodityFuturePosition(out string message) { message = string.Empty; var valueDate = valuedateBLL.ValueDate; var diffResults = new List(); var exchangedOptionPositions = new List(); var eodTradePositionStatics = DbContext.eod_trade_position_static2.Where(x => x.ValueDate == valueDate && x.TradeType == "商品期货").ToList(); var exchangeAccounts = DataCacheProvider.GetExchangeAccountDataSource().AsQueryable(); var assetUnits = DataCacheProvider.GetAssetUnitDataSource(); var underlyings = DataCacheModule.DataCacheManager.GetUnderlyingDataSource(); eodTradePositionStatics.ForEach(x => { var exchangeAccount = exchangeAccounts.FirstOrDefault(y => y.AccountCode == x.AccountCode); if (exchangeAccount != null) { var underlying = underlyings.GetData(x.UnderlyingCode); if (underlying != null) { var assetUnit = assetUnits.GetData(exchangeAccount.DefaultBookId ?? 0); exchangedOptionPositions.Add(new DbfHedgePosition() { ACCT = x.AccountCode, CURQTY = x.Volume * underlying.ContractSize * (x.PositionType == "long" ? 1 : -1), SYMBOL = x.UnderlyingCode, BookId = exchangeAccount.DefaultBookId, BookName = assetUnit != null ? assetUnit.Name : string.Empty }); } } }); var exchangedOptionPositionsGroups = exchangedOptionPositions.GroupBy(x => new { x.BookId, x.BookName, x.SYMBOL }).Select(x => new DbfHedgePosition { BookId = x.Key.BookId, SYMBOL = x.Key.SYMBOL, BookName = x.Key.BookName, CURQTY = x.Sum(y => y.CURQTY) }); if (!exchangedOptionPositionsGroups.Any()) { message = "未发现商品期货持仓数据"; } foreach (var group in exchangedOptionPositionsGroups) { var req = new TradingRiskReqModel { Stock = false, AssetTypes = new[] { "商品期货" }, BookIds = new List { group.BookId ?? 0 } }; var um = underlyings.GetData(group.SYMBOL); if (um != null) { group.Underlying = um; req.UnderlyingIds = new[] { um.id }; var result = new TradingRiskReqService(OptUser).GetResult(req); if (result != null) { var totalNotional = result.TradeRiskList.Sum(x => x.Notional); if (group.CURQTY != totalNotional) { group.SystemNotional = totalNotional; diffResults.Add(group); } } else { group.SystemNotional = 0; diffResults.Add(group); } } } return diffResults; } private List GetHedgePositionDbfFiles(UploadFileModel[] files, out List diffAccounts) { var dbfHedgePosition = new List(); diffAccounts = new List(); var exchangeAccounts = DataCacheProvider.GetExchangeAccountDataSource().AsQueryable(); var assetUnits = DataCacheProvider.GetAssetUnitDataSource(); for (var i = 0; i < files.Length; i++) { using (var stream = files[i].OpenReadStream()) using (var dbf = new DBFReader(stream)) { var columnCount = dbf.Fields.Length; if (columnCount < 12) { throw new Exception(files[i].FileName + "文件非持仓文件,不被识别"); } else { if (dbf.Fields[0].Name != "ACCT" || dbf.Fields[3].Name != "SYMBOL" || dbf.Fields[6].Name != "CURQTY" || dbf.Fields[11].Name != "COSTPRICE") { throw new Exception(files[i].FileName + "文件非持仓文件,不被识别"); } } var count = dbf.RecordCount; for (var j = 0; j < count; j++) { var dbfRecord = dbf.NextRecord(); if (dbfRecord != null) { var account = dbfRecord[0].ToString().Trim(); if (diffAccounts.Contains(account)) { continue; } var exchangeAccount = exchangeAccounts.FirstOrDefault(x => x.AccountCode == account); if (exchangeAccount != null) { var assetUnit = assetUnits.GetData(exchangeAccount.DefaultBookId ?? 0); double.TryParse(dbfRecord[6].ToString(), out var curqty); double.TryParse(dbfRecord[11].ToString(), out var costPrice); dbfHedgePosition.Add(new DbfHedgePosition() { ACCT = account, CURQTY = curqty, COSTPRICE = costPrice, SYMBOL = dbfRecord[3].ToString(), BookId = exchangeAccount.DefaultBookId, BookName = assetUnit != null ? assetUnit.Name : string.Empty, AssetUnit = assetUnit }); } else { diffAccounts.Add(account); } } } } } return dbfHedgePosition; } } public class DbfHedgePosition { /// /// 簿记账户 /// public string ACCT { get; set; } /// /// 标的代码 /// public string SYMBOL { get; set; } /// /// 【dbf文件】数量 /// public double CURQTY { get; set; } /// /// 【dbf文件】单价 /// public double COSTPRICE { get; set; } /// /// 【dbf文件】总价 /// public double DbfTradePrice { get; set; } /// /// 系统数量 /// public double SystemNotional { get; set; } public double SystemTradePrice { get; set; } public int? BookId { get; set; } public string BookName { get; set; } public underlying_manager Underlying { get; set; } public AssetUnit AssetUnit { get; set; } } }