~/workgambitcase study 03 / 03

Gambit

Fund factsheet · Hamdan Range · 03

Objective

Spec-first autonomous trading system. Research note, then a strategy document with ten named invariants, then code. Circuit breakers, mainnet guards, crash-window order reconciliation. Paper-mode only, and the promotion gate is written into the spec.

Key information

StatusPaper-mode
RoleSole author
Tests passing733
Named invariants10

Top holdings

Rough share of the work; read it as a sketch.

Python70%
pytest suites15%
Exchange APIs10%
Specs / decision log5%
733
tests
~29.6k
loc
3
circuit breakers
10
invariants
30
adrs, binbot

Problem

Software that can lose money while you sleep

An autonomous trading system is a program with a wallet and no supervision. The interesting engineering problem sits under the strategy: every ordinary software failure (a crash mid-order, a duplicate request, a network timeout at the wrong moment) turns into a financial one.

Gambit is my attempt to build that carefully rather than quickly. It runs in paper-mode only. The gate that would promote it to real money is written into the spec and it has not been met, and I'd rather say that here than have it come up in an interview.

Constraints

Rules I set before writing code

  • No code before the spec. A research note, then a strategy document, then implementation.
  • Every rule the system must never break gets a name, so it can be referred to in a test and in a code review.
  • Assume the process dies at the worst possible moment, which is between sending an order and recording that it was sent.
  • Real money is off by default and stays off until a written condition is met.

Decision 01

Ten invariants with names

The strategy document lists ten invariants: statements that must hold no matter what the market does or what fails. Naming them changes how the code reads. A test isn't called test_order_flow_3, it's named after the rule it defends, and when one fails you know which rule broke rather than which line threw.

Next to it there's a decision log. Every consequential choice gets an entry with the reasoning at the time. It's dull to maintain, and it's the first thing I read when I come back to the project after a month away.

Decision 02

Three circuit breakers and a hard stop

The system stops itself on a daily loss limit, on a losing streak, and on drawdown from peak. Each is a separate breaker with its own threshold, because they catch different failures: a bad day, a broken signal, and a slow bleed that no single day would flag.

Underneath those, mainnet guards. Live trading requires explicit configuration that defaults to off, and the code refuses to run against real funds unless that's set on purpose. It's the least clever code in the project and probably the most important.

Decision 03

What happens if it dies mid-order

The failure I designed around: the process sends an order, then crashes before it records having done so. On restart, in-memory state says there is no position and the exchange says there is one.

So every restart begins with a reconciliation. The system reads its own state, reads the exchange, and resolves the difference before it's allowed to do anything else. That's one of the ten invariants, and it has a test that kills the process inside the window on purpose.

Predecessor

binbot, retired

Gambit is the second attempt. The first, binbot, ran to 30 architecture decision records and 446 tests, handled exchange-side OCO orders with a software fallback for venue error −4120, and published its negative results rather than quietly deleting them. I killed it and started again because the design had a shape I couldn't test properly.

Results

Where it stands

  • 733 passing tests across roughly 29,600 lines of Python.
  • Ten named invariants, each with tests that try to violate it.
  • Three circuit breakers, mainnet guards, crash-window order reconciliation.
  • Paper-mode only. The promotion gate is defined and has not been met. No live trading results exist, so there are none on this page.
  • The repository is private. The spec, the invariant list and the test summary are available on request.

Honestly

What I'd do differently

I wrote the risk layer after the execution layer. It works, and the breakers sit where they need to, but a few of them read like something bolted onto the outside of the system rather than part of its structure. Built second, they look optional in the code, and risk limits are the last thing that should look optional.

The other thing is scope. 733 tests on a system that has never traded real money is only a reasonable use of time if the promotion gate eventually gets met. As it stands it's a very well tested demonstration, and I'd rather have a small system that had passed its own gate.

If this is the kind of work your team needs, email me. I answer everything.