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.
- balabs_risk_kernel-0.1.1/.gitignore +5 -0
- balabs_risk_kernel-0.1.1/PKG-INFO +71 -0
- balabs_risk_kernel-0.1.1/README.md +62 -0
- balabs_risk_kernel-0.1.1/pyproject.toml +71 -0
- balabs_risk_kernel-0.1.1/src/risk_kernel/__init__.py +1 -0
- balabs_risk_kernel-0.1.1/src/risk_kernel/constants.py +8 -0
- balabs_risk_kernel-0.1.1/src/risk_kernel/liquidator/__init__.py +0 -0
- balabs_risk_kernel-0.1.1/src/risk_kernel/liquidator/constants.py +35 -0
- balabs_risk_kernel-0.1.1/src/risk_kernel/liquidator/pipeline/__init__.py +0 -0
- balabs_risk_kernel-0.1.1/src/risk_kernel/liquidator/pipeline/liquidation_simulation.py +1270 -0
- balabs_risk_kernel-0.1.1/src/risk_kernel/liquidator/pipeline/liquidation_simulation_fast.py +590 -0
- balabs_risk_kernel-0.1.1/src/risk_kernel/liquidator/pipeline/processors/__init__.py +0 -0
- balabs_risk_kernel-0.1.1/src/risk_kernel/liquidator/pipeline/processors/liquidator.py +718 -0
- balabs_risk_kernel-0.1.1/src/risk_kernel/liquidator/pipeline/scenario_paths.py +133 -0
- balabs_risk_kernel-0.1.1/src/risk_kernel/liquidator/types.py +208 -0
|
@@ -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"
|
|
File without changes
|
|
@@ -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
|
|
File without changes
|