Files
polymarket-terminal/AGENT.MD
T
direkturcrypto 526076fe6e feat: full project overhaul — market maker, sniper, WebSocket watcher, terminal UI
- Rename project to polymarket-terminal
- Add Market Maker bot (src/mm.js) with on-chain CTF split/merge/redeem via Gnosis Safe
- Add Orderbook Sniper bot (src/sniper.js) with multi-asset GTC low-price orders
- Add WebSocket watcher (src/services/wsWatcher.js) for real-time RTDS trade events
- Add terminal dashboard UI (src/ui/dashboard.js) using blessed
- Add CTF contract helpers (src/services/ctf.js) for splitPosition, mergePositions, redeemPositions
- Add mmDetector, mmExecutor, sniperDetector, sniperExecutor services
- Add simStats utility for dry-run P&L tracking
- Translate all Indonesian-language strings to professional English across all files
- Rewrite README.md in English with full setup guide, configuration reference, and architecture overview
- Rewrite AGENT.MD in English as comprehensive AI agent and developer reference
- Update package.json name, description, scripts, and keywords

Co-Authored-By: direkturcrypto <direkturcrypto.x@mail3.me>
2026-02-23 23:03:06 +07:00

10 KiB
Raw Blame History

AGENT.md — Polymarket Terminal

Developer and AI agent reference for understanding, extending, and maintaining this project.


Project Overview

Polymarket Terminal is a Node.js (ESM) automated trading terminal for Polymarket. It provides three independent bots:

Bot Entry Point Command Purpose
Copy Trade src/index.js npm start Mirror trades from a target trader wallet
Market Maker src/mm.js npm run mm Provide liquidity on 5m/15m binary markets
Orderbook Sniper src/sniper.js npm run sniper Place low-price GTC orders to catch panic dumps

Setting Up the Project

1. Prerequisites

  • Node.js v18+ (project uses "type": "module" — native ESM, no Babel/transpilation)
  • npm (comes with Node.js)
  • A Polygon EOA wallet with:
    • A small MATIC balance (for gas)
    • USDC.e deposited via Polymarket's proxy wallet

2. Install Dependencies

npm install

Key packages:

Package Version Role
@polymarket/clob-client ^4.7.3 Official Polymarket CLOB SDK (wraps ethers v5)
ethers ^5.x Wallet signing, contract calls (pinned to v5 — do not upgrade to v6)
dotenv ^16.x .env loading
blessed ^0.1.81 Terminal dashboard UI
ws ^8.x WebSocket client for real-time trade feed
nodemon ^3.x (dev) Auto-reload during development

3. Environment Configuration

cp .env.example .env

Edit .env and fill in all required fields. Refer to .env.example for detailed comments on each variable. The minimum required fields for the copy trade bot are:

PRIVATE_KEY=0x...
PROXY_WALLET_ADDRESS=0x...
TRADER_ADDRESS=0x...

4. Run in Simulation Mode First

# Copy trade simulation
DRY_RUN=true npm start

# Market maker simulation
npm run mm-sim

# Sniper simulation
npm run sniper-sim

5. Run Live

# Set DRY_RUN=false in .env, then:
npm start        # copy trade
npm run mm       # market maker
npm run sniper   # sniper

Architecture

Module System

All files use ES Modules (import/export). Do not use require().

Configuration (src/config/index.js)

  • Loads all settings from .env via dotenv
  • Parses and validates required fields per bot type
  • Exports two validator functions:
    • validateCopyTradeConfig() — for src/index.js
    • validateMMConfig() — for src/mm.js and src/sniper.js
  • Key exported fields: privateKey, proxyWallet, traderAddress, dryRun, mmTradeSize, etc.

Client (src/services/client.js)

  • initClient() — Initializes ClobClient from @polymarket/clob-client
    • Uses signature type 2 (POLY_PROXY) — EOA signs on behalf of the proxy wallet
    • Auto-derives API credentials if not provided in .env
  • getClient() / getSigner() — Singleton getters (call initClient() first)
  • getPolygonProvider() — Returns a JsonRpcProvider for Polygon mainnet
  • getUsdcBalance() — Reads USDC.e balance from the ERC-20 contract

Watcher (src/services/watcher.js)

  • Poll-based fallback: queries data-api.polymarket.com/activity?user={address}
  • Deduplicates processed trade IDs via data/processed_trades.json (max 500 entries)
  • fetchMarketInfo(conditionId) — Fetches market metadata from Gamma API
  • fetchMarketByTokenId(tokenId) — Reverse-lookup market by token

WebSocket Watcher (src/services/wsWatcher.js)

  • Connects to Polymarket RTDS: wss://ws-live-data.polymarket.com
  • Subscribes to the user channel for the target trader address
  • Filters for trade type events matching MATCHED status
  • Auto-reconnects with exponential backoff on disconnect

Executor (src/services/executor.js)

  • calculateTradeSize(traderFillSize) — Computes our order size:
    • percentage mode: SIZE_PERCENT% of MAX_POSITION_SIZE
    • balance mode: SIZE_PERCENT% of current USDC.e balance
  • executeBuy(tokenId, size, price) — FOK market buy with retry loop
  • executeSell(tokenId, shares, mode, price) — Market or limit sell
  • getMarketOptions(tokenId) — Fetches tick size and negRisk flag from CLOB

Position Manager (src/services/position.js)

  • CRUD operations on data/positions.json
  • Key structure: { [conditionId]: { tokenId, shares, avgBuyPrice, autoSellOrderId, ... } }
  • Enforces one position per conditionId — prevents double entry

Auto Sell (src/services/autoSell.js)

  • Called after a buy fills successfully
  • Places a GTC limit SELL at avgBuyPrice × (1 + AUTO_SELL_PROFIT_PERCENT / 100)
  • Price is rounded to the market's valid tick size and clamped to $0.01$0.99

