Wheelman
OfficialClick on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Wheelmanpreview a $1 BTC long with a 2x target and show payout after fees"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Wheelman
Wheelman, the Rekt trading bot and CLI: a bot, a command line and a local MCP server for Rekt
Knockout and Minute. You run it on your own machine, with your own wallet and your own RPC endpoint.
It uses the Rekt SDK, @rekt-trading/1000x from npm, for both games, and it sends nothing the risk
limits have not allowed.
Status: 1.0.0, on mainnet. Wheelman runs from a clone of this repository. It is not an npm package.
Documentation: https://docs.rekt.money
Contact: support@asymmetra.xyz
License: Apache-2.0 (see
LICENSE)
Start in two minutes
Node 22.18 or later. There is no build step: Node runs the TypeScript directly. npm link puts
wheelman on your path; without it, run node src/cli.ts in its place. Run it from a clone: npx
and npm install -g from a git URL do not work, because Node does not run TypeScript from
node_modules.
git clone <this repository's URL> wheelman && cd wheelman
npm install && npm link
wheelman setup # wallet, RPC, strategy, risk limits; writes .env (mode 600)
wheelman markets # every market, its stake bounds and fees
wheelman preview BTC long 1 --target 2 # what an open costs and pays, after every fee
wheelman open BTC long 1 --paper # a paper position: simulated, nothing sent
wheelman run --paper # the bot on paper
wheelman run --dry-run # builds and simulates the real transactions; sends nothing
wheelman run # the bot, tradingThe wallet needs SOL for fees and rent (0.01 SOL is enough to start) and USDC for stakes.
Related MCP server: xmatters-mcp
The CLI
command | what it does |
| every market: open or not and why, stake bounds, leverage, fees, room left on a side |
| the stake, the barrier, and the payout at the target and at the barrier, after every fee |
| one Knockout position ( |
| asks the venue to close a position; the venue's keepers complete it |
| open positions, live rounds, balances, today's result |
| the bot |
| onboarding; |
| a session key for an agent (below) |
| a stdio MCP server with the same commands as tools (below) |
--paperonopen,close,positionsandrun: simulated fills on a paper account in.wheelman/paper.json. Nothing is sent.--dry-runonopen,close,runandsession: builds the real transaction, simulates it on mainnet, prints its compute units and bytes, and sends nothing. With no key, setOWNER.-o jsonprints one line:{"ok": true, "data": ...}or{"ok": false, "error": {"category", "code", "message", "retryable"}}.retryableis true only where sending the same request again cannot open a second position. The exit code is 0 on ok, 1 on an error, 2 on a bad flag.
Every open, from the CLI, an agent or the bot, passes the same risk limits. Amounts in the output
are USDC with 6 decimals; ids are text.
Agents
Users bring their own agent (Claude Code, Codex, Cursor, or any MCP client). Wheelman hosts no agent and holds no model key.
Session keys.
wheelman session start --allowance 20 --expires 24h(signed by the owner, once) authorises a freshly generated key to trade for the owner's wallet: at most the allowance in USDC, until the expiry. It also creates the owner's book when there is none and sends the key 0.01 SOL for its own fees (--fuel). The key is written towallets/session-keypair.json(mode 600) before the transaction is sent. The command prints the two settings the agent needs:OWNERandSESSION_KEYPAIR_PATH.wheelman session end(the owner) ends it, drops the allowance and returns the key's SOL. The owner's key never goes to the agent.MCP.
wheelman mcp --env agent.envservesmarkets,preview,positionsandsession_status. With a session key configured it addsopenandclose, signed by the session key; with--paperit adds them as paper-only. It never signs with the owner's key.client
how to add it
Claude Code
claude mcp add wheelman -- node /path/to/wheelman/src/cli.ts mcp --env /path/to/agent.envCodex
in
~/.codex/config.toml:[mcp_servers.wheelman],command = "node",args = ["/path/to/wheelman/src/cli.ts", "mcp", "--env", "/path/to/agent.env"]Cursor
in
.cursor/mcp.json:{"mcpServers": {"wheelman": {"command": "node", "args": ["/path/to/wheelman/src/cli.ts", "mcp", "--env", "/path/to/agent.env"]}}}agent.envholdsRPC_URL,OWNER,SESSION_KEYPAIR_PATHand the risk limits, and no owner key.Skill.
skills/wheelman/SKILL.mdteaches an agent the CLI: copy the folder into your agent's skills folder.
How it works
An open is an order. The venue fills it at its own next price, after a short delay, or returns the whole stake. Wheelman needs prices only for a strategy's signal and for paper fills.
The venue closes positions. A position ends at its barrier (the stake is gone), at its take-profit, at its timer, or after a close request. The venue's keepers send every close. A Minute round runs on Minute's clock and has no early close.
The chain is the state. Positions, balances and today's settled results are read from the chain, so a restart or a fresh container is safe.
.wheelman/holds the log, the paper account and a cache of settled transactions (they never change, so each is fetched once).One loop. Once a second the strategy reads the latest price and its own positions and returns intents. The risk guard checks each one. Each transaction is simulated first and sent only when it simulated clean. The result is read from the chain (the opened
seq, the settlement).One code path. The CLI, the MCP server and the bot call the same functions. The venue layer (
src/client.ts) has the shape of the SDK's Knockout client:market,preview,open,positions,close,settlement,history,build.
Strategies
The bot runs one strategy. Pick one with STRATEGY, and set its parameters with PARAM_<NAME>. Every parameter has a default
and a bound, and the bot refuses a value outside the bound. The defaults are starting points, not
recommendations.
knockout-momentum (Knockout). Open in the direction of a move larger than trigger_bps over lookback_s.
variable | default | bounds | meaning |
| 1 | 0.2 to 1000 | stake per position, in USDC |
| 30 | 5 to 3600 | the window the move is measured over, in seconds |
| 5 | 1 to 1000 | the smallest move that opens a position, in basis points |
| 2 | 2 to 1000, or 0 | take-profit as a multiple of the stake, 0 for none |
| 60 | 26 to 86400, or 0 | the position timer: the venue closes the position then; 0 for none |
| 60 | 0 to 86400 | seconds to wait after a position ends |
knockout-fade (Knockout). Open against a sharp move; close when the price is back where the move started.
variable | default | bounds | meaning |
| 1 | 0.2 to 1000 | stake per position, in USDC |
| 20 | 5 to 3600 | the window the move is measured over, in seconds |
| 10 | 1 to 1000 | the smallest move that opens a position, in basis points |
| 2 | 2 to 1000, or 0 | take-profit as a multiple of the stake, 0 for none |
| 30 | 26 to 86400, or 0 | the position timer: the venue closes the position then; 0 for none |
| 60 | 0 to 86400 | seconds to wait after a position ends |
| yes | yes, no | close when the price returns to where the move started |
knockout-straddle (Knockout). In a quiet market, open a long and a short of the same stake
together, in one transaction. A knockout ends one side; the other side runs to its take-profit or
its timer. One wallet may hold both sides of a market.
variable | default | bounds | meaning |
| 1 | 0.2 to 1000 | stake of each side, in USDC |
| 60 | 5 to 3600 | the window the quiet filter looks at, in seconds |
| 3 | 0.1 to 1000 | open only when the range over quiet_s is at most this, in basis points |
| 3 | 2 to 1000, or 0 | take-profit as a multiple of the stake, 0 for none |
| 120 | 26 to 86400, or 0 | the position timer: the venue closes the position then; 0 for none |
| 120 | 0 to 86400 | seconds to wait after a position ends |
minute-trend (Minute). Each round, take the side of the move over lookback_s; skip a move below min_bps.
variable | default | bounds | meaning |
| 1 | 0.01 to 100 | the total each round takes from the wallet, in USDC |
| 30 | 5 to 3600 | the window the trend is measured over, in seconds |
| 2 | 0 to 1000 | skip the round when the move is smaller than this, in basis points |
minute-schedule (Minute). Play every Nth minute at a fixed stake and side rule, inside a daily UTC window.
variable | default | bounds | meaning |
| 1 | 0.01 to 100 | the total each round takes from the wallet, in USDC |
| 1 | 1 to 1440 | play in every Nth minute of the clock |
| alternate | long, short, alternate | the side of each round |
| 0 | 0 to 23 | the first hour of the window (UTC) |
| 24 | 1 to 24 | the hour the window ends (UTC) |
template (Knockout). A skeleton that never trades: copy src/strategies/template.ts to write
your own. A strategy is { id, game, params, onTick(ctx) }; onTick returns intents and sends
nothing. Add it to registry() in src/strategies/index.ts, or load it with EXTRA_STRATEGIES.
The venue's own bounds also apply: the stake must be inside the venue's limits (Minute's for a round), which Wheelman reads from the chain.
Configuration
Environment variables only: .env on your machine (or --env <file>), the host's settings
elsewhere. .env.example lists every variable with one line on each. The ones you set:
variable | meaning |
| required: your HTTPS RPC endpoint |
| the owner's wallet |
| an agent's settings: the wallet's address and its session key |
| what the bot trades |
| the risk limits |
|
|
Wheelman checks every variable before its first RPC call and refuses a bad value with the reason.
Risk limits
The risk guard sits between every intent and the venue: the bot's, open's and an agent's. It never
blocks a close. It counts the worst case, every open stake lost, so no limit is passed after the fact.
variable | default | Wheelman opens nothing that would |
| 1 | stake more than this in one position or round |
| 2 | hold more than this many positions and rounds at once |
| required | lose more than this today (UTC), counting every open stake as lost |
| 0 | leave the wallet below this, counting every open stake as lost |
Wheelman refuses to trade without a daily loss stop. Today's loss is read from the chain, so a restart does not reset it. A session key adds the owner's own ceiling: its allowance and expiry.
Paper mode
Paper results are priced by the SDK's own settlement arithmetic, with the terms a real position
freezes at open: the barrier, the target, the exit fee and the market's fee terms (the share of a
gain the venue keeps). A Minute round also pays Minute's own fees. Two things differ from live: the
fill is the next price Wheelman sees, not the venue's, and a one-shot command checks the barrier only
at the prices it reads (run --paper sees every tick). The borrow fee is not modelled; it is 0 today.
A paper result tests what Wheelman does; it does not say what live trading pays.
RPC: any provider
Drop in any endpoint: Helius, Triton, QuickNode, or your own node. Wheelman uses little:
Stream first, poll last. The bot subscribes to its own accounts (websocket, or Yellowstone gRPC with
GRPC_URL), reads once after every reconnect, and reads at least every 30 s as a fallback.Only its own accounts. One
getMultipleAccountsreads the venue, a market and the wallet's book. When a position ends, it reads its own book's latest transactions once to learn what it paid. It never scans a program's accounts.One rate limit and one backoff per endpoint. On HTTP 429 or JSON-RPC -32005 it waits 1 s, doubles to 30 s with jitter, and stops loudly after 5 attempts.
RPC_FALLBACK_URLtakes over only whileRPC_URLfails.confirmedon every call. The blockhash and the priority fee are cached for a few seconds.One send, one bounded rebroadcast. It simulates first, sends with
maxRetries: 0, sends the same bytes again every 2 s, and stops when the transaction confirms or its blockhash expires. On a Helius endpoint it asks Helius for the priority fee; elsewhere it uses recent fees.SEND_URLmay point at a send-only endpoint.No key in a log. Every log line names the host only and redacts keys from URLs and errors.
It refuses early: a non-mainnet endpoint, an unlisted market or a stake the venue does not take stops it before any spend.
Prices
A price is needed only for a strategy's signal and for paper fills. PRICE_SOURCE=coinbase reads
Coinbase's public ticker (no key, no account) for BTC, ETH, SOL and XRP. PRICE_SOURCE=replay reads
a tape for paper mode: one JSON line a price, {"time": 1767225600000, "market": "BTC", "price": 100000}.
To add a source, write one function in src/prices.ts that returns a PriceSource.
Hosting
The same variables work everywhere. One process, no database, no web server. A fatal error exits
non-zero, so every host restarts it. Dockerfile and render.yaml are templates for your own host:
you run Wheelman, with your own wallet; nobody hosts it for you.
Any server:
npm ci --omit=dev && npm start(that iswheelman run), under your process manager.Docker:
docker build -t wheelman .thendocker run --env-file .env -v "$PWD/wallets:/app/wallets:ro" wheelman.Render:
render.yamldescribes one background worker. SetRPC_URLandDAILY_LOSS_USDCin the dashboard and put the keypair in a Secret File namedbot-keypair.json(or setWALLET_SECRET_KEY).
Safety
Wallet and session key files are written with mode 600 and never printed, logged or sent. Back up the wallet.
Use a wallet for Wheelman alone, and fund it with what you are ready to lose. At the barrier a position pays nothing.
Give an agent a session key, never the wallet. Size its allowance for one session and end it when you are done: a token allowance has no clock of its own.
Never commit
.env,wallets/or a keypair file;.gitignoreexcludes them.Use
--paperand--dry-runbefore trading, and after every change you make.
Development
npm run check runs the type check and the tests (Node's own test runner, no network).
This server cannot be deployed
Maintenance
Related MCP Connectors
Live prices, perps, prediction markets and a paper trading desk over one MCP.
Autonomous xRocket CEX trading inside operator-set limits, plus live market data over MCP
Historical tick, order book and settlement data for Polymarket and Predict.fun crypto up/down markets, plus smart-money lists and backtest quotes, over a read-only MCP server.
Trade Papertrade BTC and ETH perps from Claude, ChatGPT, Codex, Cursor and any MCP client.
Related MCP Servers
- AlicenseAqualityBmaintenanceEnables agents to read Cluby markets, positions, and pre-trade quotes over stdio, using the same arithmetic as the interface while holding no keys and signing nothing.9MIT
- AlicenseCqualityBmaintenanceEnables MCP clients to interact with the current xMatters REST API over stdio, covering people, devices, groups, on-call schedules, events, incidents, workflows, services, integrations, and subscriptions. It is read-only by default and requires explicit operator opt-in plus per-call confirmation for mutations.179Apache 2.0

Daykeeper MCPofficial
AlicenseAqualityAmaintenanceA local stdio MCP adapter for the Daykeeper management API. It uses separately issued scoped credentials and exposes read-only tools by default; planning and mutations require explicit opt-in.826 npmApache 2.0- AlicenseAqualityBmaintenanceEnables MCP clients such as Claude Code, Claude Desktop, and Cursor to communicate over stdio with the IMD swarm API to check evaluator verdicts, import public GitHub repositories, get quotes, and pay quoted orders through the x402/Permit2 flow with spend caps, dry-run safety, and configurable wallet signing.8MIT