← 返回编程题库
coding-single-name-concentration-limit-flagging中等免费版2000ms未尝试

单一交易对手集中度:标出突破 Basel 大额风险暴露限额的对手方

Single-Name Concentration: Flag Counterparties Breaching the Basel Large-Exposure Limit

开始编码

实现 solution(exposures: list[float], counterparty_id: list[int], num_counterparties: int, tier1_capital: float, limit_pct: float) -> list[int]。该行的信用风险官每日跑一次本函数,把已突破 Basel III 单一交易对手集中度限额的对手方挑出来。第 i 条记录代表一笔逐笔 Exposure-at-Default exposures[i](美元),记在 counterparty_id[i] 这个交易对手账下。对手 id 取值范围 [0, num_counterparties);从未在记录里出现的对手聚合敞口为零。tier1_capital 是该行 Tier-1 监管资本(美元);limit_pct 是单一对手限额相对 Tier-1 资本的比例(Basel 默认 0.25 = 25%)。

输出列表由如下可观测公式定义:

  1. 逐对手聚合agg[cp] = sum(exposures[i] for i in range(N) if counterparty_id[i] == cp),其中 cp in [0, num_counterparties)。从未出现在记录里的对手 agg[cp] = 0.0
  2. 阈值T = limit_pct * tier1_capital
  3. 判定:当且仅当 agg[cp] > T严格大于>=)时把 cp 写进输出。
  4. 排序:把被标出的 id 升序返回。无人越线时返回空列表 []

solution([100.0, 200.0, 300.0, 80.0, 80.0], [0, 1, 2, 0, 1], 4, 1000.0, 0.25) 返回 [1, 2]tier1_capital = 1000limit_pct = 0.25,阈值 T = 250。聚合:cp 0 的记录 100 + 80 = 180cp 1200 + 80 = 280cp 2300cp 3 没有任何记录,所以 0。逐个对 T = 250 比:cp 0 = 180(未越线),cp 1 = 280(越线——标),cp 2 = 300(越线——标),cp 3 = 0(未越线)。按升序输出 [1, 2]

一个逐记录看不见、聚合后才越线的算例:solution([100.0, 100.0, 100.0], [0, 0, 0], 1, 1000.0, 0.25) 返回 [0]。三笔记录单笔都是 100,远低于 250 阈值。但三笔全在 cp 0 名下,聚合敞口 300 越线。逐笔判定的写法会得到 [];正确答案是 [0]。这正是集中度限额的经济意义——监管关心银行对单一对手总敞口,不是任何一笔的大小。

边界exposures 为空时返回 [](任何 cp 都没有记录可聚合)。tier1_capital = 0T = 0;任何聚合敞口为正的对手都会被标(严格 >),但聚合恰为 0 的对手会被标。聚合恰好等于 T 的对手同样会被标(再次:严格 >)。当 num_counterparties 大于实际出现过的 id 数时,没出现过的对手聚合为 0,永远过不了正阈值。输出始终升序;exact 比较器会拒绝按记录遍历顺序得到的列表,哪怕集合本身是对的。

实现细节由 stubs/stub.py 提供。

实践背景

在 Basel III 大额风险暴露框架下,每家银行必须把跨账户、跨产品、跨实体聚合后超过监管限额(历史标准是合格 Tier-1 资本的 25%)的所有交易对手报送出来。本函数 solution(...) 的输出就是信用风险官每日交给前台的那张越线名单:用于驱动减仓动作(平掉越线的那本账、把头寸换约到别的对手)、资本补充(新发 Tier-1 把分母拉高)、或者在持续越线时升级到监管沟通。聚合-判定-排序这三段是模板化的:任何一个产生"逐实体越线名单"的姊妹度量(关联方大额暴露、国别敞口限额、行业上限监控)都共用同样的形状。本函数刻意锁住的几条概念约定——先聚合再判、严格大于因为限额本身允许、升序输出便于按 id 扫读、未出现过的对手聚合为 0 不会越正阈值——正是工业集中度监控管线和监管自查里反复出现的方向性错误。一遍线性扫描聚合、一遍线性扫描判定、再对(小规模的)越线集合做最终排序,就是该日度合计的标准模式。

约束条件

  • 0 <= len(exposures) == len(counterparty_id) <= 200
  • 1 <= num_counterparties <= 50;0 <= counterparty_id[i] < num_counterparties
  • 0.0 <= exposures[i] <= 1e9;0.0 <= tier1_capital <= 1e10
  • 0.0 < limit_pct <= 1.0(Basel 默认 0.25)
  • 输出:升序的 list[int],元素是 [0, num_counterparties) 范围内互不相同的对手方 id;无人越线时返回空列表 [];列表使用 exact 比较器

样例

Case 1 · statement-example: cp 1 and 2 exceed 25 percent

输入: [[100,200,300,80,80],[0,1,2,0,1],4,1000,0.25]

期望: [1,2]

聚合后 cp 0 = 180、cp 1 = 280、cp 2 = 300、cp 3 = 0;阈值 250;280 > 250 且 300 > 250,按升序输出 [1, 2]。

Case 2 · visible: empty exposures yields no flags

输入: [[],[],3,500,0.25]

期望: []

没有任何敞口记录,所有 cp 的聚合值为 0,阈值 125 > 0,无人越线,返回 []。

最近提交

还没有提交记录。

编码区

实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。

加载编辑器...
计时0:00

默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。

Case 1 · statement-example: cp 1 and 2 exceed 25 percent

输入: [[100,200,300,80,80],[0,1,2,0,1],4,1000,0.25]

期望: [1,2]

聚合后 cp 0 = 180、cp 1 = 280、cp 2 = 300、cp 3 = 0;阈值 250;280 > 250 且 300 > 250,按升序输出 [1, 2]。

Case 2 · visible: empty exposures yields no flags

输入: [[],[],3,500,0.25]

期望: []

没有任何敞口记录,所有 cp 的聚合值为 0,阈值 125 > 0,无人越线,返回 []。