Simple Node.js and TypeScript bot for PMX BTC Hourly markets on Solana. It opens a position shortly before resolution, holds it, and redeems automatically if the selected side wins. The repo also includes a small dashboard for monitoring state, balances, positions, and recent history.
- Selects the nearest active
BTC Hourlymarket. - Uses Binance price data to choose
UPorDOWN. - Sizes the trade with an EV-based optimizer instead of always buying the maximum.
- Sends buy and redeem transactions on Solana.
- Exposes a local dashboard and can be deployed with Railway + Vercel.
Install dependencies and create your local env file:
npm install
cp .env.example .envPowerShell:
Copy-Item .env.example .envMost setups only need these values in .env:
RPC_URLPRIVATE_KEYorPUBLIC_KEYfor dry-run modeENTRY_WINDOW_MINUTESMAX_STAKE_USDCDIFF_BET_CAPSMIN_EV_USDCMIN_ROI_PCTDASHBOARD_HOSTDASHBOARD_PORTRAILWAY_API_BASE_URLif you use Vercel as a public frontend
Keep the real PRIVATE_KEY only in .env. Never commit it.
Run the bot once:
npm run bot:onceRun the bot continuously:
npm run botStart the dashboard:
npm run dashboardOpen:
http://127.0.0.1:8787
Live buy test:
npm run buy:testBuild and typecheck:
npm run typecheck
npm run buildRun locally with Docker Compose:
docker compose up --buildTo use a different env file:
$env:APP_ENV_FILE=".env.example"
docker compose configRailway can run both the bot worker and the dashboard/status API in one container through:
node dist/run-railway.jsRecommended environment values:
DASHBOARD_HOST=0.0.0.0
HTTP_TIMEOUT_MS=0
RUN_ONCE=false
STATE_FILE=/data/state.jsonUsing a persistent volume mounted at /data is recommended.
Vercel serves index.html and api/status.js. Set:
RAILWAY_API_BASE_URL=https://your-railway-urlThe Vercel /api/status route proxies Railway /api/status.
- Start with
DRY_RUN=truebefore enabling real trading. npm run buy:testsends a real transaction and requires a real private key.- This bot is hold-to-resolution only; it does not do active intra-market trading.
- By default state is stored in
.data/state.json. - Do not set
PRIVATE_KEYon Vercel.