crucible-stack
A framework for defining, searching, sizing and deploying trading strategies.
It contains no strategies, and that is the point.
crucible answers one question: is this edge real,
or did I find it by looking hard enough? crucible-stack is the machinery around that
verdict, the parts every systematic strategy needs and nobody wants to write twice:
| Package | What it does | Seam |
|---|---|---|
framework |
how you define a strategy: the RulesStrategy interface, the params/config schema, the strategy registry, the Monte Carlo engine |
n/a |
engine |
the rules simulator and a pluggable exit/stop registry | n/a |
optimize |
how you search a parameter space honestly: the trial matrix, the sweep, and a selection step that prices in how many variants you actually tried | 1 |
capital |
how you size an edge into an account: R-multiples to a currency equity curve, with bootstrap bands | 3 |
orchestrate |
how you deploy it: a gate, a drift monitor, a ledger, and triggers that make re-optimization a standing process rather than a memory | 4 |
Why the strategies are missing
The split is deliberate. A strategy is somebody's edge and may be worth keeping private. The framework around it is not an edge, it is plumbing, and plumbing kept private is just plumbing you maintain alone.
So every place a strategy would go is a registry that ships empty:
from crucible_stack.framework import register_strategy, RulesStrategy
from crucible_stack.engine.exits import register_exit, ExitRule
@register_strategy("my_gold_trend") # lives in YOUR repo, public or not
class GoldTrend(RulesStrategy):
...
crucible-stack never imports your code. Your code imports it. That direction is enforced
by a test (tests/test_boundaries.py), not by good intentions, and the test is
mutation-checked so that it fails when the boundary actually breaks.
The idea worth stealing
Most backtesting stacks stop at a backtest. This one is shaped around two ideas that are easy to state and are usually skipped:
1. The search is part of the result. If you try 400 variants and report the best one's
Sharpe, you have reported the maximum of 400 draws, not an edge. optimize keeps a
SearchSpaceLog of how many variants were genuinely tried and feeds that count into the
correction (deflated Sharpe, PBO, White's Reality Check, Hansen's SPA). The honest
denominator is the whole point, and it is the number everybody rounds down.
2. A deployed strategy is not a finished one. orchestrate treats deployment as a loop
that has to keep re-earning its place: a gate that fails closed (no verdict, no
promotion), a drift monitor that compares the live book against the envelope frozen at
promotion rather than one recomputed today, and a ledger that remembers what was promoted
and when. See ADR-0003 for why each of those is shaped the way it is, and ADR-0004 for why
this repo exists at all.
Install
pip install -e . # requires Python 3.11+, and crucible >= 0.3.0
pytest -q
If you install this editable, read this first
The natural way to work on a strategy is to install both this package and your own
repo editable, side by side. That is a good setup and it has one property worth
stating plainly, because it causes bugs that look like anything but their cause: an
editable install is the working tree. There is no copy. import crucible_stack
reads the checkout directly, in whatever state it is in at that moment.
Three consequences:
A git operation here changes your strategy's behaviour, with no change to your
strategy. Switch branches, stash, or rebase in this repo and your next import
picks it up. A test that passes, then fails against an untouched strategy tree, is
usually this rather than a flake.
Version metadata is written at install time and never refreshed. pip list will
report whatever pyproject.toml said when you installed, not what the code is now. A
constraint like crucible-stack>=0.1.0 is satisfied by a checkout that could be
anywhere from that release to unreleased main. Do not read a version pin as evidence
that an API is present. Check the signature, or write a test that does. This package
does exactly that for its own dependency in tests/test_crucible_compat.py, because
the crucible API it needs shipped after the tagged release it nominally requires.
Do not declare a dependency by URL to work around a stale release. It is tempting
to pin crucible-stack @ git+https://... when you need something newer than the last
tag. It breaks any consumer that installs the same package from a local editable
checkout (pip cannot reconcile a URL requirement with a local one) and it blocks PyPI
upload. Pin normally and enforce the API with a test.
Status
Early. Extracted from a working private strategy repo rather than designed in the abstract, which shows in both directions: the seams are load-bearing and have been used in anger, and the naming still carries some of its origin.
While 0.x, breaking changes may land in a minor release, but never silently, and
removals go through deprecation. What counts as public, what is deliberately excluded, and
what changes at 1.0 are all in docs/api-stability.md. The surface
it describes is pinned by tests/test_public_api.py, so the policy is checked rather than
promised.
Metadata
Release files for crucible-stack 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| crucible_stack-0.2.0.tar.gz | 100.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| crucible_stack-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 172.4 kB
Release files / crucible_stack-0.2.0.tar.gz
| Download URL | crucible_stack-0.2.0.tar.gz |
|---|---|
| Size | 100.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2035464e022d4be6fce56b6a545555d77425a26fd257fb9cdf15e723a73533de
|
|
BLAKE2b-256 checksum How to use checksums |
2a72f92fbe10cdd04704a07a2a390cd9dec5153fb99ea4bf08b7907bcd1f87b3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logRelease files / crucible_stack-0.2.0-py3-none-any.whl
| Download URL | crucible_stack-0.2.0-py3-none-any.whl |
|---|---|
| Size | 72.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
39d2939018f75ad42be15d2457ebc9dc77cb21cab4ee7be5f2ee197c60bb2749
|
|
BLAKE2b-256 checksum How to use checksums |
c2baaaee4dcd84b9bba8da8cc29963fa310fca97686f64ba7b911931e10352e8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logSecurity for crucible-stack 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for crucible_stack-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.