Redeemer (src/services/redeemer.js)

  • checkMarketResolution(conditionId) — Queries Gamma API for resolved status
  • checkOnChainPayout(conditionId) — Reads payoutDenominator and payoutNumerators from CTF contract
  • redeemPosition(conditionId, tokenId, shares) — Calls redeemPositions on CTF via CLOB client
  • simulateRedeem(...) — Tracks wins/losses in data/sim_stats.json during dry-run

CTF Contract Helpers (src/services/ctf.js)

Used exclusively by the Market Maker bot. Interacts with the Gnosis Safe proxy wallet.

  • splitPosition(conditionId, amountUsdc) — Deposits USDC → mints equal YES+NO tokens at $0.50 each
  • mergePositions(conditionId, sharesPerSide) — Burns equal YES+NO → recovers USDC (no-slippage cut-loss)
  • cleanupOpenPositions(clobClient) — On startup, cancels open orders and merges any leftover positions
  • redeemMMPositions() — Periodic redeemer for resolved markets held by the proxy wallet
  • execSafeCall(to, data, description) — Queued Safe transaction executor (serialized to avoid nonce collisions)

Market Maker Detector (src/services/mmDetector.js)

  • Deterministic slot-based lookup using slug format: {asset}-updown-{duration}-{timestamp}
  • Polls Gamma API every MM_POLL_INTERVAL seconds
  • Targets the next upcoming slot (skips the currently active one)
  • Tracks seen market IDs to avoid re-entry

Market Maker Executor (src/services/mmExecutor.js)

  • executeMMStrategy(market) — Full flow: split → place limit sells → monitor → cut-loss/redeem
  • monitorAndManage(...) — Watches for fill events; triggers cut-loss when MM_CUT_LOSS_TIME is reached
  • cutLoss(...) — Cancels remaining orders; merges back or market-sells residual tokens
  • attemptRecoveryBuy(...) — Optional directional bet post cut-loss (controlled by MM_RECOVERY_BUY)

Sniper Detector (src/services/sniperDetector.js)

  • Scans for 5-minute markets for a configurable list of assets
  • Checks both current and next upcoming slots
  • Skips markets with fewer than 30 seconds remaining

Sniper Executor (src/services/sniperExecutor.js)

  • executeSnipe(market) — Places two GTC BUY orders (one YES, one NO) at SNIPER_PRICE
  • Tracks placed orders in memory for display in the terminal UI
  • Total cost per market = SNIPER_PRICE × SNIPER_SHARES × 2

Dashboard UI (src/ui/dashboard.js)

  • Built with blessed — two-panel terminal layout
  • Left panel: event log (color-coded, auto-scrolling)
  • Right panel: live positions, balance, and bot status
  • Handles Ctrl+C and q for graceful shutdown

Logger (src/utils/logger.js)

  • logger.info(), logger.success(), logger.warn(), logger.error()
  • logger.trade(), logger.watch(), logger.money()
  • Outputs to console (with ANSI colors) or blessed dashboard markup

State (src/utils/state.js)

  • readState(filename) — Read a JSON file from data/; returns {} if missing
  • writeState(filename, data) — Atomic write (temp file + rename) to prevent partial writes

Key API Endpoints

API Base URL Auth Purpose
Gamma API https://gamma-api.polymarket.com None Market metadata, resolution status
Data API https://data-api.polymarket.com None Trader activity, wallet positions
CLOB API https://clob.polymarket.com L2 ECDSA Place, cancel, and query orders
RTDS WebSocket wss://ws-live-data.polymarket.com None Real-time trade event stream
Polygon RPC Configurable via POLYGON_RPC_URL None On-chain reads and Safe tx submission

Contract Addresses (Polygon Mainnet)

Contract Address
CTF (ConditionalTokens) 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045
Neg Risk CTF 0xC5d563A36AE78145C45a50134d48A1215220f80a
USDC.e 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
CTF Exchange 0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E
Neg Risk Exchange 0xC5d563A36AE78145C45a50134d48A1215220f80a

State Files (data/)

This directory is gitignored and created at runtime.

File Structure Purpose
positions.json { [conditionId]: { tokenId, shares, avgBuyPrice, autoSellOrderId, ... } } Active copy-trade positions
processed_trades.json { tradeIds: string[] } Deduplication (max 500 entries, FIFO eviction)
sim_stats.json { buys, wins, losses, totalPnl, ... } Simulation performance statistics

Order Types

Type Code Used for
Fill-or-Kill FOK Market buys and sells (copy trade)
Good-Til-Cancelled GTC Auto-sell limits, MM limit sells, sniper orders

Tick Sizes

Valid limit order prices must align to one of these tick sizes: 0.1, 0.01, 0.001, 0.0001. The tick size for each market is returned by the CLOB API and respected in executor.js and autoSell.js.


Known Limitations

  • No partial fill tracking — market buy retries treat each attempt as all-or-nothing (FOK)
  • Redeem requires MATIC — on-chain CTF redemption costs gas; keep EOA funded
  • MM bot requires a Gnosis Safe proxy wallet — EOA-only wallets are not supported for the MM bot
  • Data API response shape varies — the code handles multiple known field name conventions but new API changes may require updates

Development Tips

  • Use npm run dev, npm run mm-dev, or npm run sniper-dev for auto-reload during development
  • nodemon is configured to ignore data/*.json to avoid unnecessary restarts on state updates
  • All console.log usage is replaced by logger.* — keep it consistent
  • When adding a new service, export functions individually and import by name; avoid default-export classes
  • The Safe transaction queue (_txQueue in ctf.js) is critical — never bypass it or nonce collisions will cause transaction failures