keel v0.5.7
Built from 640c496. Version binds to this hash:
keel --version reports keel 0.5.7+640c4961a411 [release].
Install
Download all wheels from this release into one directory, then install the
keel_trader wheel by path:
pip install --find-links . ./keel_trader-0.5.7-py3-none-any.whl
keel --version
keel-trader; the name
keel on PyPI belongs to an unrelated project, so pip install keel fetches
someone else's package. A build reporting DIRTY or [checkout] is not this
release and must not be run against live funds.
Configure
config.yaml is attached to this release: the production config, in
auto_trade.mode: confirm — keel previews every order and waits for your
approval. Drop it beside the install (or run keel init-config --live), put
your CDP key in a git-ignored .env, then:
keel migrate # existing database: apply schema migrations
keel init # fresh deployment: write config + seed candidate rules
Seeded rules start as candidate and trade nothing until you promote them.
Other changes
fix(assets): lower the discovery floor to 1M and pin it to the admission floor (#190)
The problem
assets discover's 24h-volume pre-filter was 5,000,000 — five times the liquidity floor the admission gate actually applies (ScreenPolicy.min_median_daily_volume = 1,000,000). Discovery was stricter than the criterion it screens for, so it was hiding assets the gate would have accepted.
Measured, not assumed
On a live sweep (2026-08-08, deployment on v0.5.6):
| floor | candidates | unsettled survivors |
|---|---|---|
| 5,000,000 (old) | 9 | 1 (ZEC) |
| 1,000,000 (new) | 38 | ZEC, DOGE, FET + 6 more to triage |
Seven assets clear both mechanical gates — 4-year history and the real liquidity criterion — that the old floor never surfaced: FET, AVAX, ICP, ALGO, UNI, CRV, DOT. Each passes assets screen with attestation as its only rejection.
Two cases make the point:
- FET — $2.94M/24h, invisible to the sweep, while measuring 4.8× the admission floor. It also ranks second of twelve on marginal independence (0.096 vs the book's own internal 0.175), so the old floor was hiding the best new candidate available.
- DOGE — $3.95M/24h, so it has never appeared in a default sweep, despite being ~30× the admission floor.
The floor, not the market, was the binding constraint on the candidate pipeline.
Why 1,000,000 specifically
It is not a fresh guess — it is ScreenPolicy.min_median_daily_volume. Setting them equal makes the pre-filter exactly as permissive as the gate, which is the most it can be without proposing assets that cannot pass.
The two remain different statistics — a 24h snapshot vs a median over history — which is what --probe-liquidity (#188) exists to reconcile. This pins the numbers, not the methods.
The drift bug found on the way
Three modules carried this default: cli.assets_discover's option, admission.DEFAULT_MIN_QUOTE_24H_VOLUME, and screen.DiscoveryPolicy. Only the first two were pinned to each other — so a caller constructing DiscoveryPolicy directly, which assets_discover itself does, could have drifted from build_discover_report silently. Now all three are pinned, plus a fourth pin to the admission floor.
Scope
No behaviour change to the gate — same criterion, same floor, same verdicts. Only how many candidates a sweep surfaces for a human to consider. TDD: existing pin flipped and watched fail (5000000 != 1000000) before any source change. 2139 passed (+2), ruff and mypy clean across 203 files.
chore: bump to 0.5.7 for the lowered discovery floor (#191)
Bumps pyproject.toml and all four workspace members 0.5.6 → 0.5.7, plus uv.lock. Same shape as #189 and #184.
Why now
#190 lowered the assets discover 24h pre-filter from 5,000,000 to 1,000,000 and pinned it to ScreenPolicy.min_median_daily_volume. The deployment runs 0.5.6+9d7dedeb5b64 [release], so sweeps from ~/keel still use the 5M floor: 9 candidates instead of 38, with FET ($2.94M/24h but 4.8× the admission floor, and 2nd of twelve on marginal independence) and DOGE ($3.95M/24h but ~30× the admission floor) both invisible.
What 0.5.7 contains
Only #190 — the discovery floor change:
- Default
--min-volume-24h5,000,000 → 1,000,000, set equal to the admission liquidity floor so a sweep can never be stricter than the gate it feeds. - Three modules carried this default (
cli.assets_discover's option,admission.DEFAULT_MIN_QUOTE_24H_VOLUME,screen.DiscoveryPolicy) and only two were pinned to each other — so a caller constructingDiscoveryPolicydirectly, whichassets_discoverdoes, could drift frombuild_discover_reportsilently. All three are now pinned, plus a fourth pin to the admission floor.
No behaviour change to any gate, rail, rule or order path. The live agent behaves identically on 0.5.6 and 0.5.7; this only changes how many candidates a scout sweep surfaces for a human to read.
Verification
2139 passed, ruff clean, mypy clean across 203 source fileskeel --version→0.5.7+7fa71e404b22on this branch