feat: maker rebate MM — HFT market-making with spread capture on 15m markets

- Place simultaneous maker limit BUY on YES+NO sides (combined ≈ $0.98)
- Merge filled pairs via CTF contract → capture spread as profit
- WebSocket RTDS real-time fill detection + onchain balance as source of truth
- No aggressive repricing when one side is filled (prevents double exposure)
- Stop re-entry after one-sided stuck cycle (prevents directional accumulation)
- Combined cap always enforced — profitable merge guaranteed
- Auto-queue next market before current closes (zero idle time)
- Remove loss-compensating martingale logic from reprice flow
- Add .env.example with full documentation for all strategies
- Update README with grant-ready project description
This commit is contained in:
direkturcrypto
2026-03-30 21:00:43 +07:00
parent 455f265ed0
commit ef249ad971
11 changed files with 1773 additions and 454 deletions
+131 -120
View File
@@ -1,181 +1,192 @@
# ══════════════════════════════════════════════════════════════════
# polymarket-terminal — Environment Configuration
# Copy this file to .env and fill in your values
# ══════════════════════════════════════════════════════════════════
# ─────────────────────────────────────────────
# WALLET SETUP
# WALLET SETUP (required for all strategies)
# ─────────────────────────────────────────────
# EOA private key — used for SIGNING only, does NOT hold USDC
# EOA private key — used for SIGNING only, does NOT hold funds
# Never share this key or commit it to version control
PRIVATE_KEY=0xYOUR_EOA_PRIVATE_KEY_HERE
# Polymarket Proxy Wallet — the address shown when you click "Deposit" on Polymarket
# This is where you deposit USDC.e, and where trades are funded from
# How to find: Login to polymarket.com → Profile → Deposit → copy the address
# This is where you deposit USDC.e and where all trades are funded from
# How to find: polymarket.com → Profile → Deposit → copy the address
PROXY_WALLET_ADDRESS=0xYOUR_PROXY_WALLET_ADDRESS_HERE
# ─────────────────────────────────────────────
# POLYGON RPC
# ─────────────────────────────────────────────
# Public RPC (default, no key required)
POLYGON_RPC_URL=https://polygon.lava.build
# Alternative RPCs:
# POLYGON_RPC_URL=https://polygon-rpc.com
# POLYGON_RPC_URL=https://rpc.ankr.com/polygon
# ─────────────────────────────────────────────
# POLYMARKET API CREDENTIALS (optional)
# Leave blank to auto-derive from your private key
# Leave blank to auto-derive from your private key on first run
# ─────────────────────────────────────────────
CLOB_API_KEY=
CLOB_API_SECRET=
CLOB_API_PASSPHRASE=
# ─────────────────────────────────────────────
# TRADER TO COPY
# Use the proxy wallet address of the trader (visible on their Polymarket profile)
# PROXY (optional — Polymarket API only, NOT Polygon RPC)
# Supports HTTP, HTTPS, and SOCKS5 proxies
# Leave empty to connect directly
# Example: http://user:pass@proxy.example.com:8080
# ─────────────────────────────────────────────
TRADER_ADDRESS=0xTRADER_PROXY_WALLET_ADDRESS
PROXY_URL=
# ─────────────────────────────────────────────
# TRADE SIZING
# DRY RUN — simulate without placing real orders
# Always test with DRY_RUN=true first!
# ─────────────────────────────────────────────
DRY_RUN=true
# ══════════════════════════════════════════════════════════════════
# MAKER REBATE MM (npm run maker-mm-bot)
# High-frequency market-making on 15m BTC Up/Down markets.
# Places maker limit orders on both YES and NO sides, merges filled
# pairs back to USDC, and captures the bid-ask spread + maker rebate.
# ══════════════════════════════════════════════════════════════════
# Assets to market-make (comma-separated slugs: btc, eth, sol, xrp)
MAKER_MM_ASSETS=btc
# Market duration to target: "5m" or "15m"
MAKER_MM_DURATION=15m
# Number of shares per side per cycle (minimum 5)
# Total USDC deployed per cycle ≈ MAKER_MM_TRADE_SIZE × combined_price
MAKER_MM_TRADE_SIZE=5
# Maximum combined bid (YES + NO) — controls spread profit
# $0.98 combined = $0.02 profit per share when both fill
# Lower = more profit per pair but lower fill rate (e.g. 0.95 = $0.05/share)
MAKER_MM_MAX_COMBINED=0.98
# Reprice check interval (seconds) — how often to check for bid drift
MAKER_MM_REPRICE_SEC=10
# Minimum bid drift (in dollars) before repricing — prevents over-trading
# Default 0.02 = only reprice if best bid moved more than 2 cents
MAKER_MM_REPRICE_THRESHOLD=0.02
# Seconds before market close to force-exit open positions (cut-loss)
MAKER_MM_CUT_LOSS_TIME=60
# Max seconds after market open to enter (entry window)
# After this window, bot waits for the next market
MAKER_MM_ENTRY_WINDOW=45
# How often to poll for new markets (seconds)
MAKER_MM_POLL_INTERVAL=5
# Delay between re-entry cycles within the same market (seconds)
MAKER_MM_REENTRY_DELAY=30
# Price range for maker rebate eligibility (both sides must be in range)
# Polymarket rebates are earned on orders within ~30-70% range
MAKER_MM_MIN_PRICE=0.30
MAKER_MM_MAX_PRICE=0.69
# ── Current Market Entry (optional) ─────────────────────────────
# Allow entering markets that are already in progress
# Useful for catching mid-market opportunities
CURRENT_MARKET_ENABLED=true
# Maximum odds (% as decimal) to allow entry into a running market
# 0.70 = skip if either YES or NO is above 70%
CURRENT_MARKET_MAX_ODDS=0.70
# ══════════════════════════════════════════════════════════════════
# COPY TRADER (npm run bot)
# Mirrors trades from a target trader's Polymarket wallet.
# ══════════════════════════════════════════════════════════════════
# Proxy wallet address of the trader to copy
# Visible on their Polymarket profile URL
TRADER_ADDRESS=0xTRADER_PROXY_WALLET_ADDRESS
# ── Trade Sizing ─────────────────────────────────────────────────
# SIZE_MODE:
# "percentage" = SIZE_PERCENT% of MAX_POSITION_SIZE per market entry
# (e.g. MAX_POSITION_SIZE=$10, SIZE_PERCENT=50 → buy $5 per entry)
# "percentage" = SIZE_PERCENT% of MAX_POSITION_SIZE per entry
# "balance" = SIZE_PERCENT% of your current USDC.e balance per entry
# (e.g. balance=$100, SIZE_PERCENT=10 → buy $10 per entry)
# Note: sizing is independent of the trader's individual fill size.
# Limit orders can fill in many small chunks — we always use our own sizing.
SIZE_MODE=balance
SIZE_PERCENT=10
# Minimum trade size in USDC (skip if calculated size is below this)
MIN_TRADE_SIZE=1
# Maximum total position per market in USDC (won't buy more once this is reached)
# Maximum total USDC position per market
MAX_POSITION_SIZE=10
# ─────────────────────────────────────────────
# AUTO SELL
# ─────────────────────────────────────────────
# ── Auto Sell ────────────────────────────────────────────────────
AUTO_SELL_ENABLED=true
AUTO_SELL_PROFIT_PERCENT=10
# Sell mode when copying trader's sell
# "market" = sell at market price immediately
# "market" = sell immediately at market price
# "limit" = place limit order at trader's sell price
SELL_MODE=market
# ─────────────────────────────────────────────
# INTERVALS
# ─────────────────────────────────────────────
# How often (seconds) to check for resolved markets to redeem
# ── Intervals ────────────────────────────────────────────────────
REDEEM_INTERVAL=60
# Skip BUY if the market closes within this many seconds from now
# Default 300 = skip if market ends in less than 5 minutes
MIN_MARKET_TIME_LEFT=300
# When FAK finds no liquidity (e.g. copying into "next market" before it opens),
# fall back to a GTC limit order and wait this many seconds for it to fill.
# Set to 0 to disable the GTC fallback entirely.
GTC_FALLBACK_TIMEOUT=60
# ─────────────────────────────────────────────
# DRY RUN (set true to simulate without real trades)
# ─────────────────────────────────────────────
DRY_RUN=true
# ─────────────────────────────────────────────
# MARKET MAKER (mm.js / npm run mm-sim)
# ─────────────────────────────────────────────
# Comma-separated assets to market-make (same slug format as sniper)
MM_ASSETS=btc
# ══════════════════════════════════════════════════════════════════
# ORDERBOOK SNIPER (npm run sniper)
# Places 3-tier GTC limit buy orders at panic-dump price levels.
# ══════════════════════════════════════════════════════════════════
# Market duration: "5m" (5-minute) or "15m" (15-minute)
MM_DURATION=5m
# USDC amount per side (total exposure = 2x this)
MM_TRADE_SIZE=5
# Limit sell price target (e.g. 0.60 = sell at $0.60)
MM_SELL_PRICE=0.60
# Seconds before market close to trigger cut-loss
MM_CUT_LOSS_TIME=60
# Keyword to match market question (case-insensitive)
MM_MARKET_KEYWORD=Bitcoin Up or Down
# Max seconds after market open to enter (0 = at open only)
MM_ENTRY_WINDOW=45
# How often to poll for new markets (seconds)
MM_POLL_INTERVAL=10
# ── Recovery Buy (after cut-loss) ───────────────────────────
# After cut-loss triggers, monitor prices for 10s and market-buy
# the dominant side if criteria are met. Does not affect the main
# MM flow — purely an opt-in add-on.
#
# Enable recovery buy
MM_RECOVERY_BUY=false
# Minimum price the dominant side must be at (and rising/stable) to qualify
MM_RECOVERY_THRESHOLD=0.70
# USDC size for the recovery buy (0 = use MM_TRADE_SIZE)
MM_RECOVERY_SIZE=0
# Enable adaptive CL when one leg fills (true = patient limit orders, false = immediate market sell)
MM_ADAPTIVE_CL=true
# Minimum combined sell price (both legs) required to place a limit order.
# Formula: filledLegPrice + unfilledLegPrice >= MM_ADAPTIVE_MIN_COMBINED
# Example: filledLeg=0.60, MM_ADAPTIVE_MIN_COMBINED=1.20 → floor=0.60 (won't limit-sell below $0.60)
# filledLeg=0.55, MM_ADAPTIVE_MIN_COMBINED=1.20 → floor=0.65
# If price is below floor, bot waits for recovery. Market-sell only at CL time as last resort.
MM_ADAPTIVE_MIN_COMBINED=1.20
# Poll interval (seconds) for the adaptive CL loop after one leg fills.
# Smaller = more responsive to price changes, more API calls.
MM_ADAPTIVE_MONITOR_SEC=5
# ─────────────────────────────────────────────
# ORDERBOOK SNIPER (sniper.js / npm run sniper-sim)
# 3-Tier Strategy: Places GTC BUY orders at 3 prices with weighted sizing
# Tier 1 (3c): smallest size | Tier 2 (2c): medium | Tier 3 (1c): largest
# Catches panic dumps at multiple price levels with optimal capital allocation
# ─────────────────────────────────────────────
# Comma-separated assets to snipe
SNIPER_ASSETS=eth,sol,xrp
# 3-Tier pricing (high to low)
SNIPER_TIER1_PRICE=0.03 # Highest price, smallest allocation (20%)
SNIPER_TIER2_PRICE=0.02 # Mid price, medium allocation (30%)
SNIPER_TIER3_PRICE=0.01 # Lowest price, largest allocation (50%)
# 3-Tier pricing (descending) — orders placed at these prices
SNIPER_TIER1_PRICE=0.03
SNIPER_TIER2_PRICE=0.02
SNIPER_TIER3_PRICE=0.01
# Max total shares per side (min 5 shares per tier)
# Example: 15 shares → 3@3c + 5@2c + 7@1c
# Example: 30 shares → 6@3c + 9@2c + 15@1c
# Max total shares to deploy (split across tiers: 20% / 30% / 50%)
SNIPER_MAX_SHARES=15
# ── Sniper Sizing Multiplier (UTC+8) ───────────────────────
# Time-based bet sizing multiplier. Format: HH:MM-HH:MM:factor,...
# Multiplies SNIPER_MAX_SHARES during the specified time windows.
# Default = 1.0x outside any window.
# Example: US afternoon bump + Asia morning discount
# Time-based sizing multiplier (UTC+8). Format: HH:MM-HH:MM:factor,...
SNIPER_MULTIPLIERS=21:00-00:00:1.41,06:00-12:00:0.85
# ── Sniper Pause After Win ─────────────────────────────────
# Number of 5-min rounds to pause an asset after a win is detected.
# Set to 0 to disable.
# Rounds to pause an asset after detecting a win (5-min intervals)
SNIPER_PAUSE_ROUNDS_AFTER_WIN=3
# ── Sniper Session Schedule (all times UTC+8) ──────────────
# Format: HH:MM-HH:MM,HH:MM-HH:MM (comma-separated sessions)
# Assets without a schedule entry are always active.
# Active session schedules per asset (UTC+8). Format: HH:MM-HH:MM,...
SNIPER_SCHEDULE_BTC=19:40-22:40,03:40-06:10
SNIPER_SCHEDULE_ETH=11:40-15:40,16:40-19:40
SNIPER_SCHEDULE_SOL=09:40-12:40,21:40-23:40
SNIPER_SCHEDULE_XRP=18:40-20:40,08:40-09:50
# ─────────────────────────────────────────────
# PROXY (Polymarket API only, NOT Polygon RPC)
# Supports HTTP/HTTPS/SOCKS5 proxies
# Leave empty to connect directly (no proxy)
# Example: http://user:pass@proxy.example.com:8080
# ─────────────────────────────────────────────
PROXY_URL=
# ══════════════════════════════════════════════════════════════════
# CLASSIC MARKET MAKER (npm run mm-bot)
# Legacy MM strategy using limit sell orders after one leg fills.
# ══════════════════════════════════════════════════════════════════
MM_ASSETS=btc
MM_DURATION=5m
MM_TRADE_SIZE=5
MM_SELL_PRICE=0.60
MM_CUT_LOSS_TIME=60
MM_MARKET_KEYWORD=Bitcoin Up or Down
MM_ENTRY_WINDOW=45
MM_POLL_INTERVAL=10
MM_RECOVERY_BUY=false
MM_RECOVERY_THRESHOLD=0.70
MM_RECOVERY_SIZE=0
MM_ADAPTIVE_CL=true
MM_ADAPTIVE_MIN_COMBINED=1.20
MM_ADAPTIVE_MONITOR_SEC=5