diff --git a/Framework/YLErp.Core/DBModels/Consts/ConsMarginTerm.cs b/Framework/YLErp.Core/DBModels/Consts/ConsMarginTerm.cs index 74779a4c..0105c168 100644 --- a/Framework/YLErp.Core/DBModels/Consts/ConsMarginTerm.cs +++ b/Framework/YLErp.Core/DBModels/Consts/ConsMarginTerm.cs @@ -10,33 +10,15 @@ namespace YLErp.DBModels /// /// 允许配置期限档(SpanConfig.BondTerm)的标的资产类型标志位。 /// 区间追保结构"按资产类型分类"时,仅这些类型允许设置非空期限档; - /// 本期仅含 利率债(TBonds=1<<4=16);ETF 子类分档能力见 TermTierEnabledEtfKinds。 + /// 仅含 利率债(TBonds=1<<4=16)。 + /// ETF 不分期限档(2026-08-27 业务裁定:ETF 没有期限概念, + /// 此前的 可转债 ETF/科创债 ETF 分档白名单 TermTierEnabledEtfKinds 已移除,如需恢复查 git 历史)。 /// public static readonly UnderlyingTypeEnum[] TermTierEnabledUnderlyingTypes = { UnderlyingTypeEnum.TBonds }; - /// - /// 允许配置期限档的 ETF 子类白名单(来自数据字典"ETF 子类")。 - /// 选择这些子类的 ETF 区块按固定4档展开(同利率债);其余子类/不区分的 ETF 区块单套参数、不分档。 - /// 取值与 underlying_manager.EtfSubType 字典项一致,由标的维护页维护。 - /// 注意:分档 ETF 子类行的 UnderlyingType 仍为 基金(32768),不走 TermTierEnabledUnderlyingTypes 位掩码(§1.2 决策:不再加枚举位)。 - /// - public static readonly List TermTierEnabledEtfKinds = new List - { - "可转债 ETF", - "科创债 ETF" - }; - - /// - /// 判断 EtfKind 是否允许分档(在 TermTierEnabledEtfKinds 白名单内)。 - /// - public static bool IsTermTierEnabledEtfKind(string etfKind) - { - return !string.IsNullOrEmpty(etfKind) && TermTierEnabledEtfKinds.Contains(etfKind); - } - /// /// 5年以下(同时也是兜底默认期限) /// diff --git a/UnitTestProject/Modules/CalcModules/MarginTemplateV2InstrumentFirstMatchTest.cs b/UnitTestProject/Modules/CalcModules/MarginTemplateV2InstrumentFirstMatchTest.cs new file mode 100644 index 00000000..6cf60d56 --- /dev/null +++ b/UnitTestProject/Modules/CalcModules/MarginTemplateV2InstrumentFirstMatchTest.cs @@ -0,0 +1,144 @@ +using YLErp.BLL; +using YLErp.DBModels; +using YLErp.Enums; +using YLErp.Modules.MarginModule; + +namespace YLErp.Modules.CalcModules +{ + /// + /// GetRateByTemplate 资产类型先行匹配回归(连 dev 库,2026-08-27 顺序裁定:先品种后期限): + /// 期限档仅利率债允许配置,品种匹配在期限之前——防止非利率债标的被利率债期限档行截胡 + /// (交易2567 实证:信用债标的按 "<5y" 精确匹配到利率债行,信用债行 BondTerm 空永远不参与)。 + /// 标的代码用库里不存在的代码(GetApplicableMarginTerm 无标的兜底返回 <5y),不依赖真实标的行情数据。 + /// 测试数据全部带 "ZZZ-品种先行测试-" 名称前缀,TestInitialize/TestCleanup 双向清理。 + /// + [TestClass] + public class MarginTemplateV2InstrumentFirstMatchTest + { + private const string Marker = "ZZZ-品种先行测试-"; + private DateTime EffectiveDate = new DateTime(2000, 1, 1); + + private YLContext db; + + [TestInitialize] + public void Init() + { + db = new YLContext(); + Cleanup(); + } + + [TestCleanup] + public void CleanupFixture() + { + Cleanup(); + db.Dispose(); + } + + private void Cleanup() + { + var templateIds = db.margin_template_v2.Where(x => x.Name.StartsWith(Marker)).Select(x => x.id).ToList(); + if (templateIds.Count > 0) + { + db.margin_template_detail.RemoveRange(db.margin_template_detail.Where(x => templateIds.Contains(x.MarginTemplateId))); + db.margin_template_v2.RemoveRange(db.margin_template_v2.Where(x => templateIds.Contains(x.id))); + db.SaveChanges(); + } + } + + private margin_template_v2 AddTieredTemplate() + { + var t = new margin_template_v2 + { + Name = Marker + "分档", + IsDefault = false, + IsForClient = false, + IsValid = true, + TradeTypes = "收益互换", + RuleType = (int)MarginRuleTypeEnum.区间追保结构, + UnderlyingSeperateType = (int)UnderlyingSeperateTypeEnum.CustomInstrumentType, + ValueDate = EffectiveDate + }; + db.margin_template_v2.Add(t); + db.SaveChanges(); + return t; + } + + private void AddDetail(int templateId, UnderlyingTypeEnum underlyingType, string bondTermJson, double initRate, double maintainRate) + { + db.margin_template_detail.Add(new margin_template_detail + { + MarginTemplateId = templateId, + ValueDate = EffectiveDate, + UnderlyingType = underlyingType, + SpanConfigJson = bondTermJson, + MarginRatio1 = initRate, + MarginRatio2 = maintainRate + }); + } + + /// + /// 信用债标的不被利率债期限档行截胡:term 恒为 "<5y"(标的不存在兜底), + /// 旧序会精确命中利率债 <5y 行;新序品种先行应命中信用债行(BondTerm 空)。 + /// + [TestMethod] + public void TI_001_信用债标的_命中信用债行_不被利率债期限档截胡() + { + var tpl = AddTieredTemplate(); + AddDetail(tpl.id, UnderlyingTypeEnum.TBonds, "{\"BondTerm\":\"<5y\"}", 0.11, 0.12); + AddDetail(tpl.id, UnderlyingTypeEnum.CreditBonds, null, 0.05, 0.06); + db.SaveChanges(); + + var rate = MarginTemplateV2RateHelper.GetRateByTemplate(tpl, "ZZZ-NOT-EXIST-CD.IB", "CreditBonds", DateTime.Today, db); + Assert.IsNotNull(rate, "品种先行后信用债行(BondTerm 空)应经期限兜底命中"); + Assert.AreEqual(0.05m, rate.InitRate.Value, "应取信用债行的初始预付金率,而非利率债 <5y 行的 0.11"); + Assert.AreEqual(0.06m, rate.MaintainRate.Value, "应取信用债行的维持预付金率,而非利率债 <5y 行的 0.12"); + } + + /// + /// 利率债标的行为不变:品种命中利率债行后,期限精确档 "<5y" 命中对应期限行(压过 5y-10y 行)。 + /// + [TestMethod] + public void TI_002_利率债标的_品种内期限精确档仍生效() + { + var tpl = AddTieredTemplate(); + AddDetail(tpl.id, UnderlyingTypeEnum.TBonds, "{\"BondTerm\":\"<5y\"}", 0.11, 0.12); + AddDetail(tpl.id, UnderlyingTypeEnum.TBonds, "{\"BondTerm\":\"5y-10y\"}", 0.13, 0.14); + db.SaveChanges(); + + var rate = MarginTemplateV2RateHelper.GetRateByTemplate(tpl, "ZZZ-NOT-EXIST-TB.IB", "TBonds", DateTime.Today, db); + Assert.IsNotNull(rate); + Assert.AreEqual(0.11m, rate.InitRate.Value, "期限兜底 <5y 时应精确命中 <5y 档行"); + Assert.AreEqual(0.12m, rate.MaintainRate.Value); + } + + /// + /// 模板未配标的品种时的既有兜底不变:品种行与通配行均无 → 不缩小行集,回落期限匹配(与旧序一致)。 + /// + [TestMethod] + public void TI_003_模板未配品种_回落期限匹配_行为不变() + { + var tpl = AddTieredTemplate(); + AddDetail(tpl.id, UnderlyingTypeEnum.TBonds, "{\"BondTerm\":\"<5y\"}", 0.11, 0.12); + db.SaveChanges(); + + var rate = MarginTemplateV2RateHelper.GetRateByTemplate(tpl, "ZZZ-NOT-EXIST-CF.IB", "CommodityFutures", DateTime.Today, db); + Assert.IsNotNull(rate, "品种落空应回落到期限匹配(旧行为兜底),不应返回 null"); + Assert.AreEqual(0.11m, rate.InitRate.Value); + } + + /// + /// 品种行与期限行均无法匹配时返回 null:非利率债标的不再"借用"利率债期限档行, + /// 由调用方按无预付金要求兜底(引擎不产出 trade_span)。 + /// + [TestMethod] + public void TI_004_品种与期限均无匹配行_返回null() + { + var tpl = AddTieredTemplate(); + AddDetail(tpl.id, UnderlyingTypeEnum.TBonds, "{\"BondTerm\":\"5y-10y\"}", 0.13, 0.14); + db.SaveChanges(); + + var rate = MarginTemplateV2RateHelper.GetRateByTemplate(tpl, "ZZZ-NOT-EXIST-CD.IB", "CreditBonds", DateTime.Today, db); + Assert.IsNull(rate, "信用债标的不应命中利率债 5y-10y 期限行"); + } + } +} diff --git a/YLErpDAL/AppManager.cs b/YLErpDAL/AppManager.cs index 0b244c2d..609c870a 100644 --- a/YLErpDAL/AppManager.cs +++ b/YLErpDAL/AppManager.cs @@ -171,6 +171,7 @@ namespace YLErp "yladmin" => _configuration.GetConnectionString("yladmin"), "ylclient" => _configuration.GetConnectionString("ylclient"), "bondoms" => _configuration.GetConnectionString("bondoms"), + "glms_bigdata" => _configuration.GetConnectionString("glms_bigdata"), "apex_oracle"=> _configuration.GetConnectionString("apex_oracle"), _ => string.Empty, }; diff --git a/YLErpDAL/Modules/MarginModule/MarginTemplateV2RateHelper.cs b/YLErpDAL/Modules/MarginModule/MarginTemplateV2RateHelper.cs index 99e47346..25999088 100644 --- a/YLErpDAL/Modules/MarginModule/MarginTemplateV2RateHelper.cs +++ b/YLErpDAL/Modules/MarginModule/MarginTemplateV2RateHelper.cs @@ -129,19 +129,39 @@ namespace YLErp.Modules.MarginModule var latestValueDate = detailQuery.Max(x => x.ValueDate); var details = detailQuery.Where(x => x.ValueDate == latestValueDate).ToList(); - //4.利率债/分档ETF 期限档匹配:精确档 → "全部"(BondTerm 为空)兜底 + //4.资产类型先行(2026-08-27 顺序裁定:先品种后期限):按资产类型分档的模板先按标的品种缩小行集—— + //品种行 → 通配行(None/All)→ 均无则不缩小(回落到与旧序一致的期限匹配,模板未配该品种的既有兜底不变)。 + //期限档仅利率债允许配置(ConsMarginTerm),品种匹配必须在期限之前:期限精确匹配对任何标的恒有 term + //(GetApplicableMarginTerm 兜底 <5y),非利率债标的会被利率债期限档行截胡、本品种行(BondTerm 空)永远不参与 + //(2026-08-27 交易2567 实证:信用债标的按 "<5y" 命中利率债行多收追保) + var candidates = details; + if (template.UnderlyingSeperateType == (int)UnderlyingSeperateTypeEnum.CustomInstrumentType + && Enum.TryParse(underlyingInstrumentType, out var instrumentFlag)) + { + var byInstrument = details.Where(x => (x.UnderlyingType & instrumentFlag) > 0).ToList(); + if (!byInstrument.Any()) + { + byInstrument = details.Where(x => x.UnderlyingType == UnderlyingTypeEnum.None || x.UnderlyingType == UnderlyingTypeEnum.All).ToList(); + } + if (byInstrument.Any()) + { + candidates = byInstrument; + } + } + + //5.期限档匹配(利率债四档):精确档 → "全部"(BondTerm 为空)兜底 var term = UnderlyingHelper.GetApplicableMarginTerm(underlyingCode, valueDate); - var matched = details.Where(x => x.SpanConfig != null && x.SpanConfig.BondTerm == term).ToList(); + var matched = candidates.Where(x => x.SpanConfig != null && x.SpanConfig.BondTerm == term).ToList(); if (!matched.Any()) { - matched = details.Where(x => x.SpanConfig == null || string.IsNullOrEmpty(x.SpanConfig.BondTerm)).ToList(); + matched = candidates.Where(x => x.SpanConfig == null || string.IsNullOrEmpty(x.SpanConfig.BondTerm)).ToList(); } if (!matched.Any()) { return null; } - //5.ETF 子类行优先(子类区分度高于期限):标的有 EtfSubType(基金类)时优先取 EtfKind=子类 的行—— + //6.ETF 子类行优先(子类区分度高于期限):标的有 EtfSubType(基金类)时优先取 EtfKind=子类 的行—— //期限档匹配未命中子类行时再单独尝试"子类 + BondTerm 空"(子类不分档通配);无子类行维持原 matched(基金通配兜底) var underlyingCategory = GetUnderlyingCategory(underlyingCode, underlyingInstrumentType); if (underlyingCategory != null) @@ -149,24 +169,6 @@ namespace YLErp.Modules.MarginModule matched = PreferCategoryRows(matched, details, underlyingCategory); } - if (template.UnderlyingSeperateType == (int)UnderlyingSeperateTypeEnum.CustomInstrumentType - && Enum.TryParse(underlyingInstrumentType, out var instrumentFlag)) - { - var byInstrument = matched.Where(x => (x.UnderlyingType & instrumentFlag) > 0).ToList(); - if (byInstrument.Any()) - { - matched = byInstrument; - } - else - { - var wildcard = matched.Where(x => x.UnderlyingType == UnderlyingTypeEnum.None || x.UnderlyingType == UnderlyingTypeEnum.All).ToList(); - if (wildcard.Any()) - { - matched = wildcard; - } - } - } - var detail = matched.First(); return new MarginRateResult { diff --git a/YLErpDAL/Modules/UnderlyingModule/FundManagerLookupService.cs b/YLErpDAL/Modules/UnderlyingModule/FundManagerLookupService.cs new file mode 100644 index 00000000..b37d8f5e --- /dev/null +++ b/YLErpDAL/Modules/UnderlyingModule/FundManagerLookupService.cs @@ -0,0 +1,94 @@ +using Dapper; +using MySqlConnector; +using YieldChain.Helpers; +using YLErp.BLL; + +namespace YLErp.Modules.UnderlyingModule +{ + public enum FundManagerLookupStatus + { + NotFound, + Unique, + Multiple, + Unavailable + } + + public sealed class FundManagerLookupResult + { + public FundManagerLookupStatus Status { get; init; } + public string InvestAdvisorName { get; init; } + } + + /// + /// 查询上游基金档案中的基金管理人。上游不可用时返回降级结果,不阻断页面编辑。 + /// + public sealed class FundManagerLookupService + { + private sealed class FundManagerRow + { + public string InvestAdvisorCode { get; set; } + public string InvestAdvisorName { get; set; } + } + + private const string LookupSql = @" +SELECT + ia.investadvisorcode AS InvestAdvisorCode, + ia.investadvisorname AS InvestAdvisorName +FROM glms_bigdata.mf_fundarchives AS fa +INNER JOIN glms_bigdata.mf_investadvisoroutline AS ia + ON CONVERT(fa.investadvisorcode USING utf8mb4) COLLATE utf8mb4_unicode_ci = + CONVERT(ia.investadvisorcode USING utf8mb4) COLLATE utf8mb4_unicode_ci +WHERE CONVERT(fa.secucode USING utf8mb4) COLLATE utf8mb4_unicode_ci = + CONVERT(TRIM(SUBSTRING_INDEX(@UnderlyingCode, '.', 1)) USING utf8mb4) COLLATE utf8mb4_unicode_ci"; + + public FundManagerLookupResult Lookup(string underlyingCode) + { + var normalizedCode = NormalizeCode(underlyingCode); + if (string.IsNullOrEmpty(normalizedCode)) + { + return new FundManagerLookupResult { Status = FundManagerLookupStatus.NotFound }; + } + + var connectionString = AppManager.GetConnectionString("glms_bigdata"); + if (string.IsNullOrWhiteSpace(connectionString)) + { + return new FundManagerLookupResult { Status = FundManagerLookupStatus.Unavailable }; + } + + try + { + using var connection = new MySqlConnection(connectionString); + var matches = connection.Query(LookupSql, new { UnderlyingCode = normalizedCode }, commandTimeout: 10) + .Where(row => !string.IsNullOrWhiteSpace(row.InvestAdvisorName)) + .GroupBy(row => (row.InvestAdvisorCode ?? string.Empty).Trim(), StringComparer.OrdinalIgnoreCase) + .Select(group => group.Select(row => row.InvestAdvisorName.Trim()).Distinct(StringComparer.OrdinalIgnoreCase).ToArray()) + .Where(names => names.Length > 0) + .ToArray(); + + return matches.Length switch + { + 0 => new FundManagerLookupResult { Status = FundManagerLookupStatus.NotFound }, + 1 when matches[0].Length == 1 => new FundManagerLookupResult { Status = FundManagerLookupStatus.Unique, InvestAdvisorName = matches[0][0] }, + _ => new FundManagerLookupResult { Status = FundManagerLookupStatus.Multiple } + }; + } + catch (Exception ex) + { + LogFactory.GetLogger().Error("查询基金管理人失败,代码:" + normalizedCode, ex); + return new FundManagerLookupResult { Status = FundManagerLookupStatus.Unavailable }; + } + } + + public static string NormalizeCode(string underlyingCode) + { + var trimmed = underlyingCode?.Trim(); + if (string.IsNullOrEmpty(trimmed)) + { + return null; + } + + var dotIndex = trimmed.IndexOf('.'); + return (dotIndex < 0 ? trimmed : trimmed.Substring(0, dotIndex)).TrimToNull(); + } + } +} diff --git a/YLErpWeb/Controllers/PricingController.cs b/YLErpWeb/Controllers/PricingController.cs index b0af74eb..c65dc87d 100644 --- a/YLErpWeb/Controllers/PricingController.cs +++ b/YLErpWeb/Controllers/PricingController.cs @@ -85,54 +85,6 @@ namespace YLErp.Web.Controllers return View(model); } - /// - /// 组合报价 - /// - [MyAuthorize("报价管理-结构化交易定价")] - public ActionResult Structure_DZ() - { - var otcTrade = new OtcOptionTradeFull() - { - TraderId = CurUser.UserId, - TraderName = CurUser.UserName, - BuySell = "卖出", - VolType = "交易", - TradeType = "香草期权", - OptionType = "看涨", - ExerciseMode = "European", - TradeDate = valuedateBLL.ValueDate, - UnderlyingInstrumentType = AppHelper.OtcConfig.StockFirst ? "Stock" : "CommodityFutures", - SettlementType = (int)SettlementTypeEnum.ClosePrice, - NoRiskRate = valuedateBLL.SystemDate.RiskFreeRate / 100, - ParticipationRate = 1, - AnnualizeFactor = 1, - MarginTemplateName = "系统默认", - CouponIncludeStartDate = false, - CouponUsePaymentDate = false - }; - - var model = new Models.PricingModel(CurUser, UserBLL.IsTradeOfCurrentLogin(CurUser.UserId)) { Trade = otcTrade }; - - if (model.NumOfSmoothingDaysCfg == "ONE") - { - model.Trade.NumOfSmoothingDays = 1; - } - //获取自定义结构信息 - var structureTypes = - new StructureService(CurUser) - .QueryStructureMap(StructureRangeEnum.BALCK_TRADE); - var structureTypeMap = new Dictionary>() { - { "气囊结构",new List() } - }; - foreach (var item in structureTypes) - { - structureTypeMap[item.Key] = item.Value; - } - ViewBag.StructureTypeMap = structureTypeMap; - - return View(model); - } - /// /// 组合报价导入 /// @@ -198,11 +150,6 @@ namespace YLErp.Web.Controllers ViewBag.ExtendInfoMap[item.Key] = item.Value; } - if (PS.Config.Is润和) - { - return View(nameof(Structure_DZ), model); - } - return View(nameof(Structure), model); } diff --git a/YLErpWeb/Controllers/margin_template_v2Controller.cs b/YLErpWeb/Controllers/margin_template_v2Controller.cs index ddc056ca..a0452fae 100644 --- a/YLErpWeb/Controllers/margin_template_v2Controller.cs +++ b/YLErpWeb/Controllers/margin_template_v2Controller.cs @@ -304,8 +304,8 @@ namespace YLErp.Web.Controllers } } - //区间追保结构 + 按资产类型分类时,期限档仅允许"允许分期限档的资产类型"(利率债)或"允许分档的 ETF 子类" - //(可转债 ETF/科创债 ETF,行 UnderlyingType=基金 + EtfKind=子类,不加枚举位)配置,防止非分档类型误配期限档; + //区间追保结构 + 按资产类型分类时,期限档仅允许利率债配置(2026-08-27 裁定:ETF 无期限概念, + //可转债 ETF/科创债 ETF 的分档白名单已移除,所有 ETF 子类/基金行一律单套参数不分档),防止非分档类型误配期限档; //该校验按行生效,与明细行数无关(单行明细同样拦截); //按严格掩码判定:行标的类型位必须全部落在可分档类型内(混合标志位如 利率债|信用债 配期限档同样拦截,与取数侧整行期限档过滤语义一致); //UnderlyingType 为空的通配行允许配期限档(取数侧期限档过滤在前、通配匹配在后,语义自洽) @@ -313,34 +313,24 @@ namespace YLErp.Web.Controllers && marginTemplate.UnderlyingSeperateType == (int)UnderlyingSeperateTypeEnum.CustomInstrumentType) { var enabledMask = ConsMarginTerm.TermTierEnabledUnderlyingTypes.Aggregate(UnderlyingTypeEnum.None, (a, t) => a | t); - var tierEnabledEtfKinds = ConsMarginTerm.TermTierEnabledEtfKinds; foreach (var detail in marginTemplate.Details) { var etfKind = detail.SpanConfig?.EtfKind; + var bondTerm = detail.SpanConfig?.BondTerm; //ETF 子类行:仅允许纯基金行(配置页子类选择器也只在纯基金区块出现) if (!string.IsNullOrEmpty(etfKind) && detail.UnderlyingType != UnderlyingTypeEnum.Fund) { throw new Exception("配置了 ETF 子类(" + etfKind + ")的参数组资产类型必须为 基金及基金专户"); } - var isTierEnabledEtfKind = tierEnabledEtfKinds.Contains(etfKind ?? ""); - if (!string.IsNullOrEmpty(detail.SpanConfig?.BondTerm) - && (detail.UnderlyingType & ~enabledMask) != UnderlyingTypeEnum.None - && !isTierEnabledEtfKind) + //ETF 子类不分期限档(对存量 4 档子类行回存给出精确报错;基金通配行由下面的掩码校验拦截) + if (!string.IsNullOrEmpty(etfKind) && !string.IsNullOrEmpty(bondTerm)) + { + throw new Exception("ETF 子类 " + etfKind + " 不分期限档,参数行不能配置期限档"); + } + if (!string.IsNullOrEmpty(bondTerm) && (detail.UnderlyingType & ~enabledMask) != UnderlyingTypeEnum.None) { throw new Exception("标的类型不允许配置期限档:" + UnderlyingTypeUtil.GetDesc(detail.UnderlyingType)); } - //分档 ETF 子类必须配期限档(区块固定4档),其余子类行禁配期限档 - if (!string.IsNullOrEmpty(etfKind)) - { - if (isTierEnabledEtfKind && string.IsNullOrEmpty(detail.SpanConfig?.BondTerm)) - { - throw new Exception("ETF 子类 " + etfKind + " 为分期限档类型,参数行必须配置期限档"); - } - if (!isTierEnabledEtfKind && !string.IsNullOrEmpty(detail.SpanConfig?.BondTerm)) - { - throw new Exception("ETF 子类 " + etfKind + " 不分期限档,参数行不能配置期限档"); - } - } } } @@ -399,8 +389,8 @@ namespace YLErp.Web.Controllers { if (marginTemplate.RuleType == (int)MarginRuleTypeEnum.区间追保结构) { - //区间追保结构:按 (利率债期限档, ETF细分) 元组分组校验(EtfKind 为预留扩展键,本期无 UI 写入,等价于仅期限档分组), - //同一分组内标的类型不允许重复,不同分组允许相同标的类型; + //区间追保结构:按 (利率债期限档, ETF细分) 元组分组校验——期限档仅利率债有值(其余恒空), + //EtfKind 为基金行的子类键;同一分组内标的类型不允许重复,不同分组允许相同标的类型; //通配行(空/全部,UnderlyingType=None/All)两两之间位与恒为 0 检不出,须单独拦截(BUG-09)—— //否则取数侧通配兜底 matched.First() 命中不确定 foreach (var termGroup in marginTemplate.Details.GroupBy(x => (x.SpanConfig?.BondTerm ?? "", x.SpanConfig?.EtfKind ?? ""))) diff --git a/YLErpWeb/Controllers/underlying_managerController.cs b/YLErpWeb/Controllers/underlying_managerController.cs index 69ba8b66..fa9e7f35 100644 --- a/YLErpWeb/Controllers/underlying_managerController.cs +++ b/YLErpWeb/Controllers/underlying_managerController.cs @@ -525,6 +525,25 @@ namespace YLErp.Web.Controllers return JsonSuccess("", underlying); } + /// + /// 查询上游基金档案中的基金管理人。查询失败或结果不唯一时返回可降级结果。 + /// + [HttpGet] + public JsonResult GetFundManager(string code, string instrumentType) + { + if (!string.Equals(instrumentType, ConsGlobal.InstrumentType.Fund, StringComparison.OrdinalIgnoreCase)) + { + return JsonSuccess("", new FundManagerLookupResult { Status = FundManagerLookupStatus.NotFound }); + } + + var result = new FundManagerLookupService().Lookup(code); + return JsonSuccess("", new + { + result.InvestAdvisorName, + IsUnique = result.Status == FundManagerLookupStatus.Unique + }); + } + /// /// 预付金参数 /// diff --git a/YLErpWeb/Views/Pricing/Structure_DZ.cshtml b/YLErpWeb/Views/Pricing/Structure_DZ.cshtml deleted file mode 100644 index af6dcf67..00000000 --- a/YLErpWeb/Views/Pricing/Structure_DZ.cshtml +++ /dev/null @@ -1,910 +0,0 @@ -@using Microsoft.AspNetCore.Html -@using YLErp.QdpModule.Constants -@model PricingModel -@{ - ViewBag.Title = "期权定价"; - - if (Model.IsImport) - { - Layout = "~/Views/Shared/_InfoLayout.cshtml"; - } - else - { - Layout = "~/Views/Shared/_MainLayout.cshtml"; - } - var assetunits = JsDataModel.GetAssetUnits(CurUser); - var traders = JsDataModel.GetTraders(assetunits); - var pageObj = new - { - assetunits = assetunits, - trade = new trade() { Strike = 0 }, - traders = JsDataModel.GetTraders(assetunits), - tradeMarginTemplateItems = new tradeController().GetMarginTemplateItems(), - tradeMarginTemplates = new tradeController().GetMarginTemplates(), - engineNames = new[] { "abc", "xyz" }, - structureTypes = ViewBag.StructureTypeMap?.Keys, - PropertyMap = ViewBag.StructureTypeMap, - IsPVIncludePrincipal = PS.Config.ErpElement.IsPVIncludePrincipal - }; - var pageData = new - { - showCCR = PS.Config.Company == CompanyEnum.国海, - is厦门象屿 = PS.Config.Company == CompanyEnum.厦门象屿, - }; -} -@section CSS{ - - @switch (PS.Config.Company) - { - case CompanyEnum.光大光子: - - break; - case CompanyEnum.国泰君安: - - break; - } - -} -@section JS{ - - - - - - - - - - - @if (PS.Config.Company == CompanyEnum.伴兴) - { - - } - else if (PS.Config.Company == CompanyEnum.茂川资本) - { - - } - else if (PS.Config.Company == CompanyEnum.弘业) - { - - } - - - -} - -@await Html.PartialAsync("_CouponDayCount") - -
- - -
-
-
- -
- -
-
- - - - @if (CurUser.交易管理_交易新增) - { - - } - -
- - -
- - - @if (CurUser.交易管理_分组设置) - { - - } -
-
-
-
- -
- -
- - - - - - - - - @**@ - - - - - - - - - - - - - - @**@ - - - - - - - - - - -
对冲手数组合成交金额组合预付金Day1PnlPVDeltaGammaCashThetaVegaRho
- {{DeltaHands}} - @if (Model.HedgingOrder && Model.IsTrader) - { - - } - {{summary.TotalTradePrice| FixNumber}}{{summary.TotalMargin| FixNumber}}{{summary.TotalDay1Pnl| FixNumber}}{{summary.Pv| FixNumber}}{{summary.Delta| FixNumber}}{{summary.GammaCash| FixNumber}}{{summary.Theta| FixNumber}}{{summary.Vega| FixNumber}}{{summary.Rho| FixNumber}}
-
- -
- - -
-
-
-
@(Model.CompanyName) 付 0.000
-
-
组合单价
-
-
-
-
-
-
-
-
-
-
- -
- - - - - -@await Html.PartialAsync("_PricingItemTpl_dz") - - - - - - - - - - - - - - - - - - - - -
- -
- -@await Html.PartialAsync("_SyntheticPrice") -@await Html.PartialAsync("/Views/trade/_part/SalesCommission.cshtml", new SalesCommissionModel() { Disabled = false, ViewType = "期权" }) - - - - diff --git a/YLErpWeb/Views/Pricing/_PricingItemTpl_dz.cshtml b/YLErpWeb/Views/Pricing/_PricingItemTpl_dz.cshtml deleted file mode 100644 index f51a95fd..00000000 --- a/YLErpWeb/Views/Pricing/_PricingItemTpl_dz.cshtml +++ /dev/null @@ -1,905 +0,0 @@ -@*定价模板*@ -@model PricingModel -@{ Layout = null;} - - \ No newline at end of file diff --git a/YLErpWeb/Views/margin_template_v2/margin_template_v2ClientEdit.cshtml b/YLErpWeb/Views/margin_template_v2/margin_template_v2ClientEdit.cshtml index 66f204fc..8242976e 100644 --- a/YLErpWeb/Views/margin_template_v2/margin_template_v2ClientEdit.cshtml +++ b/YLErpWeb/Views/margin_template_v2/margin_template_v2ClientEdit.cshtml @@ -34,7 +34,7 @@
-
+

新模板信息

@@ -142,7 +142,7 @@
-
@@ -158,7 +158,7 @@
-
@@ -167,15 +167,15 @@
-
+