Jev Trader: One Jev Decision Every Monad Block

jev-trader is the clearest production example of Jev doing real work: an open-source TypeScript bot that asks a Jev model for one trading decision every Monad block — roughly every 300 ms — and turns that answer into a live post-only limit order on the Kuru MON-USDC book. It is MIT licensed, published by Jarrod Watts, and is one of the most-starred projects in the Jev ecosystem.

Repositoryjarrodwatts/jev-trader
Stars3,032
Forks589
LanguageTypeScript
LicenseMIT
CreatedSept 16, 2026

What the bot actually does

Every block the model is asked a single question: where is the price going over the next HORIZON_BLOCKS (100 blocks by default, about 30 seconds)? It answers buy or sell, with a probability attached. The bot then posts one post-only limit order on that side, QUOTE_INSIDE_TICKS inside the touch, cancelling whatever it had resting in the same batchUpdate. Because the order is post-only, it never crosses the spread — it waits to be hit, so the bot earns the spread instead of paying it.

That is the whole idea, and it is a different use of a decision model from the usual classification demo: the model is not summarising a book or writing a rationale, it is returning one bounded choice that a program immediately converts into a signed transaction. The thresholds, sizing, position caps and cancellations all stay in code — the model only decides the side.

The 300 ms budget

A decision and an order have to fit inside one block, so the hot path makes exactly two RPC round trips: one eth_call to read the book (about 18 ms on the public RPC) and one eth_sendRawTransaction, which returns as soon as the transaction is accepted. Everything that can be moved off the hot path has been: no eth_estimateGas (Monad charges the gas limit, so the limit is fixed or derived once at startup), no synchronous send, no live gas price lookup — fees are static type-2 values with a 2 gwei priority. Receipts, fee estimates and the vault check all land on later blocks.

The repo publishes its own numbers from a dry run with the stand-in momentum model: book read p50 about 18 ms, whole loop p50 about 100 ms, of which roughly 80 ms is the mock model's inference stand-in. That gap is the part worth watching when you swap in the real model — it is the budget the model has to live inside.

Dry run first, then live

Run it with no PRIVATE_KEY and it dry-runs: real order book, real model calls, simulated fills. Set MODEL=jev and a TypeSafe API key to use the hosted model; the default mock is a momentum heuristic used as a stand-in. The project ships a bench script that compares its hand-decoded book reader against the SDK, and an offline encoder that signs a buy and a sell and asserts the calldata matches — the two checks that matter when you are writing calldata by hand.

What it shows about Jev in production

Three things. First, that a decision model fits a control loop where a chat model would not: a string response would have to be parsed, guarded and retried inside a 300 ms budget. Second, that latency accounting is the real engineering problem — the model call is one term in a budget dominated by RPC and gas mechanics. Third, that hold is a first-class outcome: the bot posts nothing when the model misses the block, which is a cleaner failure mode than firing a stale order.

The project streams its state over SSE — a snapshot on connect, then block, quote and fill events — so every decision can be checked against the order it produced. That audit trail is the part most trading bots hide, and it is why this repo is a better teaching example than a backtest notebook.

Read it

The source is at github.com/jarrodwatts/jev-trader. For the API side of the same model, see the Jev API guide; for the open-source alternative that runs locally, see Laya.

Last updated: 2026-10-19 · sources & corrections · every card links to its author's original post