JupiterJupiter Developer Platform
Docs
Pricing
Blog
Changelog
Sign In

Blog/Swap

Trailing Stop Loss

Trailing Stop Loss
yusufyusuf and evan·July 8, 2026·6 min read

A Trailing Stop Loss is a trigger price that moves on its own. It follows the market up and holds when the market falls. The feature is one sentence. The problem is that "moves on its own" means rewriting a trigger on every price tick, for every open order, on every token that's trading.

A stop that follows the peak

A normal Stop Loss is static. You set a price and it stays there. It is built to cap a loss, so you place it below where you are and leave it - and that is exactly its limit. If the market runs up before it ever falls, the stop never follows; it sits where you left it, and a reversal hands back the entire climb.

A Trailing Stop Loss moves with the market. You don't hand it a price at all; you hand it a distance. The system records the highest price reached as your high "watermark" and keeps the trigger that distance below it. As new highs come in, the watermark rises and the trigger rises with it; when the price pulls back, the trigger holds where it is. It only ever ratchets in your favour.

The difference shows up most clearly when a trade runs and then reverses. Say you hold SOL from $80, set a 10% stop, and SOL climbs to $120 before falling back:

Fixed Stop LossTrailing Stop Loss (10%)
At $80Trigger sits at $72Trigger sits at $72
SOL climbs to $120Still $72Trails up to $108
SOL reverses, you exitSell at $72Sell at $108
P&L-10%+35%

Same price action, opposite outcome. The fixed stop did the one thing it was built for - limit the downside - and on this path that meant realising a loss. The trailing stop rode the high up and locked the gain in on the way down. It does not catch the very top, as you give back the trail distance by design (here, the $120 peak less the 10% trail, leaving $108), but it turns a stop from pure loss-protection into a way to realise profit on a move you would otherwise have round-tripped.

The main lever is the size of the trail. A tighter trail - down to 0.50% - locks in closer to the high but is easier to knock out by ordinary volatility; a wider one, up to 90%, rides through the noise but concedes more on the reversal. There is no single right number, as it depends on how much movement you are willing to sit through before the order acts.

Slippage is the second lever, paired with the trail: it sets a lower-bound buffer beneath the trigger. Too tight, and a fast drop can outrun it, leaving the order unfilled; too wide, and you may fill well below where the trail meant to sell. There is no right default here either, least of all on a stop loss - how much slip you would accept before you would rather hold is yours to set.

The moving target

Trailing stop loss only became possible with the move to the LOv2 design, where every order is priced against a single USD value. That turned a stop loss into a price to watch - and a trailing stop into a price that keeps moving.

While a static stop is easy to store - one trigger price per order, set once and checked against the market until it fires - a trailing stop is the same row with one twist: the trigger price is no longer constant. It has to rise whenever the market makes a new high, then hold when the market pulls back.

The obvious way to build that is to treat each price tick as an event: when a token prints a new high, walk every open trailing order on it and rewrite its trigger. It works on paper, but it is a write amplifier. One trade that nudges the price becomes a fan-out of writes across every order watching that token, and the tokens with the most price action are precisely the ones carrying the most orders. Across everything trading at once, recomputing triggers this way would dominate the keeper's I/O for no good reason.

So we inverted it. Rather than a moving trigger per order, the keeper keeps a single running high - a "watermark" - per token, shared by every trailing stop on it. A new high updates one number, not a row each. The watermark only ever ratchets up, never down, which keeps the update trivial and leaves nothing to unwind when the price falls. That in-memory high is flushed to the database periodically, not per tick, in one batched write that recomputes the affected triggers from the new high:

trigger=watermark×(1−d)\text{trigger} = \text{watermark} \times (1 - d)trigger=watermark×(1−d)

where ddd is the trailing distance you set. Collecting in memory and flushing in batches is an old high-volume-telemetry trick, and it turns a price feed measured in milliseconds into a write rate measured in flushes. It survives restarts almost by accident, too: the watermark lives on the order row, not only in keeper memory, so a process that dies and comes back reads the high it had already persisted - there is no separate recovery path to get wrong.

One number, and the rest for free

What keeps the change small is that the recomputed trigger is written back into the very field a static order already uses. By the time anything else in the system looks at a trailing order, it sees an ordinary price order with an ordinary trigger price. The delta that makes an order "trailing" comes down to a couple of columns and the flusher that keeps one of them moving.

Everything downstream is untouched. Deposit, the trigger match, execution against a slippage-aware floor, the state machine every price order already runs through, and withdrawal all take the identical path a static order takes. This is also why triggering is not the same as executing: when the stop fires, the swap still runs through the usual price and slippage checks before it fills, exactly as any other price order would - the trail decides when to sell, not the precise price you walk away with.

We did not build a second order engine for trailing stops. We taught the one we have to move a number it was already storing, and pushed the cost of that movement into one cheap batched write instead of a storm of them.

Shipping it

Trailing Stop Loss is live in LOv2 today. If you have ever set a stop, watched the trade run past it, and wished the stop had followed, this is that order type.


yusuf and evan

July 8, 2026