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>
Previous behaviour: enter any side with positive momentum, exit at TP (+1 tick),
cycle back to IDLE — causing rapid buy-sell-buy loops on low-probability tokens.
New strategy:
- Enter ONLY the side the market already prices as probable winner (mid >= MIN_DOMINANT_MID)
- Hold position to market expiry; on-chain redeemer settles at $1.00 win / $0.00 loss
- Emergency stop-loss only (absolute mid floor, e.g. 0.20) for catastrophic reversals
- One entry per market slot — no re-entry while POSITION_OPEN
Key changes:
- SignalEngine: detect dominant side (up.mid vs down.mid), require MIN_DOMINANT_MID
threshold, new scoring weights (mid 45% / imbalance 35% / spread 20%)
- PositionEngine: remove TP, slope-drop, time-reduce exits; add expired handler;
stop-loss is now an absolute mid floor instead of relative-to-entry ticks
- oneshot.js: expirePosition() clears state without submitting sell orders;
flattenPosition() only called for emergency stops; update cfg vars
- constants.js: add SIG_NO_DOMINANT, SIG_LOW_DOMINANT, EXIT_EXPIRED reason codes
- .env.example: replace ONESHOT_TP_TICKS with MIN_DOMINANT_MID, STOP_LOSS_MID,
TTE_MIN, TTE_MAX
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a debug flag (ONESHOT_DEBUG=true / --debug / npm run oneshot-debug)
that surfaces the engine's internal decision process at every key step.
Debug output tags
─────────────────
[DBG:FEED] — Market discovery: every slug probed, API response status,
token IDs extracted, tick size fetched.
Throttled poll summary every 10 ticks per market showing
bid/ask/spread/mid/depth for both UP and DOWN sides.
[DBG:GATE] — Hard gate result every 5 evaluations per market:
TTE range, spread width, depth thinness, stale flag.
Shows exact gate fail reason or PASS confirmation.
[DBG:FEAT] — Feature breakdown for each side every 5 evals:
slope, imbalance, spread, retrace raw values plus
per-component scores and weighted total.
[DBG:SCORE] — Per-side qualify check: score vs threshold,
trend confirm flag, and QUALIFY / skip verdict.
[DBG:SIGNAL] — Always logged (no throttle) when an ENTER signal fires.
[DBG:HEART] — 5-second heartbeat: active markets, per-market SM state,
dailyPnl, consecLosses, cooldownLeft, halted flag.
New script
──────────
npm run oneshot-debug → DRY_RUN=true ONESHOT_DEBUG=true node src/oneshot.js
Co-Authored-By: direkturcrypto <direkturcrypto.x@mail3.me>
- 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>