← All posts

Two Verbs: What You Cannot Do on a Spot Exchange

We went back through the trading engine we ran on a crypto exchange from 2020 to 2021, and counted the actions it could take.

There were two. Buy. Sell.

No short. No cover. Not a single call anywhere in the codebase to borrow an asset, open a margin position, or sell something we did not already hold. The vocabulary was complete, and it was two words long.

That single fact explains more of our history than any strategy decision we ever made.

What two verbs actually means

On a spot exchange you own the thing or you do not. Holding an asset lets you sell it. It does not let you profit when the price falls — there is nothing to sell if you are not already holding, and once you have sold, a further decline is simply a decline you are not part of.

So in a rising market our system had a full range of expression. In a falling market it had exactly two moves: stop buying, or sell what it already owned. Both are defensive. Neither makes money.

Being right about a decline was worth nothing to us. We could avoid a fall. We could not trade one.

The good

The engine was honest about its own limits, in the sense that it never pretended otherwise. There is no half-built shorting path in that codebase, no abandoned margin experiment, no clever synthetic workaround that would have introduced borrowing risk we did not understand. Somebody looked at what the venue permitted and built inside it.

That restraint was correct. The synthetic routes to a short position on a spot venue in 2020 were exotic, expensive, and would have added counterparty exposure on top of an asset class that was already the riskiest thing we touched. Not building it was the right call, and it stayed the right call for the entire life of the system.

The bad — this is the missing half of a story we already published

We have written before about the day in June 2020 when a trading rule got written as a commit message, in the imperative, three times over: never keep buying into a fall.

At the time we described that as a lesson about momentum strategies. Reading the code, it is something more specific and less flattering: it is a rule we needed because we had no other way to express the view.

A system that can go short responds to a falling market by taking a position. Ours could only respond by not acting. So the discipline had to be imposed as a written prohibition on the one verb we did have — because the correct trade did not exist in our vocabulary. We were legislating around a structural limit, and calling it strategy.

That is a very easy mistake to make and a very hard one to see from inside. The rule was correct. It was also a workaround for a constraint we had accepted so completely that we had stopped noticing it.

The ugly

More of that engine was error handling than strategy.

We counted the error handling in that engine. Ninety-five separate places dealing with one class of server error. Dozens more for two others, including one so unusual that most web developers will never encounter it in a career. Retry sleeps. Handlers for connection failures. And more than a hundred guards against a response arriving with fields simply missing — the shape of the data was not guaranteed, so the code defended against its own inputs at nearly every step.

That is a measurement of us, not of anyone else. It says nothing about any venue's uptime — we never instrumented that — and everything about where our effort went. Some of that weight is the ordinary cost of talking to any network service over years. Some of it is inexperience. All of it is ours.

And that is the part worth admitting. We were spending a meaningful fraction of our engineering budget on staying upright rather than on trading, and we never once totalled it up. Each handler was added as a reasonable response to a specific incident. Nobody stood back and asked what the sum of them said about where we had chosen to operate — which is a question you can only ask if you are counting, and we were not.

What changed, and why it was a change of market rather than of code

Futures are natively two-sided. Short is not a workaround, a borrow, or a synthetic — it is a position, equal in standing to long, available in the same instrument with the same mechanics. A falling market is simply a market.

We did not fix this by writing better code. There was no better code to write. We changed where we traded.

That is the honest summary of our pivot, and it is less romantic than the version where a team outsmarts a problem. The problem was not solvable at our layer. Every rule we wrote to compensate — including the good ones — was a symptom of trying to solve a market-structure question with software.

The lesson we actually took: before optimising a strategy, check whether the thing you need is expressible in the venue you are in. If it is not, you are not writing a strategy. You are writing a workaround, and it will hold right up until the day the market moves the way you were never able to trade.


RoboTrader trades CME micro futures. Trading involves substantial risk of loss and is not suitable for every investor. Past performance is not indicative of future results.