using BaseOUDAL; using System.Text.RegularExpressions; using YLErp.Abstract.DataProviders; using YLErp.Commons; using YLErp.DBModels.Consts; using YLErp.Model; using YLErp.Modules.DataProviderModule; using YLErp.Modules.SuperviseReportModule.CFMMC.Model; namespace YLErp.Modules.SuperviseReportModule.CFMMC.Service { public abstract class SuperviseReportBaseService : YLBaseService { protected SuperviseReportReq _req { get; set; } /// /// 是否是权益报告 /// protected bool _isEquity => _req.DataSource == "权益"; /// /// 分隔符 /// 权益:分号 /// 商品:逗号 /// protected string _separator => _isEquity ? ";" : ","; protected IEodPriceProviderWrap _priceProvider; protected SuperviseReportBaseService(SuperviseReportReq req, OptUserInfo userInfo) : base(userInfo) { _req = req ?? throw new ArgumentNullException(nameof(req)); _priceProvider = new EodPriceProvider(_req.ValueDate).GetPriceProvider(SettlementTypeEnum.ClosePrice); } private readonly List ignoreTradeTypes = new List() { "凤凰期权", "雪球期权", "区间累积期权" }; /// /// /// /// /// 标的资产类型 /// 资产类型 /// 标的资产品种后缀和标的资产对应合约后缀 /// 组合标的价格 /// EodTrade不存在时抛出 protected virtual void FormatModel(SuperviseReportBaseModel model, List varietyTypes, List assetTypes, List varietySuffixs, List varietyCodeList, out SyntheticPriceModel syntheticPrice) { if (model.trade == null) { throw new ServiceException($"日终Trade不存在,交易编号:{model.OriginalTradeNumber}"); } model.BuySell = model.trade.BuySell == "买入" ? "B" : "S"; if (model.trade.TradeType == "远期") { if (model.trade.OptionType == "看跌") { model.BuySell = model.trade.BuySell == "卖出" ? "B" : "S"; } } model.ToolType = formatToolType(model.trade.TradeType, model.StructureType); model.ExerciseMode = /*ignoreTradeTypes.Contains(model.trade.TradeType) ? "O" :*/ IsOption(model.trade) ? (model.trade.ExerciseMode == "European" ? "EU" : "US") : ""; //国投特殊处理 model.ExerciseMode = PS.Config.Company == Configuration.CompanyEnum.国投 && model.trade.TradeType == "雪球期权" ? "O" : model.ExerciseMode; model.OptionType = ignoreTradeTypes.Contains(model.trade.TradeType) ? "9" : IsOption(model.trade) ? (model.trade.OptionType == "看涨" ? "2" : "1") : ""; model.Strike = (model.trade.IsMoneynessOptionData ? model.trade.SpotPrice * model.trade.Strike : model.trade.Strike) ?? 0; model.Strike = model.TradeType == "收益互换" ? Convert.ToDouble((model.trade.SpotPrice)) : model.Strike; model.ParticipateRate = model.trade.ParticipationRate ?? 1; if (model.trade.TradeType == "雪球期权") { model.IsAnnualTrade = (model.trade.trade_snowball?.IsAnnualized2).GetValueOrDefault() ? "Y" : "N"; } else if (model.trade.TradeType == "凤凰期权") { model.IsAnnualTrade = (model.trade.trade_autocall?.IsAnnualized2).GetValueOrDefault() ? "Y" : "N"; } else { model.IsAnnualTrade = model.trade.IsAnnualized ? "Y" : "N"; } //国投特殊处理 model.IsAnnualTrade = PS.Config.Company == Configuration.CompanyEnum.国投 && model.TradeType == "收益互换" ? "" : model.IsAnnualTrade; model.TradeNumber = formatTradeNumber(model); model.TradeTypeEn = IsOption(model.trade) ? formatTradeTypeEn(model) : (model.TradeType == "收益互换" && PS.Config.Company == Configuration.CompanyEnum.华安) ? "VE" : ""; var um = DataCacheProvider.GetUnderlyingDataSource().GetData(model.trade.UnderlyingCode); if (um.IsSynthetic() || !string.IsNullOrWhiteSpace(model.trade.BasisUnderlyingCode)) { Dictionary marketNoDict = new Dictionary(); var query = DbContext.TradeMeta.Where(O => O.TradeId == model.trade.id && O.MetaValue.Length > 5); if (um.IsSynthetic()) { query = query.Where(O => O.MetaKey.StartsWith(ConsTradeMetaKey.SyntheticUnderlying)); var tradeMeta = query.FirstOrDefault(); if (string.IsNullOrWhiteSpace(tradeMeta?.MetaValue)) { throw new ServiceException($"组合标的期初价格信息不完整,交易编号:{model.OriginalTradeNumber}"); } syntheticPrice = JsonHelper.Deserialize(tradeMeta.MetaValue); if (syntheticPrice.SuList == null) { throw new ServiceException($"组合标的价格缺失,交易编号:{model.trade.TradeNumber}"); } } else { query = query.Where(O => O.MetaKey == ConsTradeMetaKey.SpotInfos); var tradeMeta = query.FirstOrDefault(); string[] arrPrice = null; if (string.IsNullOrWhiteSpace(tradeMeta?.MetaValue)) { arrPrice = new[] { model.trade.SpotPrice?.ToString() }; } else { arrPrice = JsonHelper.Deserialize(tradeMeta.MetaValue); if (arrPrice == null || arrPrice.Length == 0) { throw new ServiceException($"期初价格缺失,交易编号:{model.trade.TradeNumber}"); } } var prides = new UnderlyingPriceModel[arrPrice.Length]; for (int i = 0; i < arrPrice.Length; i++) { prides[i] = new UnderlyingPriceModel(); prides[i].Price = double.TryParse(arrPrice[i], out var p) ? p : 0; prides[i].Coefficient = i == 0 ? 1 : -1; prides[i].UnderlyingCode = i == 0 ? model.trade.UnderlyingCode : model.trade.BasisUnderlyingCode; } syntheticPrice = new SyntheticPriceModel(); syntheticPrice.SuList = prides; } UnderlyingPriceModel[] underlyingCodes = syntheticPrice.SuList.Select(O => O).ToArray(); string[] arrCode = new string[underlyingCodes.Length]; string[] arrUnitZh = new string[underlyingCodes.Length]; string[] arrUnitEn = new string[underlyingCodes.Length]; string[] arrAssetTypeEn = new string[underlyingCodes.Length]; string[] arrVarietyType = new string[underlyingCodes.Length]; for (int i = 0; i < underlyingCodes.Length; i++) { if (underlyingCodes[i] == null || string.IsNullOrWhiteSpace(underlyingCodes[i].UnderlyingCode)) { arrCode[i] = ""; arrUnitZh[i] = ""; arrUnitEn[i] = ""; arrAssetTypeEn[i] = ""; arrVarietyType[i] = ""; continue; } var variety = UnderlyingDataProvider.GetVariety(underlyingCodes[i].UnderlyingCode); if (variety == null) { throw new ServiceException($"未找到品种数据: {underlyingCodes[i].UnderlyingCode}"); } var um1 = UnderlyingDataProvider.GetUnderlying(underlyingCodes[i].UnderlyingCode); string varietySuffix = formatDictItem(varietySuffixs, um1?.MarketCode, um1?.MarketCode); marketNoDict[underlyingCodes[i].UnderlyingCode] = varietySuffix; arrCode[i] = formatVarietyCode(underlyingCodes[i].UnderlyingCode, variety, varietyCodeList, varietySuffix); arrUnitZh[i] = variety.QuoteUnitSingleOriginal; arrUnitEn[i] = formatQuoteUnit(arrUnitZh[i]); arrAssetTypeEn[i] = formatDictItem(assetTypes, variety.AssetType); arrVarietyType[i] = formatDictItem(varietyTypes, variety.AssetType, "O"); } model.UnderlyingCode = formatSyntheticUnderlying(syntheticPrice, marketNoDict); //model.TradeAmount = string.Join(",", arrAmount); model.VarietyCode = JoinArr(arrCode); model.QuoteUnit = JoinArr(arrUnitZh); model.QuoteUnitEn = JoinArr(arrUnitEn); model.AssetTypeEn = JoinArr(arrAssetTypeEn); model.VarietyType = JoinArr(arrVarietyType); if (arrUnitEn.All(o => o == "bp")) { model.PriceSymbol = 3; } } else { var variety = UnderlyingDataProvider.GetVariety(model.trade.UnderlyingCode); if (variety == null) { throw new ServiceException($"未找到品种数据: {model.trade.UnderlyingCode}"); } string varietySuffix = formatDictItem(varietySuffixs, um?.MarketCode, um?.MarketCode); //model.TradeAmount = formatTradeAmount(model.trade.OriginalNotional); model.UnderlyingCode = formatUnderlyingCode(model.trade.UnderlyingCode, varietySuffix); model.VarietyCode = formatVarietyCode(model.trade.UnderlyingCode, variety, varietyCodeList, varietySuffix); model.QuoteUnit = (variety?.QuoteUnitSingleOriginal) ?? ""; model.QuoteUnitEn = formatQuoteUnit(variety?.QuoteUnitSingleOriginal); model.AssetTypeEn = formatDictItem(assetTypes, variety.AssetType); model.VarietyType = formatDictItem(varietyTypes, variety.AssetType, "O"); if (model.QuoteUnitEn == "bp") { model.PriceSymbol = 3; } syntheticPrice = null; } } protected double formatInitCastClientPayable(trade t) { double result = 0; if (t != null) { result = (t.InitialMargin * (t.Notional / t.OriginalNotional)) ?? 0; } return Math.Max(0, result); } protected string formatTradeAmount(double? notional, double coefficient = 1) { double? value = notional * coefficient; return OtcFormatHelper.FormatValue(value, 4).ToString(); } private string formatToolType(string tradeType, string structureType) { string toolType = "O"; switch (tradeType) { case "收益互换": toolType = "SW"; break; case "远期": toolType = "FW"; if (structureType == "掉期") { toolType = "SW"; } break; default: toolType = "OP"; break; } return toolType; } protected string formatDictItem(List dictItemMap, string name, string defaultValue = "") { if (name == null || dictItemMap == null) { return defaultValue; } var obj = dictItemMap.FirstOrDefault(O => O.Name == name); return obj == null ? defaultValue : obj.ShortName; } private string formatSyntheticUnderlying(SyntheticPriceModel underlying, Dictionary exchangeNo) { Func formatCode = (_coefficient, _underlyingCode) => { string code = formatUnderlyingCode(_underlyingCode, exchangeNo[_underlyingCode]); string coef = Math.Abs(_coefficient).ToString(); return $"{(coef == "1" ? "" : coef)}{code}"; }; var tipsInfo = ""; foreach (var item in underlying.SuList) { if (!string.IsNullOrEmpty(tipsInfo) || item.Coefficient < 0) { tipsInfo += (item.Coefficient >= 0 ? "+" : "-"); } tipsInfo += formatCode(item.Coefficient, item.UnderlyingCode); } return tipsInfo; } private string formatUnderlyingCode(string underlyingCode, string exchangeNo) { if (string.IsNullOrWhiteSpace(underlyingCode)) { throw new ArgumentException("标的代码不存在", nameof(underlyingCode)); } var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode); if (underlying == null) { throw new ArgumentException("标的信息不存在:" + underlyingCode); } if (underlying.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommoditySpot) { return underlying.UnderlyingName; } else if (underlyingCode.Contains(".")) { return underlyingCode; } return $"{underlyingCode}.{exchangeNo}"; } private string formatTradeNumber(SuperviseReportBaseModel model) { if ((model.trade.ParentTradeId > 0)) { var legNumber = 0; if (PS.Config.Company == Configuration.CompanyEnum.浙期) { if (!int.TryParse(Regex.Match(model.OriginalTradeNumber ?? "", @"(?<=X)\d+$").Value, out legNumber)) { return ""; } } else if (!int.TryParse(Regex.Match(model.trade.TradeNumber ?? "", @"(?<=-)\d+$").Value, out legNumber)) { return ""; } return legNumber.ToString(); } else { return ""; } } private string formatTradeTypeEn(SuperviseReportBaseModel model) { string tradeTypeEn = "O"; switch (model.TradeType) { case "香草期权": tradeTypeEn = "VA"; break; case "结构化交易": switch (model.StructureType) { case "风险逆转": tradeTypeEn = "RE"; break; case "三领口": case "三领口组合": tradeTypeEn = "CO"; break; case "跨式组合": tradeTypeEn = "STR"; break; case "宽跨式": case "宽跨式组合": tradeTypeEn = "STA"; break; case "牛市价差": case "熊市价差": tradeTypeEn = "VE"; break; case "结构化交易": //自由组合 default: break; } break; case "合成价差期权": tradeTypeEn = "SP"; break; case "凤凰期权": tradeTypeEn = "PA"; break; case "雪球期权": tradeTypeEn = "SA"; break; case "障碍期权": tradeTypeEn = "SF"; break; case "二元期权": switch (model.ExerciseMode) { case "US": case "American": switch (model.PayoffType) { case "UpOneTouch": case "DownOneTouch": case "DoubleOneTouch": tradeTypeEn = "OT"; break; case "DoubleNoTouch": tradeTypeEn = "DNT"; break; case "UpNoTouch": case "DownNoTouch": break; default: break; } break; case "EU": case "European": tradeTypeEn = "DI"; switch (model.PayoffType) { case "AssetOrNothing": break; case "CashOrNothing": break; default: break; } break; default: break; } break; case "亚式期权": tradeTypeEn = "AS"; break; case "双鲨期权": tradeTypeEn = "DSF"; break; case "区间累计期权": case "区间累积期权": tradeTypeEn = "RA"; break; default: tradeTypeEn = "O"; break; } return tradeTypeEn; } private string formatVarietyCode(string underlyingCode, Variety variety, List varietyCodeList, string marketExchangeNo) { if (string.IsNullOrWhiteSpace(underlyingCode)) { throw new ArgumentException("标的代码不存在", nameof(underlyingCode)); } var code = varietyCodeList.Where(O => O.Name.ToLower() == underlyingCode.ToLower()).Select(O => O.ShortName).FirstOrDefault(); if (!string.IsNullOrEmpty(code)) { return code; } var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode); if (underlying == null) { throw new ArgumentException("标的信息不存在:" + underlyingCode); } string assetVariety = $"{{0}}.{marketExchangeNo}"; switch (underlying.UnderlyingInstrumentType) { case ConsGlobal.InstrumentType.StockIndex: case ConsGlobal.InstrumentType.StockIF: assetVariety = variety.VarietyName; break; case ConsGlobal.InstrumentType.CommodityFutures: assetVariety = string.Format(assetVariety, variety.VarietyCode); break; case ConsGlobal.InstrumentType.CommoditySpot: if (marketExchangeNo == "SGE") { assetVariety = string.Format(assetVariety, underlyingCode); } else { assetVariety = variety.VarietyName; } break; case ConsGlobal.InstrumentType.Stock: assetVariety = string.Format(assetVariety, getStockVarietyCode(underlyingCode)); break; default: assetVariety = underlyingCode; break; } return assetVariety; } private string getStockVarietyCode(string code) { string assetVariety = ""; if (code.StartsWith("60") || code.StartsWith("000")) { //主板 assetVariety = "ZB"; } else if (code.StartsWith("002")) {//中小板 assetVariety = "ZXB"; } else if (code.StartsWith("300")) {//创业板 assetVariety = "CYB"; } else if (code.StartsWith("688")) {//科创版 assetVariety = "KCB"; } else { assetVariety = "JW"; } return assetVariety; } private string formatQuoteUnit(string quoteUnit) { switch (quoteUnit) { case "吨": return "t"; case "桶": return "barrel"; case "克": return "g"; case "千克": return "kg"; case "500千克": return "500kg"; case "股": return "share"; case "点": if (PS.Config.Company == Configuration.CompanyEnum.国投) { return "bp"; } return "point"; case "基点": return "bp"; case "units": return "units"; default: return "o"; } //return quoteUnit; } protected double formatEndStockEqvNotionalReal(double? stockEqvNotional, double percentRate) { double? result = stockEqvNotional * percentRate; return Math.Abs(OtcFormatHelper.FormatValue((result ?? 0), 4)); } protected string JoinArr(string[] arr) { HashSet singleArr = new HashSet(arr); singleArr.Remove(""); return string.Join(",", singleArr); } /// /// 是否为期权 /// /// /// private bool IsOption(trade t) { return t.IsOption() || t.TradeType == "自定义交易"; } } }