This repo contains a latency-aware backtesting engine for the Polymarket event:
Will Elon Musk post X tweets from Jan 27 to Feb 3, 2026?
The repo now also contains convert strategy research, live convert services, and crypto arbitrage engines. For the active design-doc set, use /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/docs/README.md. Historical probability-websocket docs were moved under /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/docs/archive/20260307/.
You can now run both offline backtests and live paper simulations from one entrypoint:
run_simulation.py- Mode is controlled by JSON config:
mode = offline | live - Data adapters are standalone modules and selected by config:
sources.clob.type = offline_csv | live_clobsources.xtracker.type = offline_csv | live_xtracker
Standalone modules:
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/simulation/clob_data.py/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/simulation/xtracker_data.py
Example configs:
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/simulation_offline.example.json/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/simulation_live.example.json
Run offline:
python3 /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/run_simulation.py \
--config /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/simulation_offline.example.jsonRun live:
python3 /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/run_simulation.py \
--config /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/simulation_live.example.jsonLive mode starts a local dashboard server (default http://127.0.0.1:8787) and updates it every loop.
The live dashboard now shows trigger auditing for each trade lifecycle:
- Buy trigger condition + buy trigger reason (entry)
- Sell trigger condition + sell trigger reason (exit)
- Planned sell conditions for open positions
- Recent entry signal stream with trigger details
Dashboard files:
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/simulation/live_dashboard.py/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/simulation/live_dashboard.html
Live outputs:
live_dashboard_state.jsonlive_closed_trades.csvlive_signals.csv
If your team only needs tweet-driven probability updates (and will handle orderbook execution separately), run the standalone websocket publisher:
python3 /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/run_probability_ws.py \
--config /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/probability_ws.example.jsonConfig:
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/probability_ws.example.json/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/probability_ws.cheap_v0.feb27_mar6.production.json/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/probability_ws.tp_mid_v1.feb27_mar6.production.json/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/probability_ws.no_v0.feb27_mar6.production.json/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/probability_ws.no_v1.feb27_mar6.production.json/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/elon_tweets_feb27_mar6_2026.mapping.csv
Live data sources in this publisher:
- Tweet stream source is configurable:
tweet_source_mode=xtrackerfor direct xTracker pollingtweet_source_mode=twitter_relayfor websocket relay ingest (used in the canonical production config)tweet_source_mode=placeholder_zerofor dry placeholder input
- Tweet count correction uses
xtrackerreconciliation (enabled in the provided configs):- live xTracker polling (
probability_ws.xtracker.poll_interval_seconds) - periodic full-window xTracker backfill/reconciliation (
probability_ws.xtracker.reconciliation.*) - startup historical backfill from xTracker (
startup_backfill=true)
- live xTracker polling (
- Twitter relay websocket source:
probability_ws.twitter_relay(url,keyorkey_env, reconnect/read timeouts) - Polymarket CLOB market websocket (live stream):
probability_ws.polymarket - Event link metadata (display + runtime update):
probability_ws.event_url,probability_ws.event_slug,probability_ws.event_title
Example production command for https://polymarket.com/event/elon-musk-of-tweets-february-27-march-6:
python3 /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/run_probability_ws.py \
--config /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/configs/probability_ws.cheap_v0.feb27_mar6.production.jsonWebsocket payload shape (payload_mode=flat):
{
"market": "0xa5b8958ca1bdd0b7bc09629c49f1c880e6ce214e485066f5a38092a77ba3a400",
"timestamp": "1772150400000",
"event_type": "trade_signal",
"model_version": "cheap_v0",
"token_id": "<token_id>",
"possibility": "0.52"
}Notes:
- Example production configs use:
tweet_source_mode=twitter_relayemit_only_on_twitter_change=trueemit_initial_snapshot=truepayload_include_meta=false
probability_ws.payload_modesupports:batch: one websocket message withsignalsarrayflat: one websocket message per trigger signal (entry/exit)
model_versionis always included at the top level to identify the active production model emitting the signal.probability_ws.possibility_buffersubtracts a safety margin from model YES probabilities before publish, then clamps to[0,1]. Example: model0.54with buffer0.02publishes0.52.- If you prefer not to store relay keys in JSON, set
TWITTER_RELAY_KEYand useprobability_ws.twitter_relay.key_env. - If
payload_include_meta=true, the publisher appends ametaobject with diagnostics. - Open position detection (Polygon RPC):
probability_ws.live_trading_mode=trueis required to activate live on-chain checks.probability_ws.open_position_detection.enabled=trueturns on ERC-1155 balance polling for emitted entry tokens.- Configure RPC + wallet + contract via config or env fallback keys:
rpc_urlorrpc_url_env(for examplePOLYGON_RPC_URL)wallet_addressorwallet_address_enverc1155_contract_addressorerc1155_contract_address_env
- Runtime state includes per-token fields:
entry_fill_confirmed,onchain_balance_raw,onchain_balance_units, andonchain_checked_at_utc.
Publisher outputs:
probability_ws_events.ndjsonprobability_ws_signal_emits.ndjson(persisted trigger signals + metadata for dashboard/API)probability_ws_comparison.ndjson(history snapshots for charts/table drill-down)probability_ws_state.json
Ops dashboard + APIs (enabled in config by probability_ws.dashboard.enabled):
- Dashboard UI:
http://127.0.0.1:8891/- Expected-total chart: model vs market live implied expected tweet count.
- Live table: model probability vs market live probability by range.
- Click a range row to view historical model probability vs market Yes price.
- Live paper trading is server-driven (no client-side heuristics):
- strategy logic mirrors
single_position_best_edge(best-edge candidate scoring, edge/time/tp/sl exits, cooldown, allocation controls) - default entry trigger mode is
Tweet Count Change(entries only when tweet count updates) - dashboard renders backend
paper_tradingstate, including trigger/condition/reason fields and live strategy config values
- strategy logic mirrors
- Event panel: shows current Polymarket event link and allows runtime URL update.
- URL updates are validated against the current service window.
- If event start/end time mismatches configured window, API returns a clear mismatch error.
GET /api/stateGET /api/event-urlPOST /api/event-urlwith JSON body:{ "event_url": "https://polymarket.com/event/<slug>" }GET /api/events?limit=50GET /api/signal-emits?limit=200(persisted emitted trigger signals, model-filtered)GET /api/comparison-history?limit=300GET /api/comparison-latestGET /api/latest-eventGET /api/probabilitiesGET /healthzGET /readyzGET /metrics
Local service management:
chmod +x /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/probability_ws_service.sh
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/probability_ws_service.sh smoke
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/probability_ws_service.sh start
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/probability_ws_service.sh status
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/probability_ws_service.sh logsDeployment wrapper (legacy script name, generic config path):
chmod +x /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/deploy_probability_ws_v1.sh
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/deploy_probability_ws_v1.sh check
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/deploy_probability_ws_v1.sh startDeployment reference:
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/deployment/probability_ws.service.example/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/deployment/LOCAL_PROD_CHECKLIST.md
Remote GCP deploy/update helper:
- Script:
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/remote_probability_ws_v1.sh - Defaults target:
shuo_shan@35.223.123.14, remote repo dir/home/shuo_shan/prediction_market_arbitrage - First-time deploy (sync + validate + start):
chmod +x /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/remote_probability_ws_v1.sh
bash /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/remote_probability_ws_v1.sh deploy- Code update + service restart:
bash /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/remote_probability_ws_v1.sh update- Service status / logs:
bash /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/remote_probability_ws_v1.sh status
bash /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/scripts/remote_probability_ws_v1.sh logsThe helper rewrites path-bound config values into a remote config copy (configs/probability_ws.example.remote.json) and defaults dashboard host to 0.0.0.0 for external access on port 8891.
-
elon_tweet_backtest.py- Supports two filter modes:
strict: keep only non-replies + replies to@elonmusk.tracker_proxy: keep all non-replies, then include the highest-view replies until reaching a target count (optionally fetched from XTracker tracking stats).
- Aligns to UTC and ET event window.
- Supports service-latency modeling:
fixed,uniform,mixture(fast 2-5s with occasional slow spikes), or per-row latency column.
- Supports XTracker-lag-aware execution constraints:
- minimum latency advantage, pre-importedAt entry requirement, and importedAt-anchored exits.
- Builds a Bayesian count model (
Gamma-Poisson) for fair range probabilities. - Runs event-study metrics around each filtered tweet.
- Simulates trading with configurable latency, edge threshold, and risk controls.
- Entry-selection anti-bias controls (latency/legacy):
--candidate-score-mode EDGE|ROI|ZSCORE|NET_EDGE(NET_EDGE= edge minus approx round-trip cost)--selection-mode max_edge|random_top_k--selection-top-k,--selection-random-seed--entry-edge-uncertainty-penalty--min-entry-zscore--min-edge-cost-ratio
- Supports a research replication mode:
--strategy-mode single_position_best_edge--expected-model improved|v1|latency_v1- optional seasonality/prior controls:
--use-hourly-seasonality-et--use-weekday-seasonality-et(default OFF; current estimate is not leakage-free)--prior-mean-rate-per-hour--prior-strength-hours--seasonality-factorized-json(used bylatency_v1)
- single-position controls:
--entry-edge-th,--exit-edge-th,--max-hold-seconds,--cooldown-seconds--exit-eval-tick-seconds(evaluate exits on wall-clock ticks between tweets; fixes "tweets stopped so we never time-exited")--flatten-seconds-before-end(optional forced flatten before--window-end-et)--exit-edge-confirm-events(hysteresis edge exits)--cooldown-scope,--cooldown-after-exit-mode--core-top-k,--core-exit-rank-cutoff,--core-exit-edge-th,--core-disable-tp-sl,--core-enable-tp-sl--position-fraction,--min-price,--max-price,--cost-tick--tp-ret,--sl-ret
- Supports an alternative latency trigger model:
--strategy-mode latency --expected-model latency(legacy) orlatency_v1(factorized seasonality)- entry: highest-edge bin before xTracker importedAt (with latency-advantage + pre-xtracker gating)
- exit: sell on
xtracker_updateusing--xtracker-exit-delay-secondsas the exit knob - defaults to single-position/high-frequency behavior (
max_open_positions=1,max_new_trades_per_event=1) v1applies safer defaults for late sensitivity when those knobs are unset:entry_edge_th=0.10,exit_edge_th=0.02,exit_edge_confirm_events=2cooldown_scope=per_label,cooldown_after_exit_mode=losing_onlycore_top_k=2,core_exit_rank_cutoff=3,core_disable_tp_sl=true
- optional range-token remap from trigger logs:
--range-token-overrides-csv <path>(repeatable)
- Supports two filter modes:
-
sweep_backtest_params.py- Runs grid sweeps across strategy parameters.
- Saves ranked results so you can pick a best-performing configuration.
-
search_high_winrate_strategy.py- Focused grid search for robust overall performance.
- Supports strategy controls:
yes-focus-bin-radius(e.g., +/- 2 bins around model mode for BUY_YES)- silence-driven
BUY_NOentries on higher-count bins - long hold windows with
stop-loss-pctandtake-profit-pct - silence exit controls:
- near-1.0 take profit (
silence-take-profit-near-one-price, default0.98) - market scope for silence entries (
offset_range,all_above_mode,all_bins)
- near-1.0 take profit (
- Sorts and exports configs by configurable objective:
pnl(raw total pnl)pnl_drawdown(total pnl minus drawdown penalty)
python3 /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/elon_tweet_backtest.py \
--tweets /Users/arthurmeng/Downloads/elonmusk_tweets.csv \
--trades /Users/arthurmeng/Downloads/elonmusk_market_trades.csv \
--mapping /Users/arthurmeng/Downloads/elonmust_tweets_markets.csv \
--output-dir /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/output_elon_backtest \
--filter-mode tracker_proxy \
--xtracker-tracking-id a9e9a6cb-a61a-425b-ab38-24d1576409f3 \
--latency-mode uniform \
--latency-min-seconds 2 \
--latency-max-seconds 5python3 /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/elon_tweet_backtest.py \
--tweets /Users/arthurmeng/Downloads/elonmusk_tweets.csv \
--trades /Users/arthurmeng/Downloads/elonmusk_market_trades.csv \
--mapping /Users/arthurmeng/Downloads/elonmust_tweets_markets.csv \
--range-token-overrides-csv /Users/arthurmeng/Documents/winning_strategy_trade_triggers_conservative.csv \
--range-token-overrides-csv /Users/arthurmeng/Documents/winning_strategy_trade_triggers_best_final_cash.csv \
--output-dir /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/output_repro_research_conservative_from_csvs \
--filter-mode tracker_proxy \
--target-count 350 \
--latency-mode fixed \
--latency-seconds 2 \
--strategy-mode single_position_best_edge \
--expected-model v1 \
--use-hourly-seasonality-et \
--use-weekday-seasonality-et \
--prior-mean-rate-per-hour 2.0 \
--prior-strength-hours 24.0 \
--entry-edge-th 0.15 \
--exit-edge-th 0.10 \
--max-hold-seconds 43200 \
--cooldown-seconds 21600 \
--position-fraction 0.25 \
--tp-ret 0.3 \
--sl-ret 0.3 \
--min-price 0.02 \
--max-price 0.98 \
--cost-tick 0.001 \
--total-funding 1000python3 /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/elon_tweet_backtest.py \
--tweets /Users/arthurmeng/Downloads/xtracker_elonmusk_posts_2026-01-27_2026-02-03.csv \
--trades /Users/arthurmeng/Downloads/elonmusk_market_trades.csv \
--mapping /Users/arthurmeng/Downloads/elonmust_tweets_markets.csv \
--output-dir /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/output_elon_backtest_xtracker_advantage_nolookahead_v2 \
--latency-mode mixture \
--latency-min-seconds 2 \
--latency-max-seconds 5 \
--latency-slow-seconds 30 \
--latency-slow-prob 0.08 \
--expected-xtracker-lag-seconds 160 \
--min-latency-advantage-seconds 150 \
--enforce-pre-xtracker-entry \
--xtracker-entry-buffer-seconds 2 \
--use-xtracker-exit \
--xtracker-exit-delay-seconds 45for d in 0 10 20 30 60; do
python3 /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/elon_tweet_backtest.py \
--tweets /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/verification/market_tweets_data_184874_20260213/event_184874/tweets_xtracker.csv \
--trades /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/verification/market_tweets_data_184874_20260213/event_184874/market_trades.csv \
--mapping /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/verification/market_tweets_data_184874_20260213/event_184874/market_mapping.csv \
--output-dir /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/verification/latency_model_event184874_exit_sweep/delay_${d} \
--filter-mode strict \
--latency-mode fixed \
--latency-seconds 2 \
--strategy-mode latency \
--expected-model latency \
--entry-edge-th 0.03 \
--min-latency-advantage-seconds 1 \
--xtracker-entry-buffer-seconds 1 \
--xtracker-exit-delay-seconds ${d} \
--hold-seconds 600 \
--capital-per-trade 100 \
--total-funding 1000
donetweets_all_labeled.csvtweets_filtered.csvmarket_bins.csvevent_study.csvbacktest_trades.csvsummary.jsonparameter_sweep.csv/parameter_sweep.json(from sweep script)
python3 /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/search_high_winrate_strategy.py \
--tweets /Users/arthurmeng/Downloads/elonmusk_tweets.csv \
--trades /Users/arthurmeng/Downloads/elonmusk_market_trades.csv \
--mapping /Users/arthurmeng/Downloads/elonmust_tweets_markets.csv \
--output-dir /Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/output_strategy_search_overall \
--filter-mode tracker_proxy \
--target-count 350 \
--edge-thresholds 0.08,0.12 \
--hold-seconds-list 86400,172800 \
--stop-loss-pct-list 0.12,0.2 \
--take-profit-pct-list 0.2,0.3,0.4 \
--yes-focus-bin-radius-list none \
--objective pnl_drawdown \
--drawdown-penalty 1.0- Conservative:
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/output_repro_research_conservative_from_csvs - Aggressive:
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/output_repro_research_aggressive_from_csvs - Best final cash:
/Users/arthurmeng/Documents/smart_money_polymarket/prediciton_market_arbitrage/output_repro_research_best_final_cash_from_csvs