balabs-risk-kernel 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ .ruff_cache/
5
+ dist/
@@ -0,0 +1,71 @@
1
+ Metadata-Version: 2.4
2
+ Name: balabs-risk-kernel
3
+ Version: 0.1.1
4
+ Summary: Risk model v2 liquidation kernel — pure compute, no DB access
5
+ Author-email: Twigmaester <81682766+Twigmaester@users.noreply.github.com>
6
+ Requires-Python: <3.15,>=3.13
7
+ Requires-Dist: numpy<3,>=2.1
8
+ Description-Content-Type: text/markdown
9
+
10
+ # risk-kernel
11
+
12
+ The risk model v2 liquidation-simulation kernel as a standalone package —
13
+ pure compute (numpy + stdlib), zero DB access, no write path. Powers the
14
+ on-demand LTV↔CRR estimator endpoint in `core-api` (office #490).
15
+
16
+ The kernel operates on in-memory `PricePaths` / `SellOrderbook` /
17
+ `BorrowerPosition` structures (`risk_kernel.liquidator.types`); loading those
18
+ inputs from a database is the consumer's job, never this package's.
19
+
20
+ ## Consumers
21
+
22
+ - **core-api** — installs this package from PyPI (`risk-kernel`) and runs the
23
+ kernel in-process for the estimator endpoint.
24
+ - **core** — NOT hooked up yet, deliberately out of scope for now. core keeps
25
+ its own in-tree copy at `src/risk_model_v2/liquidator/` and remains the
26
+ production source of truth for kernel logic.
27
+
28
+ ## Source of truth & sync protocol
29
+
30
+ Until core itself consumes this package, this repo is a **mirror** of core's
31
+ kernel, pinned to:
32
+
33
+ - source: **blockanalitica/core** `src/risk_model_v2/liquidator/`
34
+ - commit: **`c0bb2732e51cbb2338e0db5f49799088529e003c`** (main, 2026-07-03)
35
+
36
+ Kernel changes land in **core first** (production model), then get pulled
37
+ here:
38
+
39
+ ```sh
40
+ git -C ../core diff <pinned-commit>..main -- src/risk_model_v2/liquidator/
41
+ ```
42
+
43
+ Apply the changes to `src/risk_kernel/`, bump the pin above and the package
44
+ version, then bump the pin in consumers. The divergences below are expected
45
+ diff noise; everything else must match, e.g.:
46
+
47
+ ```sh
48
+ diff -r ../core/src/risk_model_v2/liquidator/ src/risk_kernel/liquidator/
49
+ ```
50
+
51
+ There is no test guardrail — the pin is the only drift baseline.
52
+
53
+ ## Deliberate divergences from core (the ONLY ones allowed)
54
+
55
+ 1. **Persistence stripped** from `liquidator/pipeline/processors/liquidator.py`:
56
+ the `_persist_market_crr` / `_persist_scenario_paths` /
57
+ `_rewrite_market_crr_tiers` / `_prune_market_crr_snapshot24` methods, their
58
+ call sites in `sync()`, the `risk_model_v2.models` import block, and the
59
+ imports only they used (`asdict`, `timedelta`,
60
+ `MARKET_CRR_SNAPSHOT24_RETENTION_DAYS`, `CapturedScenarioPaths`,
61
+ `select_bands`). `sync()` computes and returns `CRRSummary` objects,
62
+ nothing else. `pipeline/scenario_paths.py` is unused after the strip but
63
+ kept verbatim so the drift diff stays trivial.
64
+ 2. **Package renamed**: core's `risk_model_v2.liquidator` → `risk_kernel.liquidator`
65
+ (mechanical import rewrite; tree structure is otherwise 1:1 so the diff
66
+ above works).
67
+ 3. **`constants.py` is a 3-constant subset** of core's
68
+ `src/risk_model_v2/constants.py` (`FORECAST_STEP`, `N_MC`, `SEED`) — the
69
+ only values the kernel imports from outside the liquidator subtree.
70
+
71
+ Anything else diverging from core = drift = bug.
@@ -0,0 +1,62 @@
1
+ # risk-kernel
2
+
3
+ The risk model v2 liquidation-simulation kernel as a standalone package —
4
+ pure compute (numpy + stdlib), zero DB access, no write path. Powers the
5
+ on-demand LTV↔CRR estimator endpoint in `core-api` (office #490).
6
+
7
+ The kernel operates on in-memory `PricePaths` / `SellOrderbook` /
8
+ `BorrowerPosition` structures (`risk_kernel.liquidator.types`); loading those
9
+ inputs from a database is the consumer's job, never this package's.
10
+
11
+ ## Consumers
12
+
13
+ - **core-api** — installs this package from PyPI (`risk-kernel`) and runs the
14
+ kernel in-process for the estimator endpoint.
15
+ - **core** — NOT hooked up yet, deliberately out of scope for now. core keeps
16
+ its own in-tree copy at `src/risk_model_v2/liquidator/` and remains the
17
+ production source of truth for kernel logic.
18
+
19
+ ## Source of truth & sync protocol
20
+
21
+ Until core itself consumes this package, this repo is a **mirror** of core's
22
+ kernel, pinned to:
23
+
24
+ - source: **blockanalitica/core** `src/risk_model_v2/liquidator/`
25
+ - commit: **`c0bb2732e51cbb2338e0db5f49799088529e003c`** (main, 2026-07-03)
26
+
27
+ Kernel changes land in **core first** (production model), then get pulled
28
+ here:
29
+
30
+ ```sh
31
+ git -C ../core diff <pinned-commit>..main -- src/risk_model_v2/liquidator/
32
+ ```
33
+
34
+ Apply the changes to `src/risk_kernel/`, bump the pin above and the package
35
+ version, then bump the pin in consumers. The divergences below are expected
36
+ diff noise; everything else must match, e.g.:
37
+
38
+ ```sh
39
+ diff -r ../core/src/risk_model_v2/liquidator/ src/risk_kernel/liquidator/
40
+ ```
41
+
42
+ There is no test guardrail — the pin is the only drift baseline.
43
+
44
+ ## Deliberate divergences from core (the ONLY ones allowed)
45
+
46
+ 1. **Persistence stripped** from `liquidator/pipeline/processors/liquidator.py`:
47
+ the `_persist_market_crr` / `_persist_scenario_paths` /
48
+ `_rewrite_market_crr_tiers` / `_prune_market_crr_snapshot24` methods, their
49
+ call sites in `sync()`, the `risk_model_v2.models` import block, and the
50
+ imports only they used (`asdict`, `timedelta`,
51
+ `MARKET_CRR_SNAPSHOT24_RETENTION_DAYS`, `CapturedScenarioPaths`,
52
+ `select_bands`). `sync()` computes and returns `CRRSummary` objects,
53
+ nothing else. `pipeline/scenario_paths.py` is unused after the strip but
54
+ kept verbatim so the drift diff stays trivial.
55
+ 2. **Package renamed**: core's `risk_model_v2.liquidator` → `risk_kernel.liquidator`
56
+ (mechanical import rewrite; tree structure is otherwise 1:1 so the diff
57
+ above works).
58
+ 3. **`constants.py` is a 3-constant subset** of core's
59
+ `src/risk_model_v2/constants.py` (`FORECAST_STEP`, `N_MC`, `SEED`) — the
60
+ only values the kernel imports from outside the liquidator subtree.
61
+
62
+ Anything else diverging from core = drift = bug.
@@ -0,0 +1,71 @@
1
+ [project]
2
+ name = "balabs-risk-kernel"
3
+ dynamic = ["version"]
4
+ description = "Risk model v2 liquidation kernel — pure compute, no DB access"
5
+ authors = [{name="Twigmaester", email="81682766+Twigmaester@users.noreply.github.com"}]
6
+ readme = "README.md"
7
+ license-files = ["LICEN[CS]E*"]
8
+ requires-python = ">=3.13,<3.15"
9
+ dependencies = [
10
+ "numpy>=2.1,<3",
11
+ ]
12
+
13
+ [dependency-groups]
14
+ dev = [
15
+ "ruff==0.15.4",
16
+ ]
17
+
18
+ [tool.uv]
19
+ exclude-newer = "7 days"
20
+
21
+ [tool.ruff]
22
+ target-version = "py313"
23
+ line-length = 100
24
+ indent-width = 4
25
+
26
+ [tool.ruff.lint]
27
+ fixable = ["ALL"]
28
+ unfixable = []
29
+ extend-select = [
30
+ "YTT", # flake8-2020
31
+ "B", # flake8-bugbear
32
+ "A", # flake8-builtins
33
+ "C4", # flake8-comprehensions
34
+ "SIM", # flake8-simplify
35
+ "PIE", # flake8-pie
36
+ "DTZ", # flake8-datetimez
37
+ "I", # isort
38
+ "E", # pycodestyle
39
+ "W", # pycodestyle
40
+ "F", # pyflakes
41
+ "UP", # pyupgrade
42
+ "N", # pep8-naming
43
+ "PERF", # Perflint
44
+ ]
45
+ # Kernel code must stay diffable against core's src/risk_model_v2/liquidator/
46
+ # (see README) — rules that would force edits there are off.
47
+ ignore = ["B905", "SIM108", "PERF401"]
48
+
49
+ [tool.ruff.format]
50
+ quote-style = "double"
51
+ indent-style = "space"
52
+ skip-magic-trailing-comma = false
53
+ line-ending = "lf"
54
+
55
+ [build-system]
56
+ requires = ["hatchling>=1.29.0"]
57
+ build-backend = "hatchling.build"
58
+
59
+ [tool.hatch.version]
60
+ path = "src/risk_kernel/__init__.py"
61
+
62
+ [tool.hatch.build.targets.wheel]
63
+ packages = ["src/risk_kernel"]
64
+
65
+ [tool.hatch.build.targets.sdist]
66
+ include = ["src/**", "pyproject.toml", "README*", "LICENSE*"]
67
+
68
+ [tool.semantic_release]
69
+ commit_message = "chore(release): {version}"
70
+ version_variables = ["src/risk_kernel/__init__.py:__version__"]
71
+ allow_zero_version = true
@@ -0,0 +1 @@
1
+ __version__ = "0.1.1"
@@ -0,0 +1,8 @@
1
+ # Minimal subset of core's src/risk_model_v2/constants.py — only the values
2
+ # the vendored liquidator kernel imports. Values must match upstream at the
3
+ # commit pinned in README.md.
4
+
5
+ FORECAST_STEP = 14
6
+ N_MC = 10_000
7
+
8
+ SEED = 0
@@ -0,0 +1,35 @@
1
+ from decimal import Decimal
2
+
3
+ # Protocols that use the Maple-style margin-call cure.
4
+ # When MarketContext.protocol matches one of these and margin_call_enabled is
5
+ # left as None, the liquidator turns margin calls on. Override the flag to opt
6
+ # in/out.
7
+ MARGIN_CALL_DEFAULT_PROTOCOLS = frozenset({"maple"})
8
+
9
+ # Aave-v3 / Sparklend dual close-factor regime: hf < HF_FULL_CLOSE → liquidate 100%
10
+ # of debt; otherwise → liquidate 50% (the standard aave-v3 close factor).
11
+ AAVE_LIKE_PROTOCOLS = frozenset({"aave_v3", "sparklend"})
12
+ HF_FULL_CLOSE = 0.95
13
+ CLOSE_FACTOR_FULL = 1.0
14
+ CLOSE_FACTOR_PARTIAL = 0.5
15
+
16
+ # CRR_adj penalty steepness for the HHI concentration surcharge:
17
+ # crr_adj = crr_el * (1 + CRR_HHI_K * hhi)
18
+ CRR_HHI_K = Decimal("1.0")
19
+
20
+ # Hardcoded policy minimum CRR carried by every market, persisted as `crr_floor`.
21
+ # Stored alongside the computed CRR values, never applied to them.
22
+ CRR_FLOOR = Decimal("0.02")
23
+
24
+ # Slippage cap — a forced sale recovers at least (1 - MAX_SLIPPAGE) of the
25
+ # collateral's value at the simulated price, even when the price has fallen
26
+ # below the snapshot book or the book is exhausted. Floors recovery at 50%.
27
+ MAX_SLIPPAGE = 0.50
28
+
29
+ # Retention for the rolling intra-day `*Snapshot24` CRR tables, pruned once at
30
+ # the start of each run. Matches the orderbook SNAPSHOT24_RETENTION_DAYS.
31
+ MARKET_CRR_SNAPSHOT24_RETENTION_DAYS = 2
32
+
33
+ # Lower bound used when normalising into ratios — prevents div-by-zero without
34
+ # materially perturbing the result.
35
+ EPS = 1e-12