Lɪᴠᴇ Sʜᴏᴡ: https://polymarket.com/@byteano5?tab=activity
DM ᴍᴇ ꜰᴏʀ ɪɴǫᴜɪʀɪᴇs ʀᴇɢᴀʀᴅɪɴɢ ᴘᴜʀᴄʜᴀsᴇ ᴏʀ ɪɴᴠᴇsᴛᴍᴇɴᴛ. Bᴏᴏᴋ ᴀ ᴄᴀʟʟ ʜᴇʀᴇ: https://calendly.com/endovix/30min
This document describes the trading strategy and execution path implemented for short-horizon Polymarket crypto up/down markets (e.g. btc-updown-5m-{epoch_ts}). It excludes Telegram UI, user management, and notifications.
Primary implementation: scripts/test_5m_core.py (_run_one_cycle, main), driven by config/default.yaml under buy_above, entry, execution, and optional synth.
References: src/config.py (BuyAboveConfig, ExecutionConfig, EntryConfig), src/data/slug_builder.py, src/data/clob_ws.py, src/data/orderbook.py, src/execution/clob_client.py, src/execution/limit_buy_tracker.py, src/execution/redeem.py.
- Instrument: One 5-minute Polymarket event per asset (BTC first-class; ETH/XRP/SOL supported via config). Each event has two outcome tokens (Up / Down); the bot tracks both token IDs from Gamma.
- Epoch alignment: Current window is computed in US Eastern for 5m intervals (
POLYMARKET_5M_TIMEZONE), then converted to UTC (compute_epoch_slugs→current_slug,current_start, 300s duration). - Books: Real-time CLOB WebSocket updates feed
InMemoryOrderbookStore; entry logic uses best bid / best ask per outcome token.
There is no identifier named anon-fake in the codebase. Operationally, the live defaults match a near-parity, high-conviction snipe plus immediate liquidity taking on the buy side:
| Idea | How it maps in config/code |
|---|---|
| Trade like a retail-sized account that takes liquidity when the tape is already extreme | execution.buy_order_type: FAK (Fill-And-Kill): market-style buy consumes the book now; unfilled remainder is canceled. Retries on “no match” happen on next book update (test_5m_core.py). |
| Outcome priced around 99¢ (crypto and sports-style binary markets share the same CLOB mechanics) | Entry gate: buy_above.threshold < best_ask < buy_above.threshold_max. Default threshold_max: 0.99 means: do not enter once best_ask >= 0.99 (avoids chasing a fully locked-in 1.00 ask). Fill target: set buy_above.limit_buy_price to 0.99 when using buy_order_style: limit (GTC limit at 0.99 for amount shares). For market path, effective price follows the book; with high best_ask, fills naturally cluster just under the cap implied by threshold_max. |
| Same playbook on other asset classes | Logic is token-agnostic: only asset string, slug, and per-asset CSV / Synth gates differ. |
Practical knobs for a strict “bid 0.99” profile:
buy_above.buy_order_style: limitbuy_above.limit_buy_price: 0.99(and optionallimit_buy_price_stage1for the pre-orderbook_startphase)- Adjust
buy_above.threshold_maxto1.0if you need the orderbook signal to still fire whenbest_askprints 0.99 (otherwise the current>= threshold_maxcheck blocks exactly at 0.99).
Let elapsed = seconds since epoch_start.
| Phase | Condition | Behavior |
|---|---|---|
| Warm-up | elapsed < orderbook_pre_start_offset_seconds |
WS updates apply to the book; no entry evaluation. |
| Pre-stage (optional) | orderbook_pre_start_offset_seconds ≤ elapsed < orderbook_start_offset_seconds |
Entry uses stage-1 CSV thresholds (price_diff_threshold_*_stage1) and stage-1 limit price (limit_buy_price_stage1) when configured. |
| Main tracking | elapsed ≥ orderbook_start_offset_seconds |
Standard CSV thresholds and limit_buy_price. |
| Entry cutoff | elapsed ≥ market_sell_at_elapsed_seconds - entry_stop_before_exit_seconds |
No new entries; existing position handling continues until exit rules fire. |
Defaults (see config/default.yaml): pre-start 240s, orderbook start 270s, exit sweep 310s, entry stop 5s before exit — so tracking is tight to the end of the window.
On each book update (after phase gates), for each outcome token asset_id:
- Skip if a buy already triggered this cycle (
triggered). - Liquidity screen: require
best_ask > thresholdandbest_ask < threshold_max(strict upper bound on ask). - CSV gate (optional): if
price_diff_enabledfor this asset: readlatest_crypto_price.csv(or path from config). Requireabs(difference) > eff_price_diff(stage-1 vs stage-2 threshold). If missing: skip (logged once). - Synth gate (optional): if
synth.enabledand asset is BTC/ETH:read_synth_outcomemust match the token’s outcome label.
If all pass → one buy attempt (then triggered latches; further entries wait for next 5m cycle unless position cleared by exit path).
- Places GTC limit BUY at
eff_limit_buy(limit_buy_priceor stage-1 price) foramountoutcome shares. - Neg-risk: tries
get_neg_risk; on invalid signature, retries withneg_riskoverrides (None,True,False). - Post-fill:
limit_buy_trackerpollsget_order, updates filled shares, and maintains a GTC limit BUY on the opposite outcome atlimit_buy_opposite_price(default 0.01) for hedge sizing ≥min_outcome_order_shares.
- Builds market buy with USDC notional ≈
amount * best_ask. - Order type from
execution.buy_order_type(default config: FAK). - Same neg-risk retry pattern.
- Opposite hedge: after short delay, GTC buy opposite at
limit_buy_opposite_price.
Evaluated on each book tick before new entry logic:
sell_if_below_threshold: ifbest_ask < threshold_min→ cancel resting orders on both tokens, market sell (order typeexecution.sell_order_type, default FAK), optional fee sweep.- Time stop: if
elapsed ≥ market_sell_at_elapsed_seconds→ cancel all open orders on both outcome tokens, then market sell tracked/CLOB balance.
Dry-run: simulates without chain calls; may reset triggered for paper flow.
- Per cycle:
asyncio.gatherovermarkets.enabled_assetsfor the same epoch window. - Redeem: after resolution, wait
redeem_delay_seconds, thenredeem_positions_batch(CTFredeemPositions, optional relayer builder creds). Optional profit-based fee to server address (env-driven) after redeem or sell.
| Area | Key fields |
|---|---|
| Universe | markets.assets, markets.intervals, markets.enabled_assets |
| Timing | entry.orderbook_pre_start_offset_seconds, entry.orderbook_start_offset_seconds |
| Signal | buy_above.threshold, threshold_max, threshold_min, per-asset price_diff_threshold_*, price_diff_enabled_* |
| Size / style | buy_above.amount, buy_order_style, limit_buy_price, limit_buy_price_stage1 |
| Hedge / exit | limit_buy_opposite_price, min_outcome_order_shares, market_sell_at_elapsed_seconds, entry_stop_before_exit_seconds, sell_if_below_threshold |
| Execution | execution.buy_order_type, sell_order_type, signature_type, funder (Gnosis Safe proxy), chain_id, rpc_url |
Environment prefix: POLYBOT5M_ with nested __ for YAML paths (see load_config).
flowchart LR
Gamma[Gamma API slug / event] --> Tokens[Outcome token IDs]
WS[CLOB WebSocket books] --> OB[InMemoryOrderbookStore]
CSV[latest_crypto_price.csv] --> Gate[CSV move gate]
SynthOpt[Synth JSONL optional] --> Gate2[Synth alignment]
OB --> Decision[threshold and gates]
Gate --> Decision
Gate2 --> Decision
Decision --> CLOB[ClobClient orders]
CLOB --> Hedge[Opposite GTC hedge]
CLOB --> Exit[Time / floor market sell]
Resolve[Market resolves] --> Redeem[redeem_positions_batch]
Telegram bot (telegram_bot/), per-user config copies, Mongo trial/premium, API bridge, and balance UI are not part of this HLD; the same test_5m_core logic is what those layers invoke when running the strategy.