Configuration
where every setting lives.
Three places hold settings: config.json for the whole desk, the console for the main switches, and environment variables for keys and the server. This page says which one wins and lists the keys you are most likely to change.
01Where settings live
| Place | What goes there | When it applies |
|---|---|---|
src/config.mjs | Every default, with a comment on each key. Do not edit it; read it. | Always, unless overridden |
config.json | Your overrides of any key from src/config.mjs. Created from config.example.json, ignored by git. | At start. Restart after a change. |
Console (/admin) | Mode, bankroll, limits, lanes, smart-wallet rules, liquidation map, leverage profile, keys. | At start and immediately after each save. A console value overrides config.json once you change it from the console default (table). |
| Environment variables | Keys, Telegram ids, dashboard port and password, console secret key. | At start. Keys in the environment win over keys stored in the console. |
02How config.json works
- You only write the keys you change. Nested objects are merged with the defaults, so
{"limits": {"maxOpen": 3}}keeps every other limit. - Lists replace the default list entirely (for example
news.feeds). - A value of the wrong type is rejected at start with one clear line, for example
config: …config.json: bankrollSol: expected number, got string ("10"). Invalid JSON is reported with the file name. modemust bepaperoralert. Anything else stops the desk at start.node src/cli.mjs doctorprints warnings for contradictions: zero or negative limits, placeholder wallets, a stop at or above the entry, exposure caps that make the last slots unreachable, and more.
The example file:
{
"mode": "paper",
"bankrollSol": 10,
"telegram": { "channels": ["example_calls_channel"] },
"whales": { "wallets": ["PASTE_A_SOLANA_WALLET_YOU_FOLLOW"] },
"news": { "feeds": ["https://cointelegraph.com/rss", "https://www.coindesk.com/arc/outboundfeeds/rss/", "https://decrypt.co/feed"] },
"macro": { "enabled": true, "notionalUsd": 200 }
}
example_calls_channel and PASTE_A_SOLANA_WALLET_YOU_FOLLOW are placeholders. Replace them or remove them (how).
03The keys you will change most
| Key | Default | What it does |
|---|---|---|
mode | paper | paper: trades on paper with live data. alert: notifies only, no paper book. |
bankrollSol | 10 | Starting paper bankroll of the memecoin book, in SOL. |
loopSeconds | 20 | Seconds between desk cycles (kept at 5 or more). |
dataDir | data | Where state, journal, recordings and the console database are written. |
solanaRpc | public mainnet | Solana HTTP RPC for wallet reads and FOMO collection. |
pump.wsUrl | public mainnet WS | WebSocket for the real-time pump.fun stream. Use a private one (below). |
telegram.channels | [] | Public Telegram channels read through t.me/s/<name> for contract addresses and $TICKERs. Bare names only. |
whales.wallets | [] | Solana wallets whose buys count as a confirming signal. Empty by default; add wallets you follow, or use the smart-wallet list. |
news.feeds | 6 RSS feeds | News sources. Add X accounts through your own RSSHub or nitter instance. |
news.llm | claude-opus-5, effort low, 8 per cycle | Claude model used when ANTHROPIC_API_KEY is set. |
ev.minEv, ev.kellyFraction, ev.maxPerTokenPct | 0.03, 0.2, 2 | The core EV gate: minimum expected return after costs, fraction of Kelly, and hard cap per token in % of bankroll. |
limits | maxOpen 5, dailyLossPct 10, cooldownMinutes 60, maxExposurePct 10 | Memecoin book limits. |
protections.hardStop.redPct | 20 | Drawdown from the equity peak at which everything is sold and the desk latches (kill switch). |
portfolio.maxGrossUsd | 8000 | Cap on gross USD notional across all perp books. |
<book>.enabled | true | Turns a book off: macro, hlcopy, trend, basis, xarb, funding, polymarket, polymm, jev, flow, security, pump, wallets, liqmap, alloc. |
Every other key (lane thresholds, exit ladders, allocator, books) is documented by the comment next to it in src/config.mjs, and the important ones on the page of the feature they belong to.
04Console fields and the config keys they set
config.json is the base. With the console on (npm start, npm run dash), a console field overrides its config key only when its value differs from the console default in the table below, that is, once you really changed it. The check runs at start and after every save. If you set a field back to its console default, the config.json value (or the built-in default) applies again.
| Console field | Config key | Console default |
|---|---|---|
| Desk → Mode | mode | paper |
| Desk → Paper bankroll (SOL) | bankrollSol | 10 |
| Desk → Max open memecoin positions | limits.maxOpen | 5 |
| Desk → Daily loss stop (%) | limits.dailyLossPct | 10 |
| Memecoin lanes → Moonshot / Graduation / Revival / Smart money lane | pump.lanes.<lane>.enabled | on |
| Memecoin lanes → … ticket (% of paper equity) | pump.lanes.<lane>.stakePct | 1 (graduation 1.5) |
| Smart wallets → Rounds before a wallet can be smart | wallets.minRounds | 8 |
| Smart wallets → Minimum mean hold (s) | wallets.minMeanHoldSec | 60 |
| Smart wallets → Smart wallets needed for a consensus | pump.lanes.smart.minWallets | 3 |
| Smart wallets → Live candidate feeds | wallets.feeds | uwuu.ai 7-day list |
| Liquidation map → Refresh the map in the background | liqmap.enabled | on |
| Liquidation map → Coins | liqmap.coins | BTC ETH SOL HYPE XRP DOGE SUI BNB |
| Liquidation map → Accounts read per refresh | liqmap.wallets | 2000 |
| Liquidation map → Refresh every (min) | liqmap.everyMinutes | 30 |
| Liquidation map → Alert when price is within (%) | liqmap.alertWithinPct | 1.5 |
| Liquidation map → …holding at least (USD) | liqmap.alertMinUsd | 5,000,000 |
| Trend & leverage → Leverage profile | leverage.defaultProfile | growth |
One-off commands such as liq, wallets, replay or leverage do not start the console, so they use config.json and the defaults only. If you changed a value in the console, set the same value in config.json when you want those commands to match the running desk.
05Solana RPC and the pump.fun WebSocket
The public Solana endpoint drops heavy logsSubscribe streams. For a stable pump.fun stream, create a free endpoint at Helius, QuickNode or Chainstack and set it in one of two places:
- Console (manager or owner): Integrations → Solana RPC / WebSocket URL. Enter the
https://URL. The desk uses it assolanaRpcand derives the WebSocket (pump.wsUrl) by replacinghttpwithws, at start and right after each save. The console's Solana RPC health check tests the same URL. When filled in, it wins overconfig.json. - config.json, if your provider's WebSocket URL is not simply the HTTP URL with
ws:
{
"solanaRpc": "https://<your-rpc-host>/?api-key=<key>",
"pump": { "wsUrl": "wss://<your-rpc-host>/?api-key=<key>" }
}
RPC URLs usually contain an API key, so the console stores this field as a secret: encrypted at rest, set by the owner only, never shown back after saving. If you put the URL in config.json instead, keep that file out of any public repository.
06Environment variables
| Variable | Purpose | |
|---|---|---|
ANTHROPIC_API_KEY | Claude news scoring. | Optional |
TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID | Alerts and commands (Telegram bot). | Optional |
TELEGRAM_OWNER_ID | Your Telegram user id; required for commands in a group chat. | Optional |
TYPESAFE_API_KEY | The Jev forecaster. | Optional |
ADMIN_SECRET_KEY | Encrypts the console's stored secrets. Generate one with openssl rand -hex 32. If unset, a key is generated into data/.admin-secret-key. | Recommended on a server |
DASH_PORT | Dashboard and console port. Default 8790. | Optional |
DASH_TOKEN | Extra dashboard password (?token= or Authorization: Bearer). Needed when the console is off. | Optional |
DASH_ALLOWED_HOSTS | Public host names the dashboard answers behind a reverse proxy, comma-separated (Deployment). Without it, only loopback hosts are answered. | Optional |
DASH=0 | npm start without dashboard and console. | Optional |
DESK_ADMIN=0 | Dashboard without the console. | Optional |
DASH_DATA | npm run dash reads this data folder instead of data/ (for replays). | Optional |
There is no .env loader in the code: export the variables in your shell, or set them in your process manager (Deployment).
export TELEGRAM_BOT_TOKEN=<token>
export TELEGRAM_CHAT_ID=<chat id>
npm start
07Temporary overrides for research
replay and sweep accept --set key=value, repeatable, without touching config.json. Values are read as JSON when they parse (numbers, true/false, lists). A key that does not exist is refused, so a typo cannot silently change nothing.
node src/cli.mjs replay --set pump.lanes.moonshot.enabled=false --set ev.minEv=0.05