wss_market/
wss_market.rs

1use polysqueeze::Result;
2use polysqueeze::client::ClobClient;
3use polysqueeze::errors::PolyError;
4use polysqueeze::types::{GammaListParams, Market};
5use polysqueeze::wss::{WssMarketClient, WssMarketEvent};
6use rust_decimal::Decimal;
7use std::env;
8use std::str::FromStr;
9use std::time::{SystemTime, UNIX_EPOCH};
10
11#[tokio::main]
12async fn main() -> Result<()> {
13    let base_url =
14        env::var("POLY_API_URL").unwrap_or_else(|_| "https://clob.polymarket.com".to_string());
15    let clob = ClobClient::new(&base_url);
16
17    let min_liquidity = env::var("POLY_WSS_MIN_LIQUIDITY")
18        .ok()
19        .and_then(|value| Decimal::from_str(&value).ok())
20        .unwrap_or_else(|| Decimal::from(1_000_000));
21
22    let params = GammaListParams {
23        limit: Some(50),
24        liquidity_num_min: Some(min_liquidity),
25        ..Default::default()
26    };
27
28    let response = clob.get_markets(None, Some(&params)).await?;
29    let market = pick_liquid_market(&response.data, min_liquidity)?;
30
31    println!(
32        "Selected market {} (liquidity={:?})",
33        market.condition_id, market.liquidity_num
34    );
35
36    let asset_ids = derive_asset_ids(market).unwrap_or_else(|| Vec::new());
37
38    if asset_ids.is_empty() {
39        return Err(PolyError::validation(
40            "failed to derive asset IDs for the selected market",
41        ));
42    }
43
44    let mut client = WssMarketClient::new();
45    client.subscribe(asset_ids.clone()).await?;
46
47    println!("Subscribed to market channel for assets={:?}", asset_ids);
48
49    for _ in 0..20 {
50        match client.next_event().await {
51            Ok(WssMarketEvent::PriceChange(change)) => {
52                println!(
53                    "price_change for {}: {:?}",
54                    change.market, change.price_changes
55                );
56            }
57            Ok(WssMarketEvent::Book(book)) => {
58                println!(
59                    "book {} bids={} asks={}",
60                    book.market,
61                    book.bids.len(),
62                    book.asks.len()
63                );
64            }
65            Ok(WssMarketEvent::TickSizeChange(change)) => {
66                println!(
67                    "tick size change {} from {} to {}",
68                    change.market, change.old_tick_size, change.new_tick_size
69                );
70            }
71            Ok(WssMarketEvent::LastTrade(trade)) => {
72                println!(
73                    "last_trade {} {:?}@{}",
74                    trade.market, trade.side, trade.price
75                );
76            }
77            Err(err) => {
78                eprintln!("stream error: {}", err);
79                break;
80            }
81        }
82    }
83
84    Ok(())
85}
86
87fn pick_liquid_market(markets: &[Market], min_liquidity: Decimal) -> Result<&Market> {
88    let eligible: Vec<&Market> = markets
89        .iter()
90        .filter(|m| m.liquidity_num.unwrap_or_default() >= min_liquidity)
91        .collect();
92
93    if eligible.is_empty() {
94        return Err(PolyError::validation("no liquid markets available"));
95    }
96
97    let seed = SystemTime::now()
98        .duration_since(UNIX_EPOCH)
99        .map(|d| d.as_nanos() as usize)
100        .unwrap_or(0);
101    let idx = seed % eligible.len();
102    Ok(eligible[idx])
103}
104
105fn derive_asset_ids(market: &Market) -> Option<Vec<String>> {
106    if !market.clob_token_ids.is_empty() {
107        return Some(market.clob_token_ids.clone());
108    }
109
110    let ids = market
111        .tokens
112        .iter()
113        .map(|token| token.token_id.clone())
114        .filter(|id| !id.is_empty())
115        .collect::<Vec<_>>();
116
117    if ids.is_empty() { None } else { Some(ids) }
118}