← The essay Seven orders, six refusals Open in a tab ↗
Reports · Teardowns · September 2026

Seven orders,
six refusals.

I spent an afternoon trying to make Vibe‑Trading misbehave. I widened permissions at the commit step, replayed authorisations, corrupted the kill switch, edited the audit log. Seven orders went in. Six came back refused, and each refusal named the rule it was enforcing.

The refusal I keep thinking about happened at the commit step. I had a permission file with a fifty‑dollar order cap and tried to raise it to five thousand on its way to disk. The system refused and named its reason: widening a permission must go through a fresh proposal.

You can narrow a permission at commit time. You cannot loosen one. Most evaluations of trading agents ask how smart the model is. The engineering below assumes the model will at some point be wrong, confused, or compromised, and builds for that day.

The walkthrough

Every live order runs a fixed series of checks, in a fixed order, and they fail closed.

The picture from the top of the page, one check at a time. Seven orders are queued: one ordinary, six built to break something.

Check 1plain2widen3replay 4garble5kill6log7over
passed refused here, rule named committed to broker
The queue

Seven orders, one afternoon

Order 1 is ordinary: a forty‑dollar buy, inside every limit. The other six each attack a different organ of the safety layer.

The finished picture sits faintly behind this card. Scroll, and it fills in one check at a time.

Check 1

Is there a mandate, and is it still alive?

Before the agent can touch a live account you write a permission file the project calls a mandate: biggest allowed order, biggest total exposure, leverage, trades per day, which markets and instrument types, minimum liquidity and company size, and symbols never to touch.

The agent can propose a mandate. Only a function its loop cannot reach can commit one. And the committed file expires after thirty days by default.

“expires_at: … after which the mandate is dead and the gate fail‑closes until the user re‑authorizes. Default lifetime 30 days from created_at (configurable per commit).”

agent/src/live/mandate/model.py2

Check 2 · Order 5 stops here

The kill switch is a file on disk

Not a flag in memory, not a model decision. A file. It halts everything even when the model is stuck, and it halts everything when the file’s own contents are corrupted, because a kill switch that cannot be read is treated as a kill switch that is on.

I corrupted it. Order 5 never reached a broker.

“enforced at the filesystem layer, independent of the LLM cooperating … the file’s existence is the halt.”

agent/src/live/halt.py2

Check 3 · Order 6 stops here

The log notices when you edit it

Decisions land in an append‑only, hash‑chained journal. I edited one entry. It detected the edit, and then it refused to write anything further on top of the broken chain.

A tamper‑evident log that keeps accepting writes is a diary. This one stops.

“editing or deleting ANY earlier record breaks the hash of every record chained after it.”

agent/src/governance/ledger.py2

Check 4 · Order 3 stops here

An authorisation is good exactly once

I presented the same authorisation twice. The second one was refused. Replay is the attack an agent is most likely to perform by accident, halfway through a retry it should not have attempted.

Check 5 · Order 4 stops here

If exposure cannot be read, nothing goes through

I fed the checks a positions payload they could not parse. The order was refused rather than waved through on an assumed zero exposure.

This is the whole design in one behaviour. When the system is confused, the answer is no. Every one of those refusals costs an outage when a data feed hiccups. Somebody accepted that cost on purpose.

Check 6 · Order 7 stops here

The mandate’s own arithmetic

Order size against the cap, new exposure against the ceiling, leverage, trades already used today, the market and instrument type, minimum liquidity and company size, and the never‑touch list.

A fifty‑dollar cap bounds the damage of any single mistake at fifty dollars. Whether the strategy inside the cap makes money is a different question the cap cannot answer.

Check 7 · Order 2 stops here

You can narrow a permission. You cannot loosen one.

This one is not really about the order. It is about the file the order cites. My fifty‑dollar cap, raised to five thousand on its way to disk, was refused at the moment the mandate was written, so the mandate was never committed and every order citing it has nothing to stand on.

My favourite artifact in the whole repo is a test asserting that the agent has no reachable function that could widen its own permissions. It walks the syntax tree of everything the agent can reach and fails if any of it can open the mandate store for writing. Most test suites check what the code does. This one checks what the code must never become able to do.

“Structural guarantee: nothing the agent can reach writes the mandate store.”

agent/tests/test_no_set_mandate_tool.py2

Check 8 · Order 1 commits

