use polyoxide_clob::{Account, Clob, OrderSide};
use polyoxide_core::QueryBuilder;
use polyoxide_gamma::Gamma;
use std::time::Duration;
fn public_client() -> Clob {
Clob::public()
}
fn authenticated_client() -> Clob {
dotenvy::dotenv().ok();
let account =
Account::from_env().expect("POLYMARKET_* env vars required for authenticated tests");
Clob::from_account(account).expect("authenticated clob client")
}
async fn find_active_token_id() -> String {
let gamma = Gamma::builder().build().expect("gamma client");
let markets = gamma
.markets()
.list()
.closed(false)
.send()
.await
.expect("gamma list markets");
markets
.iter()
.find_map(|m| {
m.clob_token_ids.as_ref().and_then(|ids| {
serde_json::from_str::<Vec<String>>(ids)
.ok()
.and_then(|v| v.into_iter().next())
})
})
.expect("should find at least one active market with a token_id via Gamma")
}
#[tokio::test]
#[ignore]
async fn live_ping() {
let client = public_client();
let latency = client.health().ping().await.expect("ping should succeed");
assert!(
latency < Duration::from_secs(10),
"latency too high: {:?}",
latency
);
}
#[tokio::test]
#[ignore]
async fn live_list_markets() {
let client = public_client();
let resp = client.markets().list().send().await.expect("list markets");
assert!(!resp.data.is_empty(), "should return at least one market");
}
#[tokio::test]
#[ignore]
async fn live_simplified_markets() {
let client = public_client();
let resp = client
.markets()
.simplified()
.send()
.await
.expect("simplified markets");
assert!(
!resp.data.is_empty(),
"should return at least one simplified market"
);
}
#[tokio::test]
#[ignore]
async fn live_sampling_markets() {
let client = public_client();
let _resp = client
.markets()
.sampling()
.send()
.await
.expect("sampling markets should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_sampling_simplified_markets() {
let client = public_client();
let _resp = client
.markets()
.sampling_simplified()
.send()
.await
.expect("sampling simplified markets should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_fee_rate() {
let token_id = find_active_token_id().await;
let client = public_client();
let resp = client
.markets()
.fee_rate(&token_id)
.send()
.await
.expect("fee_rate should deserialize");
assert!(
resp.base_fee <= 10_000,
"fee rate {} bps seems unreasonably high",
resp.base_fee
);
}
#[tokio::test]
#[ignore]
async fn live_midpoint() {
let token_id = find_active_token_id().await;
let client = public_client();
let resp = client
.markets()
.midpoint(&token_id)
.send()
.await
.expect("midpoint should succeed");
let mid: f64 = resp.mid.parse().expect("mid should be a number");
assert!(
(0.0..=1.0).contains(&mid),
"midpoint {mid} should be between 0 and 1"
);
}
#[tokio::test]
#[ignore]
async fn live_order_book() {
let token_id = find_active_token_id().await;
let client = public_client();
let book = client
.markets()
.order_book(&token_id)
.send()
.await
.expect("order book should succeed");
assert!(
!book.bids.is_empty() || !book.asks.is_empty(),
"order book should have at least some levels"
);
}
#[tokio::test]
#[ignore]
async fn live_price() {
let token_id = find_active_token_id().await;
let client = public_client();
let resp = client
.markets()
.price(&token_id, OrderSide::Buy)
.send()
.await
.expect("price should succeed");
let price: f64 = resp.price.parse().expect("price should be a number");
assert!(
(0.0..=1.0).contains(&price),
"price {price} should be between 0 and 1"
);
}
#[tokio::test]
#[ignore]
async fn live_prices_history() {
let token_id = find_active_token_id().await;
let client = public_client();
let resp = client
.markets()
.prices_history(&token_id)
.query("interval", "max")
.send()
.await
.expect("prices_history should succeed");
assert!(
!resp.history.is_empty(),
"prices history should be non-empty"
);
}
#[tokio::test]
#[ignore]
async fn live_neg_risk() {
let token_id = find_active_token_id().await;
let client = public_client();
let _resp = client
.markets()
.neg_risk(&token_id)
.send()
.await
.expect("neg_risk should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_tick_size() {
let token_id = find_active_token_id().await;
let client = public_client();
let resp = client
.markets()
.tick_size(&token_id)
.send()
.await
.expect("tick_size should succeed");
let tick: f64 = resp
.minimum_tick_size
.parse()
.expect("minimum_tick_size should be a number");
assert!(tick > 0.0, "tick size {tick} should be positive");
}
#[tokio::test]
#[ignore]
async fn live_get_market() {
let client = public_client();
let list = client.markets().list().send().await.expect("list markets");
let condition_id = &list
.data
.first()
.expect("should have at least one market")
.condition_id;
let market = client
.markets()
.get(condition_id)
.send()
.await
.expect("get market should succeed");
assert_eq!(
&market.condition_id, condition_id,
"returned market should match requested condition_id"
);
}
#[tokio::test]
#[ignore]
async fn live_get_markets_by_token_ids() {
let token_id = find_active_token_id().await;
let client = public_client();
let resp = client
.markets()
.get_by_token_ids(vec![token_id.clone()])
.send()
.await
.expect("get_by_token_ids should succeed");
assert!(
!resp.data.is_empty(),
"should return at least one market for the given token_id"
);
}
#[tokio::test]
#[ignore]
async fn live_server_time() {
let client = public_client();
let resp = client
.health()
.server_time()
.send()
.await
.expect("server_time should succeed");
assert!(
resp.time > 0,
"server time {} should be positive",
resp.time
);
}
#[tokio::test]
#[ignore]
async fn live_spread() {
let token_id = find_active_token_id().await;
let client = public_client();
let resp = client
.markets()
.spread(&token_id)
.send()
.await
.expect("spread should succeed");
let spread: f64 = resp.spread.parse().expect("spread should be a number");
assert!(spread >= 0.0, "spread {spread} should be non-negative");
}
#[tokio::test]
#[ignore]
async fn live_last_trade_price() {
let token_id = find_active_token_id().await;
let client = public_client();
let resp = client
.markets()
.last_trade_price(&token_id)
.send()
.await
.expect("last_trade_price should succeed");
let price_str = resp
.price
.or(resp.last_trade_price)
.expect("response should have price or last_trade_price");
let price: f64 = price_str.parse().expect("price should be a number");
assert!(
(0.0..=1.0).contains(&price),
"last trade price {price} should be between 0 and 1"
);
}
#[tokio::test]
#[ignore]
async fn live_usdc_balance() {
let client = authenticated_client();
let resp = client
.account_api()
.expect("account_api")
.usdc_balance()
.send()
.await
.expect("usdc_balance should deserialize");
let balance: f64 = resp.balance.parse().expect("balance should be a number");
assert!(balance >= 0.0, "balance {balance} should be non-negative");
}
#[tokio::test]
#[ignore]
async fn live_balance_allowance() {
let token_id = find_active_token_id().await;
let client = authenticated_client();
let _resp = client
.account_api()
.expect("account_api")
.balance_allowance(&token_id)
.send()
.await
.expect("balance_allowance should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_list_trades() {
let client = authenticated_client();
let _trades = client
.account_api()
.expect("account_api")
.trades()
.send()
.await
.expect("trades should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_list_trades_with_filter() {
let client = authenticated_client();
let _trades = client
.account_api()
.expect("account_api")
.trades()
.after("0")
.send()
.await
.expect("trades with after filter should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_builder_trades() {
let client = authenticated_client();
let _trades = client
.account_api()
.expect("account_api")
.builder_trades()
.send()
.await
.expect("builder_trades should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_heartbeat() {
let client = authenticated_client();
let _resp = client
.account_api()
.expect("account_api")
.heartbeat()
.await
.expect("heartbeat should succeed");
}
#[tokio::test]
#[ignore]
async fn live_list_notifications() {
let client = authenticated_client();
let _notifications = client
.notifications()
.expect("notifications")
.list()
.send()
.await
.expect("list notifications should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_closed_only_status() {
let client = authenticated_client();
let _resp = client
.auth()
.expect("auth")
.closed_only_status()
.send()
.await
.expect("closed_only_status should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_reward_earnings() {
let client = authenticated_client();
let _resp = client
.rewards()
.expect("rewards")
.earnings()
.send()
.await
.expect("earnings should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_reward_total_earnings() {
let client = authenticated_client();
let _resp = client
.rewards()
.expect("rewards")
.total_earnings()
.send()
.await
.expect("total_earnings should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_reward_percentages() {
let client = authenticated_client();
let _resp = client
.rewards()
.expect("rewards")
.percentages()
.send()
.await
.expect("percentages should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_reward_market_earnings() {
let client = authenticated_client();
let _resp = client
.rewards()
.expect("rewards")
.market_earnings()
.send()
.await
.expect("market_earnings should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_reward_current_markets() {
let client = authenticated_client();
let _resp = client
.rewards()
.expect("rewards")
.current_markets()
.send()
.await
.expect("current_markets should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_rfq_config() {
let client = authenticated_client();
let _config = client
.rfq()
.expect("rfq")
.config()
.send()
.await
.expect("rfq config should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_rfq_list_requests() {
let client = authenticated_client();
let resp = client
.rfq()
.expect("rfq")
.list_requests()
.limit(5)
.send()
.await
.expect("list rfq requests should deserialize");
assert!(resp.data.len() <= 5);
}
#[tokio::test]
#[ignore]
async fn live_rfq_requester_quotes() {
let client = authenticated_client();
let _resp = client
.rfq()
.expect("rfq")
.requester_quotes()
.limit(5)
.send()
.await
.expect("requester quotes should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_rfq_quoter_quotes() {
let client = authenticated_client();
let _resp = client
.rfq()
.expect("rfq")
.quoter_quotes()
.limit(5)
.send()
.await
.expect("quoter quotes should deserialize");
}
#[tokio::test]
#[ignore]
async fn live_list_open_orders() {
let client = authenticated_client();
let _orders = client
.orders()
.expect("orders")
.list()
.send()
.await
.expect("list open orders should deserialize");
}