For one night in July 2026, a short position of mine sat on the exchange without a stop-loss. No language model was involved. The stop had been removed by my own position monitor, a piece of plain code whose only job is to make sure every position has one.
What the monitor does
The monitor runs every 15 minutes. It reads the open positions and stop orders, works out where each stop should be and acts if needed: it places a missing stop or moves an existing one closer. It never moves a stop further away. Before it sends a price to the exchange, it rounds the price to the tick size of the contract.
The bug
To round a price, the code needed the number of decimal places of the tick size. It got that number by turning the tick size into text and counting the digits after the decimal point. For a tick size of 0.01 the answer is 2.
The contract in question trades at a very low price and has a tick size of 0.000000001. JavaScript writes that number in scientific notation:
String(0.01) // "0.01" two digits after the point
String(0.000000001) // "1e-9" no point at all
With no decimal point in the text, the code counted zero decimal places and rounded every stop price for this contract to a whole number. A stop at 0.000004487 became a stop at 0.
Why the safety rule did not catch it
The rule that a stop may only move closer compares two prices. For a short position, closer means lower. A stop at 0 is lower than any real stop, so to the rule it looked like the tightest stop possible, and the move was allowed.
What happened
Moving a stop took two steps: cancel the old order, then place the new one. The cancel went through. Then the exchange rejected the new order, because a stop price of 0 is not a price. From that moment the position had no stop.
Every 15 minutes the monitor found a position without a stop, calculated a stop at 0 and was rejected again, 32 times in a row. The position closed the next morning with a loss of about half a dollar. That was luck. If the market had moved hard against the position that night, nothing would have limited the loss.
The fix
- The number of decimal places now comes from the logarithm of the tick size and no longer from its text form. I tested the function against eight tick sizes, including the smallest one and odd ones like 0.5.
- A calculated stop that is not greater than zero leads to no action at all. The monitor keeps the existing stop and logs the reason.
- Prices are formatted with a fixed number of decimal places before they are sent, so very small numbers no longer leave the system in scientific notation.
What I took from it
The order of cancel and place matters. Cancelling first leaves a gap whenever the second step fails. The futures agent that later replaced this setup works the other way round: its gateway refuses to cancel the protective stop of an open position until a stop that is at least as tight is in place.
A comparison needs plausible inputs. The rule against loosening a stop was correct and still let the worst case through, because one of the two prices it compared was nonsense. The check for a usable price has to come before the rule.
Test the extreme inputs. The rounding function worked for the usual tick sizes. I had not tested it with the smallest one.