When a position's market expires, RedeemEngine automatically polls the CTF contract and redeems the winning position on-chain — no manual redeem needed. Flow: 1. expirePosition() queues the expired position into RedeemEngine 2. RedeemEngine polls every 30s (ONESHOT_REDEEM_POLL_MS) 3. Checks Gamma API first, then CTF.payoutDenominator() on-chain 4. When settled: emits redemption:complete event with final P&L 5. Orchestrator passes P&L to RiskEngine DRY_RUN=true: simulates by reading on-chain payouts and logging win/loss DRY_RUN=false: submits real redeemPositions() tx on Polygon (gasLimit 300k) Also stores conditionId and negRisk in PositionEngine state so the expired position has all data needed for redemption without extra lookups. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
199 lines
9.4 KiB
Bash
199 lines
9.4 KiB
Bash
# ─────────────────────────────────────────────
|
||
# WALLET SETUP
|
||
# ─────────────────────────────────────────────
|
||
# EOA private key — used for SIGNING only, does NOT hold USDC
|
||
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
|
||
PROXY_WALLET_ADDRESS=0xYOUR_PROXY_WALLET_ADDRESS_HERE
|
||
|
||
# ─────────────────────────────────────────────
|
||
# POLYGON RPC
|
||
# ─────────────────────────────────────────────
|
||
POLYGON_RPC_URL=https://polygon.lava.build
|
||
|
||
# ─────────────────────────────────────────────
|
||
# POLYMARKET API CREDENTIALS (optional)
|
||
# Leave blank to auto-derive from your private key
|
||
# ─────────────────────────────────────────────
|
||
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)
|
||
# ─────────────────────────────────────────────
|
||
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)
|
||
# "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)
|
||
MAX_POSITION_SIZE=10
|
||
|
||
# ─────────────────────────────────────────────
|
||
# AUTO SELL
|
||
# ─────────────────────────────────────────────
|
||
AUTO_SELL_ENABLED=true
|
||
AUTO_SELL_PROFIT_PERCENT=10
|
||
|
||
# Sell mode when copying trader's sell
|
||
# "market" = sell at market price immediately
|
||
# "limit" = place limit order at trader's sell price
|
||
SELL_MODE=market
|
||
|
||
# ─────────────────────────────────────────────
|
||
# INTERVALS
|
||
# ─────────────────────────────────────────────
|
||
# How often (seconds) to check for resolved markets to redeem
|
||
REDEEM_INTERVAL=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
|
||
|
||
# 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
|
||
|
||
# ─────────────────────────────────────────────
|
||
# ORDERBOOK SNIPER (sniper.js / npm run sniper-sim)
|
||
# Places tiny GTC BUY orders at a low price on both sides of
|
||
# ETH/SOL/XRP 5-minute markets — catches panic dumps near $0.
|
||
# ─────────────────────────────────────────────
|
||
# Comma-separated assets to snipe
|
||
SNIPER_ASSETS=eth,sol,xrp
|
||
|
||
# Buy price per share (1 cent = $0.01)
|
||
SNIPER_PRICE=0.01
|
||
|
||
# Shares per side — minimum Polymarket order size is 5 shares
|
||
# At $0.01/share: 5 shares = $0.05 per side, $0.10 per market
|
||
SNIPER_SHARES=5
|
||
|
||
# ─────────────────────────────────────────────
|
||
# ONESHOT ENGINE (oneshot.js / npm run oneshot-sim)
|
||
# Dominant Side Hold strategy.
|
||
# Enters ONLY the side that the market already prices as the probable
|
||
# winner (mid >= ONESHOT_MIN_DOMINANT_MID), then holds the position
|
||
# to market expiry for on-chain redemption at $1.00.
|
||
# No take-profit sells. No momentum-based exits.
|
||
# ALWAYS test with DRY_RUN=true before going live.
|
||
# ─────────────────────────────────────────────
|
||
|
||
# Comma-separated assets to monitor (e.g. btc,eth,sol)
|
||
ONESHOT_ASSETS=btc
|
||
|
||
# Market duration: "5m" (5-minute) or "15m" (15-minute)
|
||
ONESHOT_DURATION=5m
|
||
|
||
# Book poll interval in milliseconds (200–500ms recommended)
|
||
ONESHOT_POLL_INTERVAL_MS=300
|
||
|
||
# USDC risk per trade — size = floor(ONESHOT_BASE_RISK_USDC / entryPrice), min 5 shares
|
||
ONESHOT_BASE_RISK_USDC=5
|
||
|
||
# ── Entry filters ──────────────────────────────────────────────────────
|
||
|
||
# Minimum mid price for the dominant side to qualify as an entry candidate.
|
||
# Example: 0.60 means the token must be priced at ≥60% probability of winning.
|
||
# Lower = more trades but more uncertain outcomes. Higher = fewer but more confident.
|
||
ONESHOT_MIN_DOMINANT_MID=0.60
|
||
|
||
# Minimum composite score to trigger entry (0–1).
|
||
# Score is based on: mid price strength (45%), order-book imbalance (35%), spread (20%).
|
||
ONESHOT_SCORE_THRESHOLD=0.55
|
||
|
||
# TTE (time-to-expiry) window in seconds for entry.
|
||
# Only enter when the market is between TTE_MIN and TTE_MAX seconds from closing.
|
||
# Narrowing this window means entering later when direction is clearer.
|
||
ONESHOT_TTE_MIN=20
|
||
ONESHOT_TTE_MAX=90
|
||
|
||
# Minimum shares at the best bid AND best ask for the depth hard gate
|
||
ONESHOT_MIN_TOP_SIZE=10
|
||
|
||
# ── Exit settings ──────────────────────────────────────────────────────
|
||
|
||
# Emergency stop-loss: exit if the token's mid price drops below this absolute level.
|
||
# Protects against a complete market reversal (e.g. entered UP at 0.70, price drops to 0.18).
|
||
# Set to 0 to disable (pure hold-to-expiry — binary win/loss outcome).
|
||
ONESHOT_STOP_LOSS_MID=0.20
|
||
|
||
# ── Risk settings ──────────────────────────────────────────────────────
|
||
|
||
# Number of consecutive emergency exits (losses) before entering cooldown
|
||
ONESHOT_MAX_CONSEC_LOSSES=2
|
||
|
||
# Number of market slots to skip during cooldown
|
||
ONESHOT_COOLDOWN_ROUNDS=3
|
||
|
||
# Maximum cumulative daily loss in USDC before halting all trading
|
||
ONESHOT_DAILY_LOSS_CAP=20
|
||
|
||
# Maximum milliseconds to wait for a FOK fill ack (timeout → cancel → IDLE)
|
||
ONESHOT_FILL_TIMEOUT_MS=800
|
||
|
||
# How often (ms) to poll for on-chain redemption after market expiry.
|
||
# 5m markets typically settle on-chain within 2–5 minutes after close.
|
||
ONESHOT_REDEEM_POLL_MS=30000
|
||
|
||
# Enable verbose debug logging (discovery probes, gate results, scoring, heartbeat)
|
||
# Can also be enabled with: npm run oneshot-debug
|
||
# Or on the command line: ONESHOT_DEBUG=true npm run oneshot
|
||
ONESHOT_DEBUG=false
|