BANGER
Product status: Banger’s public beta is paper-only. References to live execution are future-looking. Venue rules and legal claims can change; verify current primary sources for your jurisdiction.
2026-10-22 · 6 min read · facts as of 2026-10-22

Reproduce a Paper Strategy Failure With a Small Fixture

A paper strategy died on tick 14,203 with a KeyError, or it sized a position to nonsense, or it threw on a market that had no ask. You want to fix it. What you do not want is to redeploy, wait for live data to drift back into the same shape, and hope the bug fires again. That is slow, non-deterministic, and it burns a hosted run for every guess.

The faster path is the one every test suite already uses: capture the exact input that broke, pin the exact code that processed it, and replay both offline until the failure is deterministic. In testing terms you are building a fixture. According to the pytest documentation, a fixture provides a defined, reliable and consistent context for the tests.

This post is about doing that for a prediction-market strategy callback. No credentials, no new hosted runs, no orders. Just a frozen input, a frozen version, and a local repro.

Why a fixture, and not another live run

A live rerun changes three things at once: the market data, the fill model, and your code if you edited it. When all three move, you cannot attribute the failure to any one of them. A fixture freezes the first two so you can isolate the third.

This is the retest-then-regression discipline. The reproduction test is expected to fail on the old code and pass on the fixed code, a fail-before, pass-after check. Once it passes, it joins your regression suite and keeps running on later changes so the same bug cannot silently return. The verification is only complete when the bug report names the fix commit and links the runs.

Concretely, a good repro gives you: deterministic failure on demand, a diff-able unit you can attach to an issue, and a guard that survives refactors.

Pin the exact version first

A fixture is worthless if it runs against a moving target. Pin the strategy SDK before anything else. The package on PyPI is bangertrades, and you should install an exact release rather than whatever is latest:

pip install bangertrades==0.1.7

Record that version string in the issue and in the test file itself. If your repro passes on 0.1.7 but the deployment ran a different build, you have reproduced a different program. Reverify the pinned version against the package page before you trust a result, because the contract can change between releases.

Pin your strategy code the same way: the exact file, at the exact commit, that produced the failure. Reproducing against your current working copy, with uncommitted edits, is a common way to chase a ghost.

Capture a sanitized input

The strategy entry point you are reproducing is the per-tick callback. In 0.1.7 the signature is on_market_tick(self, market, tick, ctx), with an optional on_start(ctx) for setup. Your fixture needs to recreate the arguments that version of the callback saw when it failed.

The tick is the payload to capture carefully, because its field types are where calculation bugs hide:

Sanitize, do not mutate. Strip anything account-identifying or secret from the captured record, but do not round prices, fill in a missing ask with a guess, or normalize a type. The whole point is that the bug lived in the exact shape of the input. If you change the shape, you are testing a different input.

Capture the exact market ticker too, and write it down as a literal. Do not rebuild the fixture by taking the first result off a discovery call and assuming it is the same market. The first discovery result drifts; a hard-coded ticker does not.

Build the offline repro

Now instantiate your strategy and call the callback directly with the reconstructed arguments. This runs entirely in-process. It touches no venue, needs no keys, and creates no paper record. It is a plain function call wrapped in a test.

Structure it as a fail-before, pass-after test. Assert the behavior you actually want: that a Decimal comparison lands correctly, that a missing ask routes to your fallback branch instead of raising, that your size calculation returns what you expect. Run it against the buggy code and confirm it fails for the right reason. Then fix the code and confirm the same test passes. Keep the fixture file checked in next to the test so the repro is self-contained and shareable.

If part of your logic depends on an SDK interface whose exact contract you cannot verify, do not guess at it inside the repro. Isolate and test the pure calculation you can verify, and leave the uncertain integration boundary out of the fixture rather than inventing a method signature that was never shipped.

A passing fixture is not an execution result

When the fixture goes green, be precise about what you proved. You proved that a specific version of your callback handles one specific captured input the way you expect. That is a unit result. It is not evidence about fills, fees, queue position, or venue behavior.

Keep these three things separate in your head and in your write-up:

Banger's forward-paper simulator makes modeling choices you should not confuse with reality. It can fill a non-crossing resting limit at that limit and logs paper.fill.resting-assumed when it does. Its volume cap is drawn from reported volume, not full book depth or queue reconstruction. Its standard Kalshi fee helper rounds up to a whole cent, which is not identical to the finer rounding in the venue's current fee documentation. A fixture that reproduces a calculation bug says nothing about any of these. If your failure was in the simulated fill or fee math, inspect the actual paper result model instead of asserting a number your fixture never touched.

The workflow in one pass

The reason to do it this way is leverage. One captured tick plus one pinned version turns a flaky, run-burning bug into a five-second local test you can run on every change. That is cheaper than a redeploy, and far more honest about what it proves.

Sources

Keep reading

Run your first strategy free

Paper-trade on Polymarket and Kalshi market data without venue keys.

Start free