One order out of seven reached a broker

The ordinary one. Nothing retries, so a timeout leaves you unsure whether it arrived, and a separate reconciliation step gets read‑only broker access, structurally, so it cannot resend an order while working out what happened.

Six refusals, each naming its rule. That is the finished picture.

The bench

Now you try.

The same eight checks, running in your browser. Write the mandate, build an order, sabotage the machine if you like, and send it. Load one of my seven, or invent a worse one.

1 · The mandate

The permission file. An agent may propose one. Only a function outside its loop may commit one.

Markets allowed
Never touch
The file itself
A committed mandate expires after thirty days by default. An expired file is not a permissive one.

2 · The order

What you are asking the agent to send to a live account.

What you did to the machine
Each of these is one of the afternoon’s probes. Turn several on at once and the earliest check in the series is the one that answers.
0sent
0refused
0committed

3 · The answer

A refusal always names the rule. That is the part worth copying.

No order sent yet

Waiting

Build an order, or load one of the seven above, then send it.

    A reconstruction of the check series described in the teardown, running on your device. No account, no keys, nothing leaves this page. The eight checks and their order are ours: the article names the probes and the refusals, not a canonical sequence.1

    Finding 1 · Anatomy

    The part that decides is the smallest part of the repo.

    Vibe‑Trading is an open‑source finance research agent from the HKUDS lab at the University of Hong Kong. MIT licensed, created 1 April 2026, 33,164 stars. Inside, it is bigger than the name suggests: 2,488 files, of which ninety are skill definitions written for the agent itself and 462 are an alpha library.

    Much of that bulk is research machinery. The decision layer, meaning the mandate, the checks, the kill switch and the journal, is a rounding error by file count, and it is the part that decides whether a bad afternoon stays bounded.

    Every file in the repository, one square each
    473 files in the alpha zoo, holding 462 alphas
    91 SKILL.md files: 90 bundled skills plus the agent brief
    ~1,900 everything else: loaders, engines, screeners, docs, tests
    18 files in agent/src/live/: the mandate, the checks, the kill switch, the journal

    Sources. File counts read from the repository tree on 10 September 2026.2 Safety‑layer squares are placed illustratively, not by path.

    Finding 2 · What is missing

    Thirteen connectors audited. Not one will attach a stop at order entry.

    I checked all thirteen that existed when I wrote this. Twelve had no concept of it, and the one function with stop parameters is disabled on live accounts. A fourteenth, Zerodha, landed the day before this page pulled its data, and has not been checked. If entering with a stop attached is how you trade, this is not yet your tool, though a connector is a few hundred lines of MIT‑licensed code if you want to change that.

    The sharpest symptom is on eToro, where editing a stop on a live position is switched off entirely, because loosening a stop can pull more account funds into margin and the system refuses to authorise what it cannot measure in advance. That refusal is the safety layer being consistent, declining what it cannot bound, at the price of a feature you might want.

    Stop-loss at order entry, by broker connector
    0of 13 audited connectors attach a stop at order entry
    12 have no concept of it1 has stop parameters, disabled on live

    Zerodha, the fourteenth, arrived after the audit and is not shown.

    The permission model thinks in dollars of stock. Forex and CFDs are margin products, where a position can be far larger than the cash behind it.

    Sources. Connector audit as published in the teardown.1

    Finding 3 · Coverage

    China, India and Korea get dedicated engines. Europe gets one data loader.

    US coverage is solid. There are smaller signs of a fast‑moving young project too: stale docstrings, and a run‑fingerprint module the README advertises but nothing feeds yet.

    Market coverage by depth
    China
    dedicated engine
    India
    dedicated engine
    Korea
    dedicated engine
    United States
    solid
    Europe
    one data loader, no engine

    Sources. Coverage assessment as published in the teardown.1

    Finding 4 · The trap

    The agent removes the effort. It does not remove the arithmetic.

    Testing fifty strategy ideas in an afternoon used to be impossible, and the impossibility was a kind of protection: the more strategies you try against the same history, the more certain you are to find one that fits the past by luck.

    Below, every strategy is pure noise. None of them has any edge at all. Turn the dial up and watch the best of them start to look like a strategy.

    With five years of data, Bailey and co‑authors put the ceiling at 45 independent configurations before pure luck is almost guaranteed to hand you an in‑sample Sharpe of 1.3 The wider literature agrees on the direction: Harvey, Liu and Zhu ask a newly discovered factor to clear t > 3.0 once the 316 already published are priced in,4 and Hou, Xue and Zhang found 82% of 452 published anomalies fail to replicate under a multiple‑testing hurdle.5

    Best of 45 coin‑flip strategies, ranked on the same five years
    five years, tested on thistwo years it never saw

    Computed in your browser: 45 random walks with zero drift, ranked by in‑sample Sharpe. Fixed seed, so every number beside the chart is reproducible.7

    0.00Best Sharpe, in sample
     Same strategy, out of sample
     95% interval on that Sharpe
    0.00Luck alone, over this many tries3
    Ask for all three by name. None of them is guaranteed to run: the engine’s own comments call validation optional, and the agent’s instructions suggest only one of them.
    Convergent evolution

    Two teams, arriving independently, at the same four organs.

    At Purple we build in this space, so weigh this accordingly. Our Axiory MCP server connects an AI agent to a cTrader account over FIX 4.4, and it arrived at the same four safety mechanisms independently. Two teams landing on the same four organs is the strongest evidence I have that these are not decoration.

    It hits the same stop‑loss wall from the other side, solving it with an automated three‑step workflow rather than stops at entry, and FIX 4.4 denies it something Vibe‑Trading has: any view of account balance or margin. It is still pre‑production.

    Organ 1

    Pre‑order risk checks

    A fixed series that fails closed. Confusion resolves to a refusal, never to a guess.

    Organ 2

    A kill switch

    Outside the model’s reach. A file, not a flag, and unreadable counts as on.

    Organ 3

    A paper mode

    The default, not the demo. Weeks of it before a mandate touches real funds.

    Organ 4

    An append‑only journal

    Hash‑chained, tamper‑evident, and it stops writing once the chain breaks.

    The experiment

    Run it yourself, in twenty minutes.

    The entire safety layer runs on the Python standard library plus one common data package. You can exercise the part of this project that decides whether an order is allowed without an account and without a key. That is the experiment, and it is where my seven orders came from.

    1. Install Python 3.11, 3.12 or 3.13. Nothing older, nothing newer: 3.14 fails deep inside a dependency with no prebuilt wheel.2 The research half also wants a model API key you pay for and free data‑source keys for the markets you care about, so get those first.
    2. Clone the repo. Point your own coding agent at agent/SKILL.md, a 23 KB brief written for AI agents working on this codebase, and at the wiki, before it touches anything else.
    3. Have it drive the pre‑trade checks with a made‑up mandate and made‑up orders. No brokerage account: you will not need one for a long time, and paper is the default for weeks before a mandate touches real funds.
    4. Read the refusals it brings back. That is the whole exercise.

    When the system is confused, the answer is no. Somebody accepted that cost on purpose.

    Every one of those refusals buys an outage when a data feed hiccups. That is the trade, and it is the right way round. Trace a single number in any answer back to the data call that produced it. If you can, you are looking at research. If you cannot, you are looking at generated prose with figures in it, which is worse than useless because it is persuasive.

    Path 1

    Own the stack

    Run Vibe‑Trading yourself. Your keys, your uptime, your upgrade path on a young repo. Most operations, most learning.

    Path 2

    Keep the agent, drop the plumbing

    Our Axiory MCP server handles the broker plumbing while the agent stays yours. Pre‑production today, so the operations cost is unknown.

    Path 3

    The platform, operated for you

    Takumis runs the agent, the connectors, the keys and the account plumbing for you. The operations cost is theirs, not yours, and you work inside what the platform exposes.

    For agents and sceptics

    Every number on this page, and where it came from.

    Every figure here traces to a published source, or is computed in your browser from assumptions stated beside it.

      What this page is. Hello Purple is a technology publisher. This is an engineering teardown of a third‑party open‑source project, written for people building with agents. Vibe‑Trading is MIT licensed and built by HKUDS; we are not affiliated with it. Nothing here is investment advice, a recommendation to trade anything, or an offer of any financial service. A backtest is not a prediction, and a strategy that passes every honesty check has proven one thing only: that it survived the past. Two of the three paths above are our own products, which is a commercial interest you should weigh.
      By email

      Get the next piece the day it is published.

      You are on the list. One email when a new report lands.

      One email when a new report lands, nothing else. By subscribing you agree to our privacy policy.