When to Use
Invoke this skill when a strategy is asking to move one step closer to live capital, and someone has to say yes or no on the record. Strategies promoted straight out of a Jupyter notebook fail for reasons the notebook cannot show: the backtest was tuned on the same data it was scored on, the deployed commit was not the tested commit, the fills the simulator assumed never materialise, or nobody outside the author's own head ever reviewed it.
The engine evaluates one transition at a time against a fixed gate set:
RESEARCH_BACKTEST → INDEPENDENT_VALIDATION → PAPER_TRADING_SHADOW → STAGING_CANARY → LIVE_PRODUCTION
and appends every decision — approvals and refusals — to a hash-chained ledger that a later reader can verify.
Gates by target stage:
| Target stage | Gates evaluated |
|---|---|
INDEPENDENT_VALIDATION |
sequencing, reproducibility, Sharpe, drawdown |
PAPER_TRADING_SHADOW |
+ independent validator recorded (≠ author) |
STAGING_CANARY |
+ paper-trading duration, shadow divergence |
LIVE_PRODUCTION |
+ designated-person sign-off |
When NOT to Use
- As proof that a strategy is any good. Every artifact is a number the caller asserts. The engine cannot tell an honest out-of-sample Sharpe from an in-sample one, and cannot detect look-ahead bias. Passing means "the paperwork is in order and the claimed metrics clear the bar", never "the edge is real." Pair with
lookahead-bias-elimination,walk-forward-validation-setup, andmulti-year-regime-coverage-requirement. - As the record of which stage a strategy is actually in. The engine is stateless about strategy identity: it checks that the requested transition is a single forward step, not that the earlier stages truly completed. Your pipeline's stage store remains the source of truth.
- As the rollback or shutdown path. Backward and same-stage transitions are refused by design. Pulling a live strategy is
strategy-decommissioning-and-position-unwind-procedure; halting one mid-session iskill-switch-and-drawdown-circuit-breakers. - As RTS 6 Art. 8 deployment limits. Art. 8 requires predefined limits on instruments traded, order price/value/count, strategy positions, and venue count before deployment. This engine gates the decision and holds none of those limits — enforce them in the execution layer.
- As a supervisor-proof immutable ledger on its own. The hash chain detects an edit or deletion made without recomputing the chain. Anyone who can rewrite the whole ledger can recompute every downstream digest. Anchor
audit_trail_hashin storage the strategy owner cannot rewrite — seeaudit-logging-for-configuration-changes. - Where the numbers are the point. The four thresholds are house defaults, not standards. See
references/standards.mdbefore quoting any of them externally.
Prerequisites
StagePromotionArtifactsfor the transition:git_commit_hash(7–64 hex characters, non-zero),dataset_checksum(non-blank),backtest_sharpe(finite),backtest_max_drawdown_pct(positive magnitude in [0, 100] — a 12% drawdown is12.0, never-12.0),shadow_tracking_error_pct(non-negative),paper_trading_days(non-negative int),has_risk_committee_signoff(a realbool),author_id,validator_id.- A settled, documented definition of
shadow_tracking_error_pct. Canonically, tracking error is the annualized standard deviation of active returns; what this gate compares is a divergence between shadow fills and simulated fills. An annualized standard deviation of return differences and a mean absolute per-fill price divergence are different quantities and5.0means something very different under each. Fix one definition, apply it to every strategy you compare. - Thresholds you are prepared to defend in writing. The defaults (Sharpe ≥ 1.50, drawdown ≤ 15%, divergence ≤ 5%, ≥ 14 paper days) are heuristics with no regulatory basis.
- An identity scheme where
author_idandvalidator_idare distinct people. The engine enforces that the strings differ; it cannot authenticate that either person exists or holds the designated authority.
Workflow
-
Stage Sequencing Gate — evaluated first, and independently of the metrics.
- Reject unless the transition advances exactly one position in the pipeline order.
- Decision point — a stellar backtest does not buy a shortcut.
RESEARCH_BACKTEST → LIVE_PRODUCTIONfails on sequencing alone with a Sharpe of 4.0, and the failure message names each stage that was bypassed. Skipping stages is the failure mode this engine exists to prevent; if it can be argued away with good metrics it prevents nothing. - Decision point — a refusal still evaluates every other gate. A sequencing failure does not short-circuit the rest. The submitter gets one complete list of what is wrong, not a one-at-a-time drip of rejections across four resubmissions.
-
Reproducibility Gate — verify the commit and dataset are actually pinned.
- Decision point — a plausible-looking string is not a commit id. Validate hexadecimal, length 7–64, and reject an all-zero digest.
"notahash"and"0000000"are precisely what a CI job emits when it cannot resolve a revision, and a length check alone waves both through.
- Decision point — a plausible-looking string is not a commit id. Validate hexadecimal, length 7–64, and reject an all-zero digest.
-
Backtest Quantitative Gates — Sharpe floor and drawdown cap.
- Decision point — enforce the drawdown sign convention, do not assume it.
-40.0satisfiesvalue <= 15.0. Reject any negative drawdown at input rather than certifying the worst backtests in the book. - Decision point — non-finite metrics raise, they do not fail.
NaNcomparesFalseagainst every threshold, so a corrupt metric passes or fails depending only on which way the comparison happens to run. A malformed submission is a process error, distinct from a strategy that was evaluated and refused; the ledger must not blur the two.
- Decision point — enforce the drawdown sign convention, do not assume it.
-
Independence Gate — applies from
PAPER_TRADING_SHADOWonward.- Require a
validator_idthat is non-blank and differs fromauthor_idafter trimming. - Decision point — this gate is what makes
INDEPENDENT_VALIDATIONmean anything. Without it, promoting out of the independent-validation stage requires no validator at all, and the stage is a label on a diagram rather than a control.
- Require a
-
Shadow Execution Evidence Gates — entry to
STAGING_CANARYorLIVE_PRODUCTION.- Require paper-trading duration ≥ minimum and shadow divergence ≤ cap.
- Decision point — earlier stages are exempt on purpose. A strategy entering
INDEPENDENT_VALIDATIONhas no paper-trading history yet; demanding 14 days there makes the gate unsatisfiable and teaches submitters to fabricate the field.
-
Designated-Person Sign-Off Gate — entry to
LIVE_PRODUCTIONonly.- Require both the sign-off flag and a named approver. RTS 6 Art. 5(2) requires that "a person designated by the senior management of the investment firm shall authorise the deployment" — the obligation is a named person, so a boolean with nobody's name attached does not discharge it.
-
Audit Record and Ledger — record the decision so it can be checked later.
- Record an explicit, timezone-aware
decided_at_utc; hash the entire decision (both stages, every artifact, every configured threshold, the gate outcomes, the timestamp, and the previous entry's digest) into a full 64-character SHA-256; chain it to the preceding entry. - Decision point — bind the thresholds, not just the artifacts. Otherwise the same artifacts judged against a quietly loosened Sharpe floor produce an indistinguishable record, and the loosening is the thing an auditor is looking for.
- Decision point — record refusals too. A trail containing only approvals cannot demonstrate that anything was ever refused, which is the entire evidentiary value of a gate.
- Record an explicit, timezone-aware
Full procedure: see
references/workflows.md. Standards reference: seereferences/standards.md. Printable pre-flight checklist: seeassets/checklist.md.
Common Pitfalls
- Documenting sequential gatekeeping without implementing it: the pipeline diagram says five stages; the code checks the artifacts and approves whatever transition it is handed.
RESEARCH_BACKTEST → LIVE_PRODUCTIONthen passes with good numbers, skipping independent validation, shadow trading and canary in one hop — the exact deployment this skill exists to block. - Accepting a negatively-signed drawdown: a 40% drawdown submitted as
-40.0satisfies<= 15.0. The gate approves the worst backtest in the book and reportsDRAWDOWN_GATEas passed. - Letting the author be the validator:
author_id == validator_idis self-certification. The stage is called independent validation and the sign-off obligation names a designated person; a string comparison is the cheapest control that makes either true. - An audit hash nobody can recompute: seeding a digest with an unrecorded
time.time()produces a value that looks cryptographic and proves nothing — no auditor can reproduce it. Worse, on a platform with ~15 ms clock resolution two distinct decisions in the same tick collide to one digest, so two different promotions appear in the ledger as the same event. - An audit hash that omits the evidence: hashing only the strategy id, stage names, commit hash and approval boolean leaves the Sharpe ratio, the tracking error, the paper-trading days and the validator's name unprotected. Every number that justified the approval can be edited afterwards without disturbing the digest.
- A status code with the failure count baked in: emitting
"REJECTED_GATES_FAILED (3)"means no caller can match on the string, and any documented constant likeREJECTED_LOW_SHARPEis never actually produced. Branch on a stable enum; readfailed_gatesfor the detail. - A truthy non-boolean sign-off:
has_risk_committee_signoff = "pending"is truthy in Python and grants live deployment approval. Validate the type, not just the value. - Naive timestamps in a promotion record: "approved at 09:30" without an offset cannot be reconciled against exchange session times or another jurisdiction's records, and is worst around DST transitions — exactly when it matters.
- Quoting the thresholds as industry standards: no regulator publishes a minimum backtest Sharpe, a maximum shadow divergence, or a minimum paper-trading duration. ESMA states the "scope, frequency, and intensity of testing vary significantly across the industry" and recognises "the need for proportionality." A number presented to a supervisor as a standard is a claim you will be asked to source.
- Treating a passing audit as evidence the strategy works: every artifact is asserted by the submitter. The engine validates paperwork, not edge.
- Forgetting that changing a threshold is itself a material change: under the ESMA briefing's retesting triggers, changing risk-control thresholds warrants re-testing. Loosening the Sharpe floor to get a strategy through is a governance event, not a config tweak.
Verification
- Walk the full pipeline one stage at a time with a passing bundle (Sharpe 1.82, drawdown 11.4%, divergence 3.1%, 18 paper days, distinct author/validator, sign-off present) and confirm all four transitions approve, with gate counts rising 4 → 5 → 7 → 8 as the later gate sets engage.
- Submit
RESEARCH_BACKTEST → LIVE_PRODUCTIONwith the same passing bundle ⟹is_approvedisFalse,STAGE_SEQUENCE_GATEfails, and the message names all three skipped stages. Repeat with a backward (LIVE_PRODUCTION → RESEARCH_BACKTEST) and a same-stage transition ⟹ both refused. - Boundary checks, each pair passing then failing: Sharpe
1.50/1.4999; drawdown15.0/15.0001; divergence5.0/5.0001; paper days14/13. A drawdown of15.004renders as15.0%in the message and must still fail. - Set
author_id == validator_id(including with whitespace padding) ⟹INDEPENDENCE_GATEfails. Promote out ofINDEPENDENT_VALIDATIONwith a blankvalidator_id⟹ refused. - Reproducibility:
"notahash","0000000", a 6-character hash and a 65-character hash are all refused; a 7-character, a 40-character and an uppercase hex hash pass; a whitespace-onlydataset_checksumis refused. - Negative checks that must raise
ValueError: a negative or >100 drawdown, a negative divergence,NaN/infin any metric, negative or non-integer paper days,has_risk_committee_signoff="pending", a blankauthor_idorstrategy_id, a stage passed as a plain string, and a naive or malformeddecided_at_utc. Constructor: a drawdown cap of0.0or1000.0, a negative divergence cap, negative or non-integer minimum paper days. - Audit integrity: the hash is 64 characters and
verify_audit_hashreturnsTrue; a second engine given identical inputs and the same timestamp produces an identical digest; altering any of the Sharpe, divergence, paper days, sign-off flag, validator id, dataset checksum, recorded outcome, or the thresholds makes verification returnFalse; two distinct decisions never share a digest. - Ledger integrity: entry 0 chains from
GENESIS_HASH, indices are contiguous, refusals are recorded alongside approvals, andverify_ledgerreturnsFalseafter an entry is edited, deleted, or reordered. - Run
python -m unittest discover -s skills/strategy-research-to-production-pipeline-governance/scriptsand confirm 100% pass.
Related Skills
strategy-committee-governance-for-capital-allocation-decisionsnew-strategy-onboarding-checklistpaper-to-live-promotion-checklistcanary-releases-for-strategy-code-changesbacktest-determinism-and-reproducibilityresearch-environment-vs-production-environment-parityaudit-logging-for-configuration-changesrisk-control-configuration-change-approval-workflowstrategy-decommissioning-and-position-unwind-proceduremodel-versioning-and-rollback