Тема
Harvester ASK-side liquidity research — 2026-05-06
Question
For a resting BUY at price ≤ 0.95 (typical harvester entry — DIRECTIONAL_MAX_ENTRY_PRICE=0.98, DIRECTIONAL_MIN_ENTRY_PRICE=0.97, DIRECTIONAL_ENTRY_PRICE_BASE=best-bid, +1¢ offset → real fill price clusters 0.94–0.98), how often did the captured order books actually offer matching ask liquidity? What entry knobs would translate to non-zero fill probability?
Method
Custom Rust binary crates/pm-analytics/src/bin/book_depth_analyzer.rs:
- Streams
ws_market.jsonl.zstframe-by-frame (multi-frame zstd, no whole-file load). - Per asset_id, reconstructs ASK orderbook from
WsBookSnapshot(full replace) +WsBookDeltaside=Sell (per-level mutate). - At every book mutation, computes cumulative depth at price ≤ {0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99}.
- Accumulates per-asset stats: max depth, mean depth when present, fillable-time = cumulative seconds when depth ≥
DIRECTIONAL_MIN_SIZE_SHARES=5. - Time-delta cap = 60 s/sample (one-shot long gaps shouldn't inflate counts).
Two independent capture sessions analysed (different days, different active markets):
| Session id | ws_market size | frames | unique assets | span |
|---|---|---|---|---|
1778021322240182207-directional | 596 MB | 34,036,133 | 4,259 | ~9.7 h |
1778073881466125560-directional | 186 MB | 10,522,205 | 1,292 | ~3.5 h |
Total: ~13 h of live Polymarket WS book traffic, ~5,500 unique assets touched.
Headline finding
Harvester at price ≤ 0.95 will almost never fill. Across 13 h of book history covering 5,551 assets:
| Threshold | Session A fillable hrs | Session B fillable hrs | A: % assets ever fillable | B: % assets ever fillable |
|---|---|---|---|---|
| ≤ 0.93 | 0.007 | 0.000 | 0.5% | 0.4% |
| ≤ 0.94 | 0.007 | 0.000 | 0.6% | 0.4% |
| ≤ 0.95 | 0.010 | 0.006 | 0.7% | 0.8% |
| ≤ 0.96 | 0.021 | 0.016 | 0.9% | 1.5% |
| ≤ 0.97 | 0.088 | 0.094 | 1.6% | 3.4% |
| ≤ 0.98 | 0.184 | 0.219 | 2.1% | 5.6% |
| ≤ 0.99 | 0.261 | 0.328 | 3.0% | 7.4% |
Read this row by row:
- At ≤ 0.95: across all 4259 assets in session A there were 37 cumulative seconds of fillable depth — that's the entire window in which any harvester order at ≤0.95 could have transacted with the visible ask side. Median market sees 0 seconds.
- Each step up (0.95 → 0.96 → 0.97) doubles or triples both the asset-coverage and the cumulative time. The flow lives between 0.97 and 0.99, not below 0.95.
- The single-asset depth distribution (full table in
harvester-depth-1778021322.md) shows that when liquidity does appear, it tends to be substantial (mean depth 50–1044 shares when present); it just appears for sub-second flashes.
Implications for strategy knobs
What would NOT work
DIRECTIONAL_MAX_ENTRY_PRICE=0.95withentry_price_base=best-bid + 1¢→ place at ~0.94, hope ask drops to 0.94: probability ≈ 0.5–0.7% of assets ever, median 0 seconds per asset. Confirms the production observation: bot places ~50 orders, sits in spread, fills 0 in hours.DIRECTIONAL_MAX_ENTRY_PRICE=0.95+entry_mode=market(cross book): would fill instantly, but at ~0.97 ask → out-of-bounds at themax_entry_pricefilter → still rejected atevaluate_signalstep.entry_price_base=best-ask− 1¢ at the existing 0.95 cap: same problem — the −1¢ improvement still has to land at ≤ 0.95.
What COULD work
DIRECTIONAL_MAX_ENTRY_PRICE=0.99— opens the window where ~3-7% of assets show fillable depth. ~0.3 asset-hours per 10 h of capture = roughly 1 fill per asset per few hours of typical market. Realistic floor for a harvester to actually transact.entry_mode=market+MAX_ENTRY_PRICE=0.99— taker fills at best_ask which is mostly in 0.97–0.99 range. Eats ~1¢ slippage vs 0.97 mid but guarantees execution. Subtract Polymarket taker fee (the active fee table — verify viaclob_client::get_market; this analysis does not derive PnL).- Price-base shift to
best-ask− 0¢ (post_only=true) — improver order, joins the spread on the buy side, more likely to attract aggressive sellers when ask retreats. Still subject to depth window.
Subtle: depth distribution shape
When fillable depth appears at ≤ 0.95, it's not "1 share at 0.95, fills our 5-share order partially". The mean depth when present is 50–1044 shares (many top assets show >1000 max). This means: when the window opens it opens for substantial volume, just briefly. A taker order would consume a lot; a passive maker rarely sees the window persist long enough to be hit.
The capture frame rate (sub-second, 34M snapshots over 10 h ≈ 1 frame per ms on average) means we can resolve sub-second windows. The ~0.01 asset-hours total of fillable depth at ≤ 0.95 across 4259 assets = about 30 seconds spread across 30 markets per 10 hours, i.e. each "fillable window" is on the order of seconds, opening a few times per market per day.
Recommendation
Three concrete tests to escalate:
- Knob raise:
DIRECTIONAL_MAX_ENTRY_PRICE=0.99,MIN_ENTRY_PRICE=0.97,entry_price_base=best-bid,+1¢,post_only=true. Run a capture session, replay, count fills. Expectation: 1-3 fills per asset per 24 h, modest PnL footprint per fill (high probability outcomes have low PnL margin). - Market-cross knob:
entry_mode=market,MAX_ENTRY_PRICE=0.99. Replay, measure slippage. Expectation: every admitted candidate fills at ~best_ask = 0.97-0.99 immediately. Lose ~1¢ on improvement but guaranteed exec. - Variant C revisit:
entry_price_base=best-ask,offset=-1¢,post_only=truewith the higher cap (0.99). Improver pattern: become the new best_bid by 1¢ above old, attract aggressive sellers. Replay measures hit-rate.
Tests #1 and #2 are config-only — single-variant sweeps via grids/ toml + pm-analytics sweep. Test #3 same.
Caveats / known limitations of this analysis
- Snapshot-only sessions: both sampled sessions show
deltas=0per asset. Polymarket WS market channel emits full snapshots more often than the schema admits incremental deltas — the analyzer correctly treats each snapshot as full replace, but a delta-heavy session would have richer mid-snapshot resolution. Conclusion does not change. - Asset selection bias: capture file contains every asset the bot subscribed to during that session, which is biased toward markets the bot already had orders or candidates on (weather binaries with extreme probabilities). General Polymarket market depth at ≤ 0.95 may differ on, e.g., presidential or sports markets — this analysis does NOT generalise to them.
- No PnL projection: this study measures fill probability under given price-range knobs. Translating "fillable-time" into "expected USD/hour" requires combining with strategy fees, exit-price model, and adverse-selection cost — separate work.
- Time-delta cap of 60 s prevents single-frame gaps from inflating fill-time when a market falls quiet. Sessions with longer typical between-snapshot gaps would under-count proportionally; the cap is conservative.
Reproduce
sh
cargo build -p pm-analytics --bin book-depth-analyzer
scp target/debug/book-depth-analyzer deploy@<vps>:/tmp/
ssh deploy@<vps> '
sudo /tmp/book-depth-analyzer \
--captures-root ~/pm-backtest/instances/<instance>/data/captures \
--session <session_id> \
--thresholds 0.93,0.94,0.95,0.96,0.97,0.98,0.99 \
--reference 0.95 \
--min-fill-size 5
'The binary is sized ~350 MB (debug). Production-friendly version would build with --release (~25 MB) when the run is recurring.
Artefacts
harvester-depth-1778021322.md— Session A full report (top-30 assets + aggregate).harvester-depth-1778073881.md— Session B full report.