fix: resolve rustfmt configuration duplicate key error and apply consistent code formatting across all source files

This commit is contained in:
floor-licker
2025-12-05 19:09:06 -05:00
parent 5576d765ee
commit 9993e51c7f
29 changed files with 2540 additions and 1673 deletions
+48 -39
View File
@@ -6,32 +6,35 @@ use tokio::time::{sleep, Duration};
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🚀 Advanced Network Optimizations - polyfill-rs");
println!("===============================================");
// Use the best-performing configuration (Internet)
let client = ClobClient::new_internet("https://clob.polymarket.com");
println!("📊 Test 1: Connection Pre-warming");
println!("=================================");
// Test without pre-warming
let start = Instant::now();
let _ = client.get_server_time().await;
let cold_start = start.elapsed();
println!(" ❄️ Cold start: {:?}", cold_start);
// Test with pre-warming
let client_warm = ClobClient::new_internet("https://clob.polymarket.com");
let _ = client_warm.prewarm_connections().await;
let start = Instant::now();
let _ = client_warm.get_server_time().await;
let warm_start = start.elapsed();
println!(" 🔥 Warm start: {:?}", warm_start);
println!(" 📈 Improvement: {:.1}x faster", cold_start.as_millis() as f64 / warm_start.as_millis() as f64);
println!(
" 📈 Improvement: {:.1}x faster",
cold_start.as_millis() as f64 / warm_start.as_millis() as f64
);
println!("\n📊 Test 2: Request Batching Simulation");
println!("=====================================");
// Sequential requests
let start = Instant::now();
for _ in 0..5 {
@@ -39,18 +42,21 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
let sequential_time = start.elapsed();
println!(" 📝 Sequential: 5 requests in {:?}", sequential_time);
// Parallel requests (simulating batching)
let start = Instant::now();
let futures = (0..5).map(|_| client.get_server_time());
let _results: Vec<_> = futures_util::future::join_all(futures).await;
let parallel_time = start.elapsed();
println!(" ⚡ Parallel: 5 requests in {:?}", parallel_time);
println!(" 📈 Improvement: {:.1}x faster", sequential_time.as_millis() as f64 / parallel_time.as_millis() as f64);
println!(
" 📈 Improvement: {:.1}x faster",
sequential_time.as_millis() as f64 / parallel_time.as_millis() as f64
);
println!("\n📊 Test 3: Circuit Breaker Pattern");
println!("=================================");
struct SimpleCircuitBreaker {
failure_count: u32,
failure_threshold: u32,
@@ -58,14 +64,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
last_failure: Option<Instant>,
state: CircuitState,
}
#[derive(Debug, PartialEq)]
enum CircuitState {
Closed, // Normal operation
Open, // Failing, reject requests
HalfOpen, // Testing if service recovered
}
impl SimpleCircuitBreaker {
fn new() -> Self {
Self {
@@ -76,7 +82,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
state: CircuitState::Closed,
}
}
fn can_execute(&mut self) -> bool {
match self.state {
CircuitState::Closed => true,
@@ -91,30 +97,30 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
} else {
false
}
}
},
CircuitState::HalfOpen => true,
}
}
fn on_success(&mut self) {
self.failure_count = 0;
self.state = CircuitState::Closed;
}
fn on_failure(&mut self) {
self.failure_count += 1;
self.last_failure = Some(Instant::now());
if self.failure_count >= self.failure_threshold {
self.state = CircuitState::Open;
}
}
}
let mut circuit_breaker = SimpleCircuitBreaker::new();
let mut successful_requests = 0;
let mut rejected_requests = 0;
// Simulate some requests with circuit breaker
for i in 0..10 {
if circuit_breaker.can_execute() {
@@ -125,13 +131,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
if i < 3 {
println!(" ✅ Request {} succeeded", i + 1);
}
}
},
Err(_) => {
circuit_breaker.on_failure();
if i < 3 {
println!(" ❌ Request {} failed", i + 1);
}
}
},
}
} else {
rejected_requests += 1;
@@ -139,21 +145,24 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" 🚫 Request {} rejected by circuit breaker", i + 1);
}
}
// Small delay between requests
sleep(Duration::from_millis(100)).await;
}
println!(" 📊 Results: {} successful, {} rejected", successful_requests, rejected_requests);
println!(
" 📊 Results: {} successful, {} rejected",
successful_requests, rejected_requests
);
println!("\n📊 Test 4: Adaptive Timeout Strategy");
println!("===================================");
struct AdaptiveTimeout {
recent_times: Vec<Duration>,
max_samples: usize,
}
impl AdaptiveTimeout {
fn new() -> Self {
Self {
@@ -161,27 +170,27 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
max_samples: 10,
}
}
fn add_sample(&mut self, duration: Duration) {
self.recent_times.push(duration);
if self.recent_times.len() > self.max_samples {
self.recent_times.remove(0);
}
}
fn get_adaptive_timeout(&self) -> Duration {
if self.recent_times.is_empty() {
return Duration::from_millis(5000); // Default
}
let avg = self.recent_times.iter().sum::<Duration>() / self.recent_times.len() as u32;
// Set timeout to 3x average response time
avg * 3
}
}
let mut adaptive_timeout = AdaptiveTimeout::new();
// Collect some samples
for i in 0..5 {
let start = Instant::now();
@@ -193,10 +202,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
}
}
let recommended_timeout = adaptive_timeout.get_adaptive_timeout();
println!(" 🎯 Recommended timeout: {:?}", recommended_timeout);
println!("\n🎯 Advanced Optimization Summary");
println!("===============================");
println!("Implemented Optimizations:");
@@ -204,7 +213,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" ✅ Request parallelization (batching simulation)");
println!(" ✅ Circuit breaker pattern (prevents cascade failures)");
println!(" ✅ Adaptive timeouts (dynamic based on network conditions)");
println!("\nFurther Optimizations Available:");
println!(" 🔧 Custom DNS resolver with caching");
println!(" 🔧 Connection affinity (sticky connections)");
@@ -212,12 +221,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" 🔧 Geographical load balancing");
println!(" 🔧 WebSocket connections for real-time data");
println!(" 🔧 HTTP/3 (QUIC) when supported");
println!("\n📈 Expected Network Improvements:");
println!(" • 10-30% latency reduction from optimized HTTP client");
println!(" • 50-80% improvement in connection reuse scenarios");
println!(" • Better resilience during network instability");
println!(" • Adaptive performance based on network conditions");
Ok(())
}
+70 -47
View File
@@ -7,10 +7,10 @@ use std::time::Instant;
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load environment variables from .env file
dotenv::dotenv().ok();
println!("🔐 Authenticated Network Benchmark - Real Order Creation");
println!("=======================================================");
// API credentials from .env file
let _api_key = std::env::var("POLYMARKET_API_KEY")
.map_err(|_| "POLYMARKET_API_KEY not found in .env file")?;
@@ -18,17 +18,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.map_err(|_| "POLYMARKET_SECRET not found in .env file")?;
let _passphrase = std::env::var("POLYMARKET_PASSPHRASE")
.map_err(|_| "POLYMARKET_PASSPHRASE not found in .env file")?;
println!("✅ Loaded API credentials from .env file");
let client = ClobClient::new_internet("https://clob.polymarket.com");
println!("🔑 Setting up API credentials...");
// Test 1: API Key Creation/Derivation (part of the 266.5ms benchmark)
println!("\n📊 Test 1: API Key Setup");
println!("========================");
let mut setup_times = Vec::new();
for i in 0..3 {
let start = Instant::now();
@@ -36,33 +36,33 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(_creds) => {
let duration = start.elapsed();
setup_times.push(duration);
println!(" Run {}: ✅ API key setup in {:?}", i+1, duration);
println!(" Run {}: ✅ API key setup in {:?}", i + 1, duration);
// Set the credentials for order creation
// Note: We'd need to properly set up the client with these creds
break;
}
},
Err(e) => {
let duration = start.elapsed();
setup_times.push(duration);
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
}
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
},
}
}
if !setup_times.is_empty() {
let avg = setup_times.iter().sum::<std::time::Duration>() / setup_times.len() as u32;
println!(" 📈 API setup average: {:?}", avg);
}
// Test 2: Order Creation with EIP-712 (the real 266.5ms test)
println!("\n📊 Test 2: Order Creation + EIP-712 Signing");
println!("===========================================");
println!("Target: polymarket-rs-client 266.5ms ± 28.6ms");
// We need a real token ID for a valid order
let token_id = "21742633143463906290569050155826241533067272736897614950488156847949938836455";
let mut order_times = Vec::new();
for i in 0..5 {
let order_args = OrderArgs::new(
@@ -71,56 +71,70 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Decimal::from_str("1.0").unwrap(), // Minimum size
Side::BUY,
);
let start = Instant::now();
match client.create_order(&order_args, None, None, None).await {
Ok(order) => {
let duration = start.elapsed();
order_times.push(duration);
println!(" Run {}: ✅ Order created in {:?}", i+1, duration);
println!(" Run {}: ✅ Order created in {:?}", i + 1, duration);
// Immediately cancel to clean up
// Note: We'd need the proper cancel method here
println!(" 📝 Order ID: {} (would cancel immediately)",
format!("{:?}", order).chars().take(50).collect::<String>());
}
println!(
" 📝 Order ID: {} (would cancel immediately)",
format!("{:?}", order).chars().take(50).collect::<String>()
);
},
Err(e) => {
let duration = start.elapsed();
order_times.push(duration);
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
// Even errors give us timing info about how far we got
if duration.as_millis() > 50 {
println!(" 💡 Error occurred after network round-trip, timing still valid");
}
}
},
}
}
if !order_times.is_empty() {
let avg = order_times.iter().sum::<std::time::Duration>() / order_times.len() as u32;
let min = order_times.iter().min().unwrap();
let max = order_times.iter().max().unwrap();
let std_dev = {
let mean = avg.as_millis() as f64;
let variance = order_times.iter()
let variance = order_times
.iter()
.map(|t| (t.as_millis() as f64 - mean).powi(2))
.sum::<f64>() / order_times.len() as f64;
.sum::<f64>()
/ order_times.len() as f64;
variance.sqrt()
};
println!("\n 📊 Order Creation Results:");
println!(" 📈 polyfill-rs: {:.1}ms ± {:.1}ms", avg.as_millis(), std_dev);
println!(
" 📈 polyfill-rs: {:.1}ms ± {:.1}ms",
avg.as_millis(),
std_dev
);
println!(" 📊 Range: {:?} - {:?}", min, max);
println!(" 🆚 vs original (266.5ms): {:.1}x {}",
266.5 / avg.as_millis() as f64,
if avg.as_millis() < 267 { "faster" } else { "slower" });
println!(
" 🆚 vs original (266.5ms): {:.1}x {}",
266.5 / avg.as_millis() as f64,
if avg.as_millis() < 267 {
"faster"
} else {
"slower"
}
);
}
// Test 3: Compare with Market Data (for context)
println!("\n📊 Test 3: Market Data (for comparison)");
println!("======================================");
let mut market_times = Vec::new();
for i in 0..3 {
let start = Instant::now();
@@ -129,41 +143,50 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let duration = start.elapsed();
market_times.push(duration);
if i < 2 {
println!(" Run {}: ✅ {} markets in {:?}", i+1, markets.data.len(), duration);
println!(
" Run {}: ✅ {} markets in {:?}",
i + 1,
markets.data.len(),
duration
);
}
}
},
Err(e) => {
let duration = start.elapsed();
market_times.push(duration);
if i < 2 {
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
}
}
},
}
}
if !market_times.is_empty() {
let avg = market_times.iter().sum::<std::time::Duration>() / market_times.len() as u32;
println!(" 📈 Market data average: {:?}", avg);
println!(" 🆚 vs original (404.5ms): {:.1}x faster", 404.5 / avg.as_millis() as f64);
println!(
" 🆚 vs original (404.5ms): {:.1}x faster",
404.5 / avg.as_millis() as f64
);
}
println!("\n🎯 Authenticated Benchmark Summary");
println!("=================================");
println!("Real Production Performance:");
if !order_times.is_empty() {
let order_avg = order_times.iter().sum::<std::time::Duration>() / order_times.len() as u32;
println!(" • Order creation: {:?} (vs 266.5ms baseline)", order_avg);
}
if !market_times.is_empty() {
let market_avg = market_times.iter().sum::<std::time::Duration>() / market_times.len() as u32;
let market_avg =
market_times.iter().sum::<std::time::Duration>() / market_times.len() as u32;
println!(" • Market data: {:?} (vs 404.5ms baseline)", market_avg);
}
println!("\nThis gives us the REAL production numbers to compare!");
println!("Network optimizations + EIP-712 signing performance combined.");
Ok(())
}
+52 -38
View File
@@ -7,107 +7,116 @@ use std::time::Instant;
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🚀 polyfill-rs Performance Benchmark Demo");
println!("==========================================");
let client = ClobClient::new("https://clob.polymarket.com");
// Benchmark 1: Order creation and EIP-712 signing (computational cost)
println!("\n📊 Benchmark 1: Order Creation + EIP-712 Signing");
println!("------------------------------------------------");
let order_args = OrderArgs::new(
"test_token_id",
Decimal::from_str("0.75")?,
Decimal::from_str("100.0")?,
Side::BUY,
);
let mut order_times = Vec::new();
for i in 0..10 {
let start = Instant::now();
// This measures the computational cost of order creation and signing
// Note: Will fail without proper credentials, but we're measuring the CPU work
let _result = client.create_order(&order_args, None, None, None).await;
let duration = start.elapsed();
order_times.push(duration);
if i == 0 {
println!(" First run: {:?}", duration);
}
}
let avg_order_time = order_times.iter().sum::<std::time::Duration>() / order_times.len() as u32;
let min_order_time = order_times.iter().min().unwrap();
let max_order_time = order_times.iter().max().unwrap();
println!(" Average: {:?}", avg_order_time);
println!(" Range: {:?} - {:?}", min_order_time, max_order_time);
println!(" 📈 vs baseline (266.5ms): {:.1}x faster",
266.5 / avg_order_time.as_millis() as f64);
println!(
" 📈 vs baseline (266.5ms): {:.1}x faster",
266.5 / avg_order_time.as_millis() as f64
);
// Benchmark 2: Market data fetching and parsing
println!("\n📊 Benchmark 2: Fetch + Parse Simplified Markets");
println!("-----------------------------------------------");
let mut fetch_times = Vec::new();
for i in 0..5 {
let start = Instant::now();
match client.get_sampling_simplified_markets(None).await {
Ok(markets) => {
let duration = start.elapsed();
fetch_times.push(duration);
if i == 0 {
println!(" ✅ Fetched {} markets in {:?}", markets.data.len(), duration);
println!(
" ✅ Fetched {} markets in {:?}",
markets.data.len(),
duration
);
}
}
},
Err(e) => {
let duration = start.elapsed();
println!(" ⚠️ Network error (expected): {} in {:?}", e, duration);
// Still count the time for computational work done before network failure
fetch_times.push(duration);
}
},
}
}
if !fetch_times.is_empty() {
let avg_fetch_time = fetch_times.iter().sum::<std::time::Duration>() / fetch_times.len() as u32;
let avg_fetch_time =
fetch_times.iter().sum::<std::time::Duration>() / fetch_times.len() as u32;
let min_fetch_time = fetch_times.iter().min().unwrap();
let max_fetch_time = fetch_times.iter().max().unwrap();
println!(" Average: {:?}", avg_fetch_time);
println!(" Range: {:?} - {:?}", min_fetch_time, max_fetch_time);
println!(" 📈 vs baseline (404.5ms): {:.1}x faster",
404.5 / avg_fetch_time.as_millis() as f64);
println!(
" 📈 vs baseline (404.5ms): {:.1}x faster",
404.5 / avg_fetch_time.as_millis() as f64
);
}
// Benchmark 3: Memory efficiency demonstration
println!("\n📊 Benchmark 3: Memory Usage Analysis");
println!("------------------------------------");
println!(" 🔧 Memory optimizations in polyfill-rs:");
println!(" • Fixed-point arithmetic (u32/i64 vs Decimal)");
println!(" • Zero-allocation order book updates");
println!(" • Compact data structures");
println!(" • Cache-aligned memory layouts");
println!(" 📈 Expected: ~10x less memory vs baseline (15.9MB)");
// Demonstrate order book efficiency
println!("\n📊 Benchmark 4: Order Book Performance");
println!("------------------------------------");
use polyfill_rs::OrderBookImpl;
let mut book = OrderBookImpl::new("demo_token".to_string(), 100);
let start = Instant::now();
// Simulate rapid order book updates
for i in 0..10000 {
let price = Decimal::from_str(&format!("0.{:04}", 5000 + (i % 1000)))?;
let size = Decimal::from_str("100.0")?;
// These operations use fixed-point math internally
let bid_delta = polyfill_rs::OrderDelta {
token_id: "demo_token".to_string(),
@@ -125,16 +134,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
size,
sequence: (i + 10000) as u64,
};
let _ = book.apply_delta(bid_delta);
let _ = book.apply_delta(ask_delta);
}
let book_duration = start.elapsed();
println!(" ⚡ 20,000 order book updates in {:?}", book_duration);
println!(" 📊 Rate: {:.0} updates/second",
20000.0 / book_duration.as_secs_f64());
println!(
" 📊 Rate: {:.0} updates/second",
20000.0 / book_duration.as_secs_f64()
);
// Fast operations
let start = Instant::now();
for _ in 0..100000 {
@@ -142,8 +153,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = book.mid_price_fast();
}
let fast_ops_duration = start.elapsed();
println!(" ⚡ 200,000 fast spread/mid calculations in {:?}", fast_ops_duration);
println!(
" ⚡ 200,000 fast spread/mid calculations in {:?}",
fast_ops_duration
);
println!("\n🎯 Summary");
println!("=========");
println!("polyfill-rs delivers significant performance improvements through:");
@@ -154,6 +168,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!();
println!("🔬 Run `cargo bench` for detailed criterion benchmarks");
println!("📊 Run `./scripts/benchmark_comparison.sh` for comprehensive analysis");
Ok(())
}
+199 -164
View File
@@ -10,36 +10,40 @@
//! - Rate limiting and performance optimizations
use polyfill_rs::{
// Core client types
ClobClient, PolyfillClient, OrderArgs, Side, OrderType,
// Order book management
book::{OrderBook, OrderBookManager},
// Streaming capabilities
stream::{WebSocketStream, StreamManager},
// Fill execution
fill::{FillEngine, FillProcessor},
// Types and structures
types::*,
// Error handling
errors::{PolyfillError, Result},
// Fill execution
fill::{FillEngine, FillProcessor},
// Streaming capabilities
stream::{StreamManager, WebSocketStream},
// Types and structures
types::*,
// Utility functions
utils::{crypto, math, retry, time, url, rate_limit, address},
utils::{address, crypto, math, rate_limit, retry, time, url},
// Configuration
ClientConfig,
// Core client types
ClobClient,
OrderArgs,
OrderType,
PolyfillClient,
Side,
};
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use std::time::Duration;
use tokio::time::sleep;
use tracing::{error, info, debug};
use tracing::{debug, error, info};
/// Comprehensive demo showcasing all polyfill-rs functionality
#[allow(dead_code)]
@@ -91,40 +95,40 @@ impl PolyfillDemo {
pub fn new() -> Result<Self> {
// Create basic client
let client = ClobClient::new("https://clob.polymarket.com");
// Create advanced client with configuration
let _config = ClientConfig {
base_url: "https://clob.polymarket.com".to_string(),
chain_id: 137, // Polygon
private_key: None, // Would be set in production
api_credentials: None, // Would be set in production
chain_id: 137, // Polygon
private_key: None, // Would be set in production
api_credentials: None, // Would be set in production
max_slippage: Some(dec!(0.01)), // 1% max slippage
fee_rate: Some(dec!(0.02)), // 2% fee rate
fee_rate: Some(dec!(0.02)), // 2% fee rate
timeout: Some(Duration::from_secs(30)),
max_connections: Some(100),
};
let advanced_client = PolyfillClient::new("https://clob.polymarket.com");
// Create order book manager
let book_manager = OrderBookManager::new(100);
// Create fill engine
let fill_engine = FillEngine::new(
dec!(1.0), // Min fill size
dec!(2.0), // Max slippage 2%
5, // 5 bps fee rate
dec!(1.0), // Min fill size
dec!(2.0), // Max slippage 2%
5, // 5 bps fee rate
);
// Create fill processor
let fill_processor = FillProcessor::new(1000);
// Create stream manager
let stream_manager = StreamManager::new();
// Create rate limiter (100 requests per second)
let rate_limiter = rate_limit::TokenBucket::new(100, 100);
Ok(Self {
client,
advanced_client,
@@ -140,24 +144,24 @@ impl PolyfillDemo {
/// Demo 1: Basic API Operations
pub async fn demo_basic_api_operations(&mut self) -> Result<()> {
info!("=== Demo 1: Basic API Operations ===");
// Test connectivity
let is_ok = self.client.get_ok().await;
info!("API connectivity: {}", is_ok);
self.stats.api_calls += 1;
// Get server time
match self.client.get_server_time().await {
Ok(timestamp) => {
info!("Server time: {}", timestamp);
self.stats.api_calls += 1;
}
},
Err(e) => {
error!("Failed to get server time: {}", e);
self.stats.errors += 1;
}
},
}
// Get sampling markets
match self.client.get_sampling_markets(None).await {
Ok(markets) => {
@@ -166,32 +170,36 @@ impl PolyfillDemo {
info!(" Market: {} - {}", market.question, market.market_slug);
}
self.stats.api_calls += 1;
}
},
Err(e) => {
error!("Failed to get markets: {}", e);
self.stats.errors += 1;
}
},
}
Ok(())
}
/// Demo 2: Order Book Operations
pub async fn demo_order_book_operations(&mut self) -> Result<()> {
info!("=== Demo 2: Order Book Operations ===");
// Example token ID (you would use a real one in production)
let token_id = "12345";
// Get order book from API
match self.client.get_order_book(token_id).await {
Ok(order_book) => {
info!("Order book for token {}: {} bids, {} asks",
token_id, order_book.bids.len(), order_book.asks.len());
info!(
"Order book for token {}: {} bids, {} asks",
token_id,
order_book.bids.len(),
order_book.asks.len()
);
// Create local order book
let mut local_book = OrderBook::new(token_id.to_string(), 50);
// Apply order book data to local book
for (i, bid) in order_book.bids.iter().enumerate() {
local_book.apply_delta(OrderDelta {
@@ -203,7 +211,7 @@ impl PolyfillDemo {
sequence: i as u64,
})?;
}
for (i, ask) in order_book.asks.iter().enumerate() {
local_book.apply_delta(OrderDelta {
token_id: token_id.to_string(),
@@ -214,19 +222,29 @@ impl PolyfillDemo {
sequence: (order_book.bids.len() + i) as u64,
})?;
}
// Get analytics
let analytics = local_book.analytics();
info!("Book analytics:");
info!(" Bid levels: {}, Ask levels: {}", analytics.bid_count, analytics.ask_count);
info!(" Total bid size: {}, Total ask size: {}", analytics.total_bid_size, analytics.total_ask_size);
info!(
" Bid levels: {}, Ask levels: {}",
analytics.bid_count, analytics.ask_count
);
info!(
" Total bid size: {}, Total ask size: {}",
analytics.total_bid_size, analytics.total_ask_size
);
if let Some(spread) = analytics.spread {
info!(" Spread: {} ({:.2}%)", spread, analytics.spread_pct.unwrap_or(dec!(0)));
info!(
" Spread: {} ({:.2}%)",
spread,
analytics.spread_pct.unwrap_or(dec!(0))
);
}
if let Some(mid) = analytics.mid_price {
info!(" Mid price: {}", mid);
}
// Calculate market impact
if let Some(impact) = local_book.calculate_market_impact(Side::BUY, dec!(100.0)) {
info!("Market impact for 100 size buy:");
@@ -234,103 +252,98 @@ impl PolyfillDemo {
info!(" Impact: {:.2}%", impact.impact_pct);
info!(" Total cost: {}", impact.total_cost);
}
self.stats.api_calls += 1;
}
},
Err(e) => {
error!("Failed to get order book: {}", e);
self.stats.errors += 1;
}
},
}
Ok(())
}
/// Demo 3: Market Data Operations
pub async fn demo_market_data_operations(&mut self) -> Result<()> {
info!("=== Demo 3: Market Data Operations ===");
let token_id = "12345";
// Get midpoint
match self.client.get_midpoint(token_id).await {
Ok(midpoint) => {
info!("Midpoint for {}: {}", token_id, midpoint.mid);
self.stats.api_calls += 1;
}
},
Err(e) => {
error!("Failed to get midpoint: {}", e);
self.stats.errors += 1;
}
},
}
// Get spread
match self.client.get_spread(token_id).await {
Ok(spread) => {
info!("Spread for {}: {}", token_id, spread.spread);
self.stats.api_calls += 1;
}
},
Err(e) => {
error!("Failed to get spread: {}", e);
self.stats.errors += 1;
}
},
}
// Get price for both sides
for side in [Side::BUY, Side::SELL] {
match self.client.get_price(token_id, side).await {
Ok(price) => {
info!("{} price for {}: {}", side.as_str(), token_id, price.price);
self.stats.api_calls += 1;
}
},
Err(e) => {
error!("Failed to get {} price: {}", side.as_str(), e);
self.stats.errors += 1;
}
},
}
}
// Get tick size
match self.client.get_tick_size(token_id).await {
Ok(tick_size) => {
info!("Tick size for {}: {}", token_id, tick_size);
self.stats.api_calls += 1;
}
},
Err(e) => {
error!("Failed to get tick size: {}", e);
self.stats.errors += 1;
}
},
}
// Get neg risk
match self.client.get_neg_risk(token_id).await {
Ok(neg_risk) => {
info!("Neg risk for {}: {}", token_id, neg_risk);
self.stats.api_calls += 1;
}
},
Err(e) => {
error!("Failed to get neg risk: {}", e);
self.stats.errors += 1;
}
},
}
Ok(())
}
/// Demo 4: Order Creation and Management
pub async fn demo_order_operations(&mut self) -> Result<()> {
info!("=== Demo 4: Order Creation and Management ===");
// Create order arguments
let order_args = OrderArgs::new(
"12345",
dec!(0.75),
dec!(100.0),
Side::BUY,
);
let order_args = OrderArgs::new("12345", dec!(0.75), dec!(100.0), Side::BUY);
info!("Created order args: {:?}", order_args);
// Create market order request
let market_order = MarketOrderRequest {
token_id: "12345".to_string(),
@@ -339,9 +352,9 @@ impl PolyfillDemo {
slippage_tolerance: Some(dec!(1.0)), // 1% slippage
client_id: Some("demo_market_order".to_string()),
};
info!("Created market order request: {:?}", market_order);
// Create limit order request
let limit_order = OrderRequest {
token_id: "12345".to_string(),
@@ -352,21 +365,21 @@ impl PolyfillDemo {
expiration: None,
client_id: Some("demo_limit_order".to_string()),
};
info!("Created limit order request: {:?}", limit_order);
self.stats.orders_processed += 2;
Ok(())
}
/// Demo 5: Fill Execution
pub async fn demo_fill_execution(&mut self) -> Result<()> {
info!("=== Demo 5: Fill Execution ===");
// Create a mock order book for testing
let mut book = OrderBook::new("12345".to_string(), 50);
// Add some liquidity
for i in 1..=5 {
book.apply_delta(OrderDelta {
@@ -378,7 +391,7 @@ impl PolyfillDemo {
sequence: i,
})?;
}
for i in 1..=5 {
book.apply_delta(OrderDelta {
token_id: "12345".to_string(),
@@ -389,9 +402,9 @@ impl PolyfillDemo {
sequence: i + 10,
})?;
}
info!("Created order book with liquidity");
// Execute market order
let market_order = MarketOrderRequest {
token_id: "12345".to_string(),
@@ -400,9 +413,11 @@ impl PolyfillDemo {
slippage_tolerance: Some(dec!(2.0)),
client_id: Some("demo_market_buy".to_string()),
};
let fill_result = self.fill_engine.execute_market_order(&market_order, &book)?;
let fill_result = self
.fill_engine
.execute_market_order(&market_order, &book)?;
info!("Market order execution result:");
info!(" Status: {:?}", fill_result.status);
info!(" Total size: {}", fill_result.total_size);
@@ -410,14 +425,14 @@ impl PolyfillDemo {
info!(" Total cost: {}", fill_result.total_cost);
info!(" Fees: {}", fill_result.fees);
info!(" Number of fills: {}", fill_result.fills.len());
// Process fills
for fill in &fill_result.fills {
self.fill_processor.process_fill(fill.clone())?;
self.stats.fills_processed += 1;
self.stats.total_volume += fill.size;
}
// Execute limit order
let limit_order = OrderRequest {
token_id: "12345".to_string(),
@@ -428,45 +443,48 @@ impl PolyfillDemo {
expiration: None,
client_id: Some("demo_limit_sell".to_string()),
};
let limit_result = self.fill_engine.execute_limit_order(&limit_order, &book)?;
info!("Limit order execution result:");
info!(" Status: {:?}", limit_result.status);
info!(" Total size: {}", limit_result.total_size);
info!(" Average price: {}", limit_result.average_price);
self.stats.orders_processed += 2;
Ok(())
}
/// Demo 6: Utility Functions
pub async fn demo_utility_functions(&mut self) -> Result<()> {
info!("=== Demo 6: Utility Functions ===");
// Time utilities
info!("Time utilities:");
info!(" Current timestamp (secs): {}", time::now_secs());
info!(" Current timestamp (millis): {}", time::now_millis());
info!(" Current timestamp (micros): {}", time::now_micros());
// Math utilities
info!("Math utilities:");
let price = dec!(0.7534);
let tick_size = dec!(0.01);
let rounded_price = math::round_to_tick(price, tick_size);
info!(" Price: {}, Tick size: {}, Rounded: {}", price, tick_size, rounded_price);
info!(
" Price: {}, Tick size: {}, Rounded: {}",
price, tick_size, rounded_price
);
let notional = math::notional(price, dec!(100.0));
info!(" Notional value: {}", notional);
let spread_pct = math::spread_pct(dec!(0.75), dec!(0.76));
info!(" Spread percentage: {:?}", spread_pct);
let mid_price = math::mid_price(dec!(0.75), dec!(0.76));
info!(" Mid price: {:?}", mid_price);
// Address utilities
info!("Address utilities:");
let address = "0x1234567890123456789012345678901234567890";
@@ -474,32 +492,36 @@ impl PolyfillDemo {
Ok(addr) => info!(" Parsed address: {:?}", addr),
Err(e) => error!(" Failed to parse address: {}", e),
}
let token_id = "12345";
match address::validate_token_id(token_id) {
Ok(_) => info!(" Valid token ID: {}", token_id),
Err(e) => error!(" Invalid token ID: {}", e),
}
// URL utilities
info!("URL utilities:");
let endpoint = url::build_endpoint("https://api.example.com", "/v1/orders")?;
info!(" Built endpoint: {}", endpoint);
// Rate limiting
info!("Rate limiting:");
for i in 0..5 {
let allowed = self.rate_limiter.try_consume();
info!(" Request {}: {}", i + 1, if allowed { "ALLOWED" } else { "RATE LIMITED" });
info!(
" Request {}: {}",
i + 1,
if allowed { "ALLOWED" } else { "RATE LIMITED" }
);
}
Ok(())
}
/// Demo 7: Error Handling and Retry Logic
pub async fn demo_error_handling(&mut self) -> Result<()> {
info!("=== Demo 7: Error Handling and Retry Logic ===");
// Demonstrate retry logic
let retry_config = retry::RetryConfig {
max_attempts: 3,
@@ -508,53 +530,59 @@ impl PolyfillDemo {
backoff_factor: 2.0,
jitter: true,
};
let operation = || async {
// Simulate a potentially failing operation
if rand::random::<bool>() {
Ok("Success!")
} else {
Err(PolyfillError::network("Simulated network error", std::io::Error::other("Simulated error")))
Err(PolyfillError::network(
"Simulated network error",
std::io::Error::other("Simulated error"),
))
}
};
match retry::with_retry(&retry_config, operation).await {
Ok(result) => {
info!("Retry operation succeeded: {}", result);
}
},
Err(e) => {
error!("Retry operation failed after all attempts: {}", e);
self.stats.errors += 1;
}
},
}
// Demonstrate error types
info!("Error types demonstration:");
let api_error = PolyfillError::api(400, "Bad Request");
info!(" API Error: {:?}", api_error);
let network_error = PolyfillError::network("Connection timeout", std::io::Error::new(std::io::ErrorKind::TimedOut, "Connection timeout"));
let network_error = PolyfillError::network(
"Connection timeout",
std::io::Error::new(std::io::ErrorKind::TimedOut, "Connection timeout"),
);
info!(" Network Error: {:?}", network_error);
let parse_error = PolyfillError::parse("Invalid JSON", None);
info!(" Parse Error: {:?}", parse_error);
let config_error = PolyfillError::config("Invalid configuration");
info!(" Config Error: {:?}", config_error);
Ok(())
}
/// Demo 8: Streaming Capabilities (Mock)
pub async fn demo_streaming_capabilities(&mut self) -> Result<()> {
info!("=== Demo 8: Streaming Capabilities ===");
// Create a mock WebSocket stream
let _stream = WebSocketStream::new("wss://stream.polymarket.com");
info!("Created WebSocket stream");
// Simulate subscription
let subscription = WssSubscription {
auth: WssAuth {
@@ -567,12 +595,14 @@ impl PolyfillDemo {
asset_ids: Some(vec!["12345".to_string(), "67890".to_string()]),
channel_type: "USER".to_string(),
};
info!("Created subscription: {:?}", subscription);
// Simulate receiving stream messages
let messages = vec![
StreamMessage::Heartbeat { timestamp: chrono::Utc::now() },
StreamMessage::Heartbeat {
timestamp: chrono::Utc::now(),
},
StreamMessage::BookUpdate {
data: OrderDelta {
token_id: "12345".to_string(),
@@ -581,7 +611,7 @@ impl PolyfillDemo {
price: dec!(0.75),
size: dec!(100.0),
sequence: 1,
}
},
},
StreamMessage::Trade {
data: FillEvent {
@@ -595,14 +625,14 @@ impl PolyfillDemo {
maker_address: alloy_primitives::Address::ZERO,
taker_address: alloy_primitives::Address::ZERO,
fee: dec!(0.375),
}
},
},
];
for message in messages {
info!("Received stream message: {:?}", message);
self.stats.stream_messages += 1;
// Process message based on type
match &message {
StreamMessage::BookUpdate { data } => {
@@ -611,31 +641,35 @@ impl PolyfillDemo {
error!(" Failed to apply book update: {}", e);
self.stats.errors += 1;
}
}
},
StreamMessage::Trade { data } => {
info!(" Processing trade: {} {} @ {}",
data.side.as_str(), data.size, data.price);
info!(
" Processing trade: {} {} @ {}",
data.side.as_str(),
data.size,
data.price
);
if let Err(e) = self.fill_processor.process_fill(data.clone()) {
error!(" Failed to process fill: {}", e);
self.stats.errors += 1;
}
}
},
StreamMessage::Heartbeat { timestamp } => {
debug!(" Received heartbeat at: {}", timestamp);
}
},
_ => {
info!(" Unhandled message type");
}
},
}
}
Ok(())
}
/// Demo 9: Performance and Analytics
pub async fn demo_performance_analytics(&mut self) -> Result<()> {
info!("=== Demo 9: Performance and Analytics ===");
// Get fill engine statistics
let fill_stats = self.fill_engine.get_stats();
info!("Fill engine statistics:");
@@ -643,7 +677,7 @@ impl PolyfillDemo {
info!(" Total fills: {}", fill_stats.total_fills);
info!(" Total volume: {}", fill_stats.total_volume);
info!(" Total fees: {}", fill_stats.total_fees);
// Get fill processor statistics
let processor_stats = self.fill_processor.get_stats();
info!("Fill processor statistics:");
@@ -652,7 +686,7 @@ impl PolyfillDemo {
info!(" Pending volume: {}", processor_stats.pending_volume);
info!(" Processed fills: {}", processor_stats.processed_fills);
info!(" Processed volume: {}", processor_stats.processed_volume);
// Get demo statistics
info!("Demo statistics:");
info!(" API calls: {}", self.stats.api_calls);
@@ -661,50 +695,51 @@ impl PolyfillDemo {
info!(" Stream messages: {}", self.stats.stream_messages);
info!(" Errors: {}", self.stats.errors);
info!(" Total volume: {}", self.stats.total_volume);
// Calculate error rate
let total_operations = self.stats.api_calls + self.stats.orders_processed + self.stats.stream_messages;
let total_operations =
self.stats.api_calls + self.stats.orders_processed + self.stats.stream_messages;
let error_rate = if total_operations > 0 {
(self.stats.errors as f64 / total_operations as f64) * 100.0
} else {
0.0
};
info!(" Error rate: {:.2}%", error_rate);
Ok(())
}
/// Run all demos
pub async fn run_all_demos(&mut self) -> Result<()> {
info!("Starting comprehensive polyfill-rs demo...");
// Run all demo sections
self.demo_basic_api_operations().await?;
sleep(Duration::from_millis(500)).await;
self.demo_order_book_operations().await?;
sleep(Duration::from_millis(500)).await;
self.demo_market_data_operations().await?;
sleep(Duration::from_millis(500)).await;
self.demo_order_operations().await?;
sleep(Duration::from_millis(500)).await;
self.demo_fill_execution().await?;
sleep(Duration::from_millis(500)).await;
self.demo_utility_functions().await?;
sleep(Duration::from_millis(500)).await;
self.demo_error_handling().await?;
sleep(Duration::from_millis(500)).await;
self.demo_streaming_capabilities().await?;
sleep(Duration::from_millis(500)).await;
self.demo_performance_analytics().await?;
info!("Comprehensive demo completed successfully!");
Ok(())
}
@@ -714,18 +749,18 @@ impl PolyfillDemo {
async fn main() -> Result<()> {
// Initialize logging
tracing_subscriber::fmt::init();
info!("Polyfill-rs Comprehensive Demo");
info!("==============================");
// Create and run demo
let mut demo = PolyfillDemo::new()?;
if let Err(e) = demo.run_all_demos().await {
error!("Demo failed: {}", e);
std::process::exit(1);
}
info!("Demo completed successfully!");
Ok(())
}
}
+95 -56
View File
@@ -54,100 +54,125 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Comparing with polymarket-rs-client baseline:");
println!(" 88,053 allocs, 81,823 frees, 15,945,966 bytes allocated");
println!();
// Load environment variables
dotenv::dotenv().ok();
let client = ClobClient::new_internet("https://clob.polymarket.com");
// Test 1: Market Data Fetching Memory Usage
println!("📊 Test 1: Market Data Fetching Memory");
println!("=====================================");
// Reset and measure market data fetching
reset_counters();
let start_stats = get_memory_stats();
let start_time = Instant::now();
let result = client.get_sampling_simplified_markets(None).await;
let duration = start_time.elapsed();
let end_stats = get_memory_stats();
match result {
Ok(markets) => {
println!("✅ Fetched {} markets in {:?}", markets.data.len(), duration);
println!(
"✅ Fetched {} markets in {:?}",
markets.data.len(),
duration
);
let (bytes_allocated, allocs, deallocs) = (
end_stats.0 - start_stats.0,
end_stats.1 - start_stats.1,
end_stats.2 - start_stats.2,
);
println!("📈 polyfill-rs memory usage:");
println!(" {} allocs, {} frees, {} bytes allocated", allocs, deallocs, bytes_allocated);
println!("📊 vs baseline (15,945,966 bytes): {:.1}x less memory",
15_945_966.0 / bytes_allocated as f64);
println!("📊 vs baseline ({} allocs): {:.1}x fewer allocations",
88_053, 88_053.0 / allocs as f64);
}
println!(
" {} allocs, {} frees, {} bytes allocated",
allocs, deallocs, bytes_allocated
);
println!(
"📊 vs baseline (15,945,966 bytes): {:.1}x less memory",
15_945_966.0 / bytes_allocated as f64
);
println!(
"📊 vs baseline ({} allocs): {:.1}x fewer allocations",
88_053,
88_053.0 / allocs as f64
);
},
Err(e) => {
println!("❌ Error: {}", e);
println!("⚠️ Still measuring memory usage of error handling...");
let (bytes_allocated, allocs, deallocs) = (
end_stats.0 - start_stats.0,
end_stats.1 - start_stats.1,
end_stats.2 - start_stats.2,
);
println!("📈 Memory usage (even with error):");
println!(" {} allocs, {} frees, {} bytes allocated", allocs, deallocs, bytes_allocated);
}
println!(
" {} allocs, {} frees, {} bytes allocated",
allocs, deallocs, bytes_allocated
);
},
}
// Test 2: Order Book Memory Efficiency
println!("\n📊 Test 2: Order Book Memory Efficiency");
println!("======================================");
reset_counters();
let start_stats = get_memory_stats();
// Create order book and populate it
let mut book = OrderBookImpl::new("test_token".to_string(), 100);
// Add many orders to test memory efficiency
for i in 0..1000 {
let price = Decimal::from_str(&format!("0.{:04}", 5000 + (i % 100))).unwrap();
let size = Decimal::from_str("100.0").unwrap();
let delta = polyfill_rs::OrderDelta {
token_id: "test_token".to_string(),
timestamp: chrono::Utc::now(),
side: if i % 2 == 0 { polyfill_rs::Side::BUY } else { polyfill_rs::Side::SELL },
side: if i % 2 == 0 {
polyfill_rs::Side::BUY
} else {
polyfill_rs::Side::SELL
},
price,
size,
sequence: i as u64,
};
let _ = book.apply_delta(delta);
}
let end_stats = get_memory_stats();
let (bytes_allocated, allocs, deallocs) = (
end_stats.0 - start_stats.0,
end_stats.1 - start_stats.1,
end_stats.2 - start_stats.2,
);
println!("📈 Order book (1000 updates):");
println!(" {} allocs, {} frees, {} bytes allocated", allocs, deallocs, bytes_allocated);
println!("📊 Per update: {:.1} bytes/update", bytes_allocated as f64 / 1000.0);
println!(
" {} allocs, {} frees, {} bytes allocated",
allocs, deallocs, bytes_allocated
);
println!(
"📊 Per update: {:.1} bytes/update",
bytes_allocated as f64 / 1000.0
);
// Test 3: JSON Parsing Memory
println!("\n📊 Test 3: JSON Parsing Memory Usage");
println!("===================================");
let sample_json = r#"{
"data": [
{
@@ -168,69 +193,83 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
]
}"#;
reset_counters();
let start_stats = get_memory_stats();
// Parse JSON 1000 times to measure memory usage
for _ in 0..1000 {
let _: Result<serde_json::Value, _> = serde_json::from_str(sample_json);
}
let end_stats = get_memory_stats();
let (bytes_allocated, allocs, deallocs) = (
end_stats.0 - start_stats.0,
end_stats.1 - start_stats.1,
end_stats.2 - start_stats.2,
);
println!("📈 JSON parsing (1000 operations):");
println!(" {} allocs, {} frees, {} bytes allocated", allocs, deallocs, bytes_allocated);
println!("📊 Per parse: {:.1} bytes/parse", bytes_allocated as f64 / 1000.0);
println!(
" {} allocs, {} frees, {} bytes allocated",
allocs, deallocs, bytes_allocated
);
println!(
"📊 Per parse: {:.1} bytes/parse",
bytes_allocated as f64 / 1000.0
);
// Test 4: Fixed-point vs Decimal Memory
println!("\n📊 Test 4: Fixed-point vs Decimal Memory");
println!("=======================================");
// Test Decimal operations
reset_counters();
let start_stats = get_memory_stats();
let mut decimals = Vec::new();
for i in 0..1000 {
let decimal = Decimal::from_str(&format!("0.{:04}", i)).unwrap();
decimals.push(decimal);
}
let end_stats = get_memory_stats();
let decimal_memory = end_stats.0 - start_stats.0;
let decimal_allocs = end_stats.1 - start_stats.1;
println!("📈 Decimal operations (1000 values):");
println!(" {} allocs, {} bytes allocated", decimal_allocs, decimal_memory);
println!(
" {} allocs, {} bytes allocated",
decimal_allocs, decimal_memory
);
// Test fixed-point operations
reset_counters();
let start_stats = get_memory_stats();
let mut fixed_points = Vec::new();
for i in 0..1000 {
let fixed_point = (i as u32) * 10000; // Scale factor of 10000
fixed_points.push(fixed_point);
}
let end_stats = get_memory_stats();
let fixed_memory = end_stats.0 - start_stats.0;
let fixed_allocs = end_stats.1 - start_stats.1;
println!("📈 Fixed-point operations (1000 values):");
println!(" {} allocs, {} bytes allocated", fixed_allocs, fixed_memory);
println!(
" {} allocs, {} bytes allocated",
fixed_allocs, fixed_memory
);
if decimal_memory > 0 && fixed_memory > 0 {
println!("📊 Fixed-point vs Decimal: {:.1}x less memory",
decimal_memory as f64 / fixed_memory as f64);
println!(
"📊 Fixed-point vs Decimal: {:.1}x less memory",
decimal_memory as f64 / fixed_memory as f64
);
}
println!("\n🎯 Memory Benchmark Summary");
println!("==========================");
println!("Key Findings:");
@@ -238,8 +277,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" • Fixed-point arithmetic: Significantly less memory than Decimal");
println!(" • JSON parsing: Efficient deserialization");
println!(" • Network operations: Memory usage dominated by response size");
println!("\nNote: These are ACTUAL measured values, not estimates!");
Ok(())
}
+46 -29
View File
@@ -5,18 +5,24 @@ use std::time::Instant;
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🚀 Network Optimization Test - polyfill-rs");
println!("===========================================");
// Test different client configurations
let clients = vec![
("Standard", ClobClient::new("https://clob.polymarket.com")),
("Colocated", ClobClient::new_colocated("https://clob.polymarket.com")),
("Internet", ClobClient::new_internet("https://clob.polymarket.com")),
(
"Colocated",
ClobClient::new_colocated("https://clob.polymarket.com"),
),
(
"Internet",
ClobClient::new_internet("https://clob.polymarket.com"),
),
];
for (name, client) in clients {
println!("\n📊 Testing {} Client Configuration", name);
println!("{}=", "=".repeat(40 + name.len()));
// Test 1: Server time (baseline latency)
println!(" 🔍 Server Time Test:");
let mut times = Vec::new();
@@ -27,36 +33,42 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let duration = start.elapsed();
times.push(duration);
if i < 2 {
println!(" Run {}: ✅ {} in {:?}", i+1, timestamp, duration);
println!(" Run {}: ✅ {} in {:?}", i + 1, timestamp, duration);
}
}
},
Err(e) => {
let duration = start.elapsed();
times.push(duration);
if i < 2 {
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
}
}
},
}
}
if !times.is_empty() {
let avg = times.iter().sum::<std::time::Duration>() / times.len() as u32;
let min = times.iter().min().unwrap();
let max = times.iter().max().unwrap();
let std_dev = {
let mean = avg.as_millis() as f64;
let variance = times.iter()
let variance = times
.iter()
.map(|t| (t.as_millis() as f64 - mean).powi(2))
.sum::<f64>() / times.len() as f64;
.sum::<f64>()
/ times.len() as f64;
variance.sqrt()
};
println!(" 📈 Average: {:.1}ms ± {:.1}ms", avg.as_millis(), std_dev);
println!(
" 📈 Average: {:.1}ms ± {:.1}ms",
avg.as_millis(),
std_dev
);
println!(" 📊 Range: {:?} - {:?}", min, max);
println!(" 🌐 Best: {:?}", min);
}
// Test 2: Market data fetching
println!(" 🔍 Market Data Test:");
let mut times = Vec::new();
@@ -67,29 +79,34 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let duration = start.elapsed();
times.push(duration);
if i < 2 {
println!(" Run {}: ✅ {} markets in {:?}", i+1, markets.data.len(), duration);
println!(
" Run {}: ✅ {} markets in {:?}",
i + 1,
markets.data.len(),
duration
);
}
}
},
Err(e) => {
let duration = start.elapsed();
times.push(duration);
if i < 2 {
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
}
}
},
}
}
if !times.is_empty() {
let avg = times.iter().sum::<std::time::Duration>() / times.len() as u32;
let min = times.iter().min().unwrap();
let max = times.iter().max().unwrap();
println!(" 📈 Average: {:?}", avg);
println!(" 📊 Range: {:?} - {:?}", min, max);
println!(" 🌐 Best: {:?}", min);
}
// Test 3: Connection reuse test
println!(" 🔍 Connection Reuse Test:");
let start = Instant::now();
@@ -99,18 +116,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
if i == 0 {
println!(" First request: {:?}", start.elapsed());
}
}
},
Err(e) => {
println!(" Error on request {}: {}", i+1, e);
println!(" Error on request {}: {}", i + 1, e);
break;
}
},
}
}
let total_time = start.elapsed();
println!(" 📈 5 requests total: {:?}", total_time);
println!(" 📊 Average per request: {:?}", total_time / 5);
}
println!("\n🎯 Network Optimization Summary");
println!("===============================");
println!("HTTP Client Optimizations Applied:");
@@ -119,17 +136,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" • HTTP/2 with keep-alive");
println!(" • Optimized timeouts for different environments");
println!(" • Compression enabled/disabled based on use case");
println!("\nConfiguration Recommendations:");
println!(" • Colocated: Use for servers close to exchange");
println!(" • Internet: Use for retail/remote connections");
println!(" • Standard: Balanced settings for most use cases");
println!("\nAdditional Optimizations Available:");
println!(" • Custom DNS resolver");
println!(" • Connection pre-warming");
println!(" • Request batching");
println!(" • Circuit breaker patterns");
Ok(())
}
+46 -29
View File
@@ -5,13 +5,13 @@ use std::time::Instant;
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🌐 Network Latency Test for polyfill-rs");
println!("======================================");
let client = ClobClient::new("https://clob.polymarket.com");
// Test 1: Simplified markets (comparable to original 404.5ms benchmark)
println!("\n📊 Test 1: Simplified Markets");
println!("-----------------------------");
let mut times = Vec::new();
for i in 0..5 {
let start = Instant::now();
@@ -19,31 +19,38 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(markets) => {
let duration = start.elapsed();
times.push(duration);
println!(" Run {}: ✅ {} markets in {:?}", i+1, markets.data.len(), duration);
}
println!(
" Run {}: ✅ {} markets in {:?}",
i + 1,
markets.data.len(),
duration
);
},
Err(e) => {
let duration = start.elapsed();
times.push(duration);
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
}
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
},
}
}
if !times.is_empty() {
let avg = times.iter().sum::<std::time::Duration>() / times.len() as u32;
let min = times.iter().min().unwrap();
let max = times.iter().max().unwrap();
println!(" 📈 Average: {:?}", avg);
println!(" 📊 Range: {:?} - {:?}", min, max);
println!(" 🆚 vs original (404.5ms): {:.1}x",
404.5 / avg.as_millis() as f64);
println!(
" 🆚 vs original (404.5ms): {:.1}x",
404.5 / avg.as_millis() as f64
);
}
// Test 2: Full markets
println!("\n📊 Test 2: Full Markets");
println!("----------------------");
let mut times = Vec::new();
for i in 0..3 {
let start = Instant::now();
@@ -51,29 +58,34 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(markets) => {
let duration = start.elapsed();
times.push(duration);
println!(" Run {}: ✅ {} markets in {:?}", i+1, markets.data.len(), duration);
}
println!(
" Run {}: ✅ {} markets in {:?}",
i + 1,
markets.data.len(),
duration
);
},
Err(e) => {
let duration = start.elapsed();
times.push(duration);
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
}
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
},
}
}
if !times.is_empty() {
let avg = times.iter().sum::<std::time::Duration>() / times.len() as u32;
let min = times.iter().min().unwrap();
let max = times.iter().max().unwrap();
println!(" 📈 Average: {:?}", avg);
println!(" 📊 Range: {:?} - {:?}", min, max);
}
// Test 3: Server time (lightweight endpoint)
println!("\n📊 Test 3: Server Time (Lightweight)");
println!("-----------------------------------");
let mut times = Vec::new();
for i in 0..10 {
let start = Instant::now();
@@ -82,27 +94,32 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let duration = start.elapsed();
times.push(duration);
if i == 0 {
println!(" Run {}: ✅ Timestamp {} in {:?}", i+1, timestamp, duration);
println!(
" Run {}: ✅ Timestamp {} in {:?}",
i + 1,
timestamp,
duration
);
}
}
},
Err(e) => {
let duration = start.elapsed();
times.push(duration);
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
}
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
},
}
}
if !times.is_empty() {
let avg = times.iter().sum::<std::time::Duration>() / times.len() as u32;
let min = times.iter().min().unwrap();
let max = times.iter().max().unwrap();
println!(" 📈 Average: {:?}", avg);
println!(" 📊 Range: {:?} - {:?}", min, max);
println!(" 🌐 Network baseline latency: ~{:?}", min);
}
println!("\n🎯 Summary");
println!("=========");
println!("Network latency dominates end-to-end performance.");
@@ -115,6 +132,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("• Run from same geographic location");
println!("• Use same network conditions");
println!("• Measure full end-to-end latency");
Ok(())
}
+55 -32
View File
@@ -5,12 +5,12 @@ use std::time::Instant;
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🔐 Proper Authenticated Benchmark - Real Performance");
println!("===================================================");
// Note: For a real benchmark, we'd need:
// 1. A private key to initialize the signer
// 2. Proper API credential setup
// 3. Valid market/token IDs
println!("⚠️ Authentication Setup Required");
println!("================================");
println!("To get real order creation benchmarks, we need:");
@@ -18,13 +18,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" 2. Proper client initialization with credentials");
println!(" 3. Valid market context for orders");
println!();
// What we CAN measure: Network performance
let client = ClobClient::new_internet("https://clob.polymarket.com");
println!("📊 What We CAN Measure: Network Performance");
println!("==========================================");
// Test 1: Basic connectivity (network baseline)
println!("\n🔍 Network Baseline Test:");
let mut baseline_times = Vec::new();
@@ -33,24 +33,30 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let result = client.get_server_time().await;
let duration = start.elapsed();
baseline_times.push(duration);
match result {
Ok(timestamp) => {
if i < 2 {
println!(" Run {}: ✅ Server time {} in {:?}", i+1, timestamp, duration);
println!(
" Run {}: ✅ Server time {} in {:?}",
i + 1,
timestamp,
duration
);
}
}
},
Err(e) => {
if i < 2 {
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
}
}
},
}
}
let baseline_avg = baseline_times.iter().sum::<std::time::Duration>() / baseline_times.len() as u32;
let baseline_avg =
baseline_times.iter().sum::<std::time::Duration>() / baseline_times.len() as u32;
println!(" 📈 Network baseline: {:?}", baseline_avg);
// Test 2: Market data (what we successfully measured before)
println!("\n🔍 Market Data Performance:");
let mut market_times = Vec::new();
@@ -59,42 +65,57 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let result = client.get_sampling_simplified_markets(None).await;
let duration = start.elapsed();
market_times.push(duration);
match result {
Ok(markets) => {
if i < 2 {
println!(" Run {}: ✅ {} markets in {:?}", i+1, markets.data.len(), duration);
println!(
" Run {}: ✅ {} markets in {:?}",
i + 1,
markets.data.len(),
duration
);
}
}
},
Err(e) => {
if i < 2 {
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
}
}
},
}
}
let market_avg = market_times.iter().sum::<std::time::Duration>() / market_times.len() as u32;
println!(" 📈 Market data average: {:?}", market_avg);
println!(" 🆚 vs original (404.5ms): {:.1}x faster", 404.5 / market_avg.as_millis() as f64);
println!(
" 🆚 vs original (404.5ms): {:.1}x faster",
404.5 / market_avg.as_millis() as f64
);
println!("\n🎯 Realistic Performance Estimates");
println!("=================================");
println!("Based on our network measurements:");
println!(" • Network baseline: {:?}", baseline_avg);
println!(" • Market data: {:?} (3.8x faster than original)", market_avg);
println!(
" • Market data: {:?} (3.8x faster than original)",
market_avg
);
println!();
println!("For order creation (266.5ms original):");
println!(" • Network component: ~{:?} (measured)", baseline_avg);
println!(" • EIP-712 signing: ~5-20ms (typical crypto operation)");
println!(" • JSON serialization: ~1ms (measured separately)");
println!(" • Estimated total: ~{:?} (vs 266.5ms original)",
baseline_avg + std::time::Duration::from_millis(15));
println!(" • Estimated improvement: {:.1}x faster",
266.5 / (baseline_avg.as_millis() + 15) as f64);
println!(
" • Estimated total: ~{:?} (vs 266.5ms original)",
baseline_avg + std::time::Duration::from_millis(15)
);
println!(
" • Estimated improvement: {:.1}x faster",
266.5 / (baseline_avg.as_millis() + 15) as f64
);
println!("\n📊 Summary of Real Performance");
println!("=============================");
println!("What we measured:");
@@ -103,11 +124,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" ✅ Computational: microsecond-scale operations");
println!();
println!("What we estimate:");
println!(" 📊 Order creation: ~{:?} (vs 266.5ms = 2.2x faster)",
baseline_avg + std::time::Duration::from_millis(15));
println!(
" 📊 Order creation: ~{:?} (vs 266.5ms = 2.2x faster)",
baseline_avg + std::time::Duration::from_millis(15)
);
println!(" 📊 All operations benefit from 11% network optimization");
println!(" 📊 Connection reuse provides 70% improvement on subsequent calls");
println!(" 📊 Request batching provides 200% improvement for parallel operations");
Ok(())
}
+101 -76
View File
@@ -3,23 +3,23 @@
//! This example demonstrates all available API endpoints in a simple, easy-to-run format.
//! It can be run without authentication credentials and will test all public endpoints.
use polyfill_rs::{ClobClient, Side, Result, PolyfillError};
use polyfill_rs::{ClobClient, PolyfillError, Result, Side};
use rust_decimal::Decimal;
use tokio::time::{sleep, Duration};
use tracing::{info, error, warn};
use tracing::{error, info, warn};
/// Quick demo that tests all available endpoints
#[tokio::main]
async fn main() -> Result<()> {
// Initialize logging
tracing_subscriber::fmt::init();
info!("Polyfill-rs Quick Demo");
info!("======================");
// Create client
let client = ClobClient::new("https://clob.polymarket.com");
// Test 1: Basic connectivity
info!("\nTesting API Connectivity...");
match test_connectivity(&client).await {
@@ -27,37 +27,37 @@ async fn main() -> Result<()> {
Err(e) => {
error!("API connectivity test failed: {}", e);
return Err(e);
}
},
}
// Test 2: Get a valid token ID from markets
info!("\nGetting Market Data...");
let token_id = match get_valid_token_id(&client).await {
Ok(id) => {
info!("Found valid token ID: {}", id);
id
}
},
Err(e) => {
error!("Failed to get valid token ID: {}", e);
return Err(e);
}
},
};
// Test 3: Test all market data endpoints
info!("\nTesting Market Data Endpoints...");
test_market_data_endpoints(&client, &token_id).await?;
// Test 4: Test error handling
info!("\nTesting Error Handling...");
test_error_handling(&client).await?;
// Test 5: Performance test
info!("\nTesting Performance...");
test_performance(&client, &token_id).await?;
info!("\nAll tests completed successfully!");
info!("The polyfill-rs client is working correctly with the Polymarket API.");
Ok(())
}
@@ -66,39 +66,43 @@ async fn test_connectivity(client: &ClobClient) -> Result<()> {
// Test /ok endpoint
let is_ok = client.get_ok().await;
if !is_ok {
return Err(PolyfillError::network("API not responding", std::io::Error::other("API not responding")));
return Err(PolyfillError::network(
"API not responding",
std::io::Error::other("API not responding"),
));
}
info!(" /ok endpoint responding");
// Test /time endpoint
let server_time = client.get_server_time().await?;
info!(" Server time: {}", server_time);
// Verify server time is reasonable (within last 24 hours)
let current_time = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let time_diff = server_time.abs_diff(current_time);
if time_diff > 86400 { // 24 hours
if time_diff > 86400 {
// 24 hours
warn!(" Server time seems off (diff: {} seconds)", time_diff);
} else {
info!(" Server time is reasonable");
}
Ok(())
}
/// Get a valid token ID from the markets endpoint
async fn get_valid_token_id(client: &ClobClient) -> Result<String> {
let markets = client.get_sampling_markets(None).await?;
if markets.data.is_empty() {
return Err(PolyfillError::api(404, "No markets found"));
}
// Find a market with active tokens
for market in &markets.data {
if market.active && !market.closed {
@@ -113,8 +117,11 @@ async fn get_valid_token_id(client: &ClobClient) -> Result<String> {
}
}
}
Err(PolyfillError::api(404, "No active markets with valid tokens found"))
Err(PolyfillError::api(
404,
"No active markets with valid tokens found",
))
}
/// Test all market data endpoints
@@ -122,42 +129,46 @@ async fn test_market_data_endpoints(client: &ClobClient, token_id: &str) -> Resu
// Test order book
info!(" Testing order book endpoint...");
let order_book = client.get_order_book(token_id).await?;
info!(" Order book: {} bids, {} asks", order_book.bids.len(), order_book.asks.len());
info!(
" Order book: {} bids, {} asks",
order_book.bids.len(),
order_book.asks.len()
);
// Test midpoint
info!(" Testing midpoint endpoint...");
let midpoint = client.get_midpoint(token_id).await?;
info!(" Midpoint: {}", midpoint.mid);
// Test spread
info!(" Testing spread endpoint...");
let spread = client.get_spread(token_id).await?;
info!(" Spread: {}", spread.spread);
// Test buy price
info!(" Testing buy price endpoint...");
let buy_price = client.get_price(token_id, Side::BUY).await?;
info!(" Buy price: {}", buy_price.price);
// Test sell price
info!(" Testing sell price endpoint...");
let sell_price = client.get_price(token_id, Side::SELL).await?;
info!(" Sell price: {}", sell_price.price);
// Test tick size
info!(" Testing tick size endpoint...");
let tick_size = client.get_tick_size(token_id).await?;
info!(" Tick size: {}", tick_size);
// Test neg risk
info!(" Testing neg risk endpoint...");
let neg_risk = client.get_neg_risk(token_id).await?;
info!(" Neg risk: {}", neg_risk);
// Validate data consistency
info!(" Validating data consistency...");
validate_market_data(&order_book, &midpoint, &spread, &buy_price, &sell_price)?;
Ok(())
}
@@ -175,37 +186,39 @@ fn validate_market_data(
} else {
info!(" Order book has liquidity");
}
// Check that prices are positive
if buy_price.price <= Decimal::ZERO {
warn!(" Buy price is not positive: {}", buy_price.price);
} else {
info!(" Buy price is positive");
}
if sell_price.price <= Decimal::ZERO {
warn!(" Sell price is not positive: {}", sell_price.price);
} else {
info!(" Sell price is positive");
}
// Check that spread is reasonable
if spread.spread < Decimal::ZERO {
warn!(" Spread is negative: {}", spread.spread);
} else {
info!(" Spread is non-negative");
}
// Check that midpoint is between buy and sell prices (if both exist)
if buy_price.price > Decimal::ZERO && sell_price.price > Decimal::ZERO {
if midpoint.mid < buy_price.price || midpoint.mid > sell_price.price {
warn!(" Midpoint {} is not between buy {} and sell {}",
midpoint.mid, buy_price.price, sell_price.price);
warn!(
" Midpoint {} is not between buy {} and sell {}",
midpoint.mid, buy_price.price, sell_price.price
);
} else {
info!(" Midpoint is between buy and sell prices");
}
}
Ok(())
}
@@ -217,35 +230,33 @@ async fn test_error_handling(client: &ClobClient) -> Result<()> {
match result {
Ok(_) => {
warn!(" Invalid token ID returned data instead of error");
}
Err(e) => {
match e {
PolyfillError::Api { status, .. } => {
if status >= 400 {
info!(" Invalid token ID correctly returned error: {}", status);
} else {
warn!(" Unexpected status code for invalid token: {}", status);
}
},
Err(e) => match e {
PolyfillError::Api { status, .. } => {
if status >= 400 {
info!(" Invalid token ID correctly returned error: {}", status);
} else {
warn!(" Unexpected status code for invalid token: {}", status);
}
_ => {
info!(" Invalid token ID returned error: {:?}", e);
}
}
}
},
_ => {
info!(" Invalid token ID returned error: {:?}", e);
},
},
}
// Test with empty token ID
info!(" Testing empty token ID...");
let result = client.get_order_book("").await;
match result {
Ok(_) => {
warn!(" Empty token ID returned data instead of error");
}
},
Err(e) => {
info!(" Empty token ID correctly returned error: {:?}", e);
}
},
}
Ok(())
}
@@ -254,56 +265,70 @@ async fn test_performance(client: &ClobClient, token_id: &str) -> Result<()> {
let mut total_time = Duration::from_secs(0);
let mut success_count = 0;
let test_count = 5;
info!(" Running {} performance tests...", test_count);
for i in 1..=test_count {
let start = std::time::Instant::now();
// Test a mix of endpoints
let results = tokio::join!(
client.get_server_time(),
client.get_midpoint(token_id),
client.get_spread(token_id),
);
let duration = start.elapsed();
total_time += duration;
match results {
(Ok(_), Ok(_), Ok(_)) => {
success_count += 1;
info!(" Test {}: PASSED {:.2}ms", i, duration.as_secs_f64() * 1000.0);
}
info!(
" Test {}: PASSED {:.2}ms",
i,
duration.as_secs_f64() * 1000.0
);
},
_ => {
warn!(" Test {}: FAILED in {:.2}ms", i, duration.as_secs_f64() * 1000.0);
}
warn!(
" Test {}: FAILED in {:.2}ms",
i,
duration.as_secs_f64() * 1000.0
);
},
}
// Small delay between tests
sleep(Duration::from_millis(100)).await;
}
let avg_time = total_time / test_count as u32;
let success_rate = (success_count as f64 / test_count as f64) * 100.0;
info!(" Performance Summary:");
info!(" Success rate: {:.1}%", success_rate);
info!(" Average response time: {:.2}ms", avg_time.as_secs_f64() * 1000.0);
info!(
" Average response time: {:.2}ms",
avg_time.as_secs_f64() * 1000.0
);
info!(" Total time: {:.2}s", total_time.as_secs_f64());
// Performance thresholds
if avg_time > Duration::from_secs(2) {
warn!(" Average response time is slow: {:.2}ms", avg_time.as_secs_f64() * 1000.0);
warn!(
" Average response time is slow: {:.2}ms",
avg_time.as_secs_f64() * 1000.0
);
} else {
info!(" Response times are acceptable");
}
if success_rate < 80.0 {
warn!(" Success rate is low: {:.1}%", success_rate);
} else {
info!(" Success rate is good");
}
Ok(())
}
+108 -64
View File
@@ -7,13 +7,13 @@ use std::time::Instant;
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load environment variables from .env file
dotenv::dotenv().ok();
println!("🚀 Real Network Benchmark - polyfill-rs vs polymarket-rs-client");
println!("================================================================");
// Set up client with credentials
let client = ClobClient::new("https://clob.polymarket.com");
// API credentials from .env file
let _api_key = std::env::var("POLYMARKET_API_KEY")
.map_err(|_| "POLYMARKET_API_KEY not found in .env file")?;
@@ -21,16 +21,16 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.map_err(|_| "POLYMARKET_SECRET not found in .env file")?;
let _passphrase = std::env::var("POLYMARKET_PASSPHRASE")
.map_err(|_| "POLYMARKET_PASSPHRASE not found in .env file")?;
println!("✅ Loaded API credentials from .env file");
println!("🔑 Using API credentials for authenticated requests");
// Test 1: Simplified Markets (matches original 404.5ms benchmark)
println!("\n📊 Test 1: Fetch Simplified Markets");
println!("===================================");
println!("Original polymarket-rs-client: 404.5ms ± 22.9ms");
let mut times = Vec::new();
for i in 0..10 {
let start = Instant::now();
@@ -39,42 +39,59 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let duration = start.elapsed();
times.push(duration);
if i < 3 {
println!(" Run {}: ✅ {} markets in {:?}", i+1, markets.data.len(), duration);
println!(
" Run {}: ✅ {} markets in {:?}",
i + 1,
markets.data.len(),
duration
);
}
}
},
Err(e) => {
let duration = start.elapsed();
times.push(duration);
if i < 3 {
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
}
}
},
}
}
if !times.is_empty() {
let avg = times.iter().sum::<std::time::Duration>() / times.len() as u32;
let min = times.iter().min().unwrap();
let max = times.iter().max().unwrap();
let std_dev = {
let mean = avg.as_millis() as f64;
let variance = times.iter()
let variance = times
.iter()
.map(|t| (t.as_millis() as f64 - mean).powi(2))
.sum::<f64>() / times.len() as f64;
.sum::<f64>()
/ times.len() as f64;
variance.sqrt()
};
println!(" 📈 polyfill-rs: {:.1}ms ± {:.1}ms", avg.as_millis(), std_dev);
println!(
" 📈 polyfill-rs: {:.1}ms ± {:.1}ms",
avg.as_millis(),
std_dev
);
println!(" 📊 Range: {:?} - {:?}", min, max);
println!(" 🆚 vs original: {:.1}x {}",
404.5 / avg.as_millis() as f64,
if avg.as_millis() < 405 { "faster" } else { "slower" });
println!(
" 🆚 vs original: {:.1}x {}",
404.5 / avg.as_millis() as f64,
if avg.as_millis() < 405 {
"faster"
} else {
"slower"
}
);
}
// Test 2: Full Markets (no direct comparison, but good to measure)
println!("\n📊 Test 2: Fetch Full Markets");
println!("=============================");
let mut times = Vec::new();
for i in 0..5 {
let start = Instant::now();
@@ -83,38 +100,43 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let duration = start.elapsed();
times.push(duration);
if i < 2 {
println!(" Run {}: ✅ {} markets in {:?}", i+1, markets.data.len(), duration);
println!(
" Run {}: ✅ {} markets in {:?}",
i + 1,
markets.data.len(),
duration
);
}
}
},
Err(e) => {
let duration = start.elapsed();
times.push(duration);
if i < 2 {
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
}
}
},
}
}
if !times.is_empty() {
let avg = times.iter().sum::<std::time::Duration>() / times.len() as u32;
let min = times.iter().min().unwrap();
let max = times.iter().max().unwrap();
println!(" 📈 polyfill-rs: {:?} average", avg);
println!(" 📊 Range: {:?} - {:?}", min, max);
}
// Test 3: Order Creation with EIP-712 (matches original 266.5ms benchmark)
println!("\n📊 Test 3: Create Order with EIP-712 Signature");
println!("==============================================");
println!("Original polymarket-rs-client: 266.5ms ± 28.6ms");
// First, try to create or derive API key
match client.create_or_derive_api_key(None).await {
Ok(_creds) => {
println!(" 🔑 API credentials set up successfully");
// Now test order creation
let mut times = Vec::new();
for i in 0..5 {
@@ -124,59 +146,71 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Decimal::from_str("1.0").unwrap(), // Minimum order size
Side::BUY,
);
let start = Instant::now();
match client.create_order(&order_args, None, None, None).await {
Ok(_order) => {
let duration = start.elapsed();
times.push(duration);
if i < 2 {
println!(" Run {}: ✅ Order created in {:?}", i+1, duration);
println!(" Run {}: ✅ Order created in {:?}", i + 1, duration);
}
// Cancel the order immediately to clean up
// Note: Would need to extract order ID from response for cancellation
}
},
Err(e) => {
let duration = start.elapsed();
times.push(duration);
if i < 2 {
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
}
}
},
}
}
if !times.is_empty() {
let avg = times.iter().sum::<std::time::Duration>() / times.len() as u32;
let min = times.iter().min().unwrap();
let max = times.iter().max().unwrap();
let std_dev = {
let mean = avg.as_millis() as f64;
let variance = times.iter()
let variance = times
.iter()
.map(|t| (t.as_millis() as f64 - mean).powi(2))
.sum::<f64>() / times.len() as f64;
.sum::<f64>()
/ times.len() as f64;
variance.sqrt()
};
println!(" 📈 polyfill-rs: {:.1}ms ± {:.1}ms", avg.as_millis(), std_dev);
println!(
" 📈 polyfill-rs: {:.1}ms ± {:.1}ms",
avg.as_millis(),
std_dev
);
println!(" 📊 Range: {:?} - {:?}", min, max);
println!(" 🆚 vs original: {:.1}x {}",
266.5 / avg.as_millis() as f64,
if avg.as_millis() < 267 { "faster" } else { "slower" });
println!(
" 🆚 vs original: {:.1}x {}",
266.5 / avg.as_millis() as f64,
if avg.as_millis() < 267 {
"faster"
} else {
"slower"
}
);
}
}
},
Err(e) => {
println!(" ❌ Could not set up API credentials: {}", e);
println!(" ⚠️ Skipping order creation benchmark");
}
},
}
// Test 4: Memory usage comparison
println!("\n📊 Test 4: Memory Usage Analysis");
println!("===============================");
println!("Original: 88,053 allocs, 81,823 frees, 15,945,966 bytes allocated");
// This would require memory profiling tools for accurate measurement
println!(" 🔧 polyfill-rs optimizations:");
println!(" • Fixed-point arithmetic reduces allocation overhead");
@@ -184,34 +218,38 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" • Zero-allocation order book updates");
println!(" • Pre-allocated pools for high-frequency operations");
println!(" 📈 Estimated: ~10x reduction in allocations");
// Test 5: Computational performance (our strength)
println!("\n📊 Test 5: Computational Performance");
println!("===================================");
use polyfill_rs::OrderBookImpl;
let mut book = OrderBookImpl::new("test_token".to_string(), 100);
// Order book updates
let start = Instant::now();
for i in 0..10000 {
let price = Decimal::from_str(&format!("0.{:04}", 5000 + (i % 1000))).unwrap();
let size = Decimal::from_str("100.0").unwrap();
let delta = polyfill_rs::OrderDelta {
token_id: "test_token".to_string(),
timestamp: chrono::Utc::now(),
side: if i % 2 == 0 { polyfill_rs::Side::BUY } else { polyfill_rs::Side::SELL },
side: if i % 2 == 0 {
polyfill_rs::Side::BUY
} else {
polyfill_rs::Side::SELL
},
price,
size,
sequence: i as u64,
};
let _ = book.apply_delta(delta);
}
let book_duration = start.elapsed();
// Fast calculations
let start = Instant::now();
for _ in 0..1000000 {
@@ -219,12 +257,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = book.mid_price_fast();
}
let calc_duration = start.elapsed();
println!(" ⚡ Order book updates: 10,000 in {:?} ({:.0} ops/sec)",
book_duration, 10000.0 / book_duration.as_secs_f64());
println!(" ⚡ Fast calculations: 2M in {:?} ({:.0}M ops/sec)",
calc_duration, 2.0 / calc_duration.as_secs_f64());
println!(
" ⚡ Order book updates: 10,000 in {:?} ({:.0} ops/sec)",
book_duration,
10000.0 / book_duration.as_secs_f64()
);
println!(
" ⚡ Fast calculations: 2M in {:?} ({:.0}M ops/sec)",
calc_duration,
2.0 / calc_duration.as_secs_f64()
);
println!("\n🎯 Final Comparison Summary");
println!("==========================");
println!("| Metric | polymarket-rs-client | polyfill-rs | Improvement |");
@@ -234,13 +278,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("| Order book ops | N/A | ~1µs per update | New capability |");
println!("| Fast calculations | N/A | ~500ns per op | New capability |");
println!("| Memory usage | 15.9MB allocated | ~10x less | Significant |");
println!("\n✨ Key Advantages of polyfill-rs:");
println!(" • Competitive network performance");
println!(" • Superior computational performance");
println!(" • Memory-efficient data structures");
println!(" • Zero-allocation hot paths");
println!(" • Fixed-point arithmetic optimizations");
Ok(())
}
+95 -61
View File
@@ -5,13 +5,13 @@ use std::time::Instant;
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🚀 Simple Network Benchmark - polyfill-rs");
println!("==========================================");
let client = ClobClient::new("https://clob.polymarket.com");
// Test 1: Server Time (baseline network latency)
println!("\n📊 Test 1: Server Time (Network Baseline)");
println!("=========================================");
let mut times = Vec::new();
for i in 0..10 {
let start = Instant::now();
@@ -20,52 +20,54 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let duration = start.elapsed();
times.push(duration);
if i < 3 {
println!(" Run {}: ✅ {} in {:?}", i+1, timestamp, duration);
println!(" Run {}: ✅ {} in {:?}", i + 1, timestamp, duration);
}
}
},
Err(e) => {
let duration = start.elapsed();
times.push(duration);
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
}
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
},
}
}
if !times.is_empty() {
let avg = times.iter().sum::<std::time::Duration>() / times.len() as u32;
let min = times.iter().min().unwrap();
let max = times.iter().max().unwrap();
println!(" 📈 Average: {:?}", avg);
println!(" 📊 Range: {:?} - {:?}", min, max);
println!(" 🌐 Network baseline: ~{:?}", min);
}
// Test 2: Market Data (comparable to original benchmarks)
println!("\n📊 Test 2: Market Data Fetching");
println!("===============================");
println!("Target: polymarket-rs-client 404.5ms ± 22.9ms");
// Try different endpoints to see which ones work
let endpoints = vec![
("Simplified Markets", "get_sampling_simplified_markets"),
("Full Markets", "get_sampling_markets"),
("Market Prices", "get_prices_batch"),
];
for (name, _method) in endpoints {
println!("\n 🔍 Testing {}:", name);
let mut times = Vec::new();
for i in 0..5 {
let start = Instant::now();
let result = match name {
"Simplified Markets" => {
client.get_sampling_simplified_markets(None).await.map(|r| r.data.len())
}
"Full Markets" => {
client.get_sampling_markets(None).await.map(|r| r.data.len())
}
"Simplified Markets" => client
.get_sampling_simplified_markets(None)
.await
.map(|r| r.data.len()),
"Full Markets" => client
.get_sampling_markets(None)
.await
.map(|r| r.data.len()),
"Market Prices" => {
// Try with some example BookParams
let book_params = vec![
@@ -75,96 +77,116 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
];
client.get_prices(&book_params).await.map(|r| r.len())
}
},
_ => continue,
};
let duration = start.elapsed();
times.push(duration);
match result {
Ok(count) => {
if i < 2 {
println!(" Run {}: ✅ {} items in {:?}", i+1, count, duration);
println!(" Run {}: ✅ {} items in {:?}", i + 1, count, duration);
}
}
},
Err(e) => {
if i < 2 {
println!(" Run {}: ❌ Error in {:?}: {}", i+1, duration, e);
println!(" Run {}: ❌ Error in {:?}: {}", i + 1, duration, e);
}
}
},
}
}
if !times.is_empty() {
let avg = times.iter().sum::<std::time::Duration>() / times.len() as u32;
let min = times.iter().min().unwrap();
let max = times.iter().max().unwrap();
let std_dev = {
let mean = avg.as_millis() as f64;
let variance = times.iter()
let variance = times
.iter()
.map(|t| (t.as_millis() as f64 - mean).powi(2))
.sum::<f64>() / times.len() as f64;
.sum::<f64>()
/ times.len() as f64;
variance.sqrt()
};
println!(" 📈 polyfill-rs: {:.1}ms ± {:.1}ms", avg.as_millis(), std_dev);
println!(
" 📈 polyfill-rs: {:.1}ms ± {:.1}ms",
avg.as_millis(),
std_dev
);
println!(" 📊 Range: {:?} - {:?}", min, max);
if name == "Simplified Markets" {
println!(" 🆚 vs original (404.5ms): {:.1}x {}",
404.5 / avg.as_millis() as f64,
if avg.as_millis() < 405 { "faster" } else { "slower" });
println!(
" 🆚 vs original (404.5ms): {:.1}x {}",
404.5 / avg.as_millis() as f64,
if avg.as_millis() < 405 {
"faster"
} else {
"slower"
}
);
}
}
}
// Test 3: Computational Performance (our strength)
println!("\n📊 Test 3: Computational Performance");
println!("===================================");
use polyfill_rs::OrderBookImpl;
use rust_decimal::Decimal;
use std::str::FromStr;
let mut book = OrderBookImpl::new("test_token".to_string(), 100);
// Populate the book first
for i in 0..100 {
let price = Decimal::from_str(&format!("0.{:04}", 5000 + i)).unwrap();
let size = Decimal::from_str("100.0").unwrap();
let delta = polyfill_rs::OrderDelta {
token_id: "test_token".to_string(),
timestamp: chrono::Utc::now(),
side: if i % 2 == 0 { polyfill_rs::Side::BUY } else { polyfill_rs::Side::SELL },
side: if i % 2 == 0 {
polyfill_rs::Side::BUY
} else {
polyfill_rs::Side::SELL
},
price,
size,
sequence: i as u64,
};
let _ = book.apply_delta(delta);
}
// Benchmark order book updates
let start = Instant::now();
for i in 0..10000 {
let price = Decimal::from_str(&format!("0.{:04}", 5000 + (i % 1000))).unwrap();
let size = Decimal::from_str("100.0").unwrap();
let delta = polyfill_rs::OrderDelta {
token_id: "test_token".to_string(),
timestamp: chrono::Utc::now(),
side: if i % 2 == 0 { polyfill_rs::Side::BUY } else { polyfill_rs::Side::SELL },
side: if i % 2 == 0 {
polyfill_rs::Side::BUY
} else {
polyfill_rs::Side::SELL
},
price,
size,
sequence: (i + 1000) as u64,
};
let _ = book.apply_delta(delta);
}
let book_duration = start.elapsed();
// Benchmark fast calculations
let start = Instant::now();
for _ in 0..1000000 {
@@ -172,17 +194,23 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = book.mid_price_fast();
}
let calc_duration = start.elapsed();
println!(" ⚡ Order book: 10,000 updates in {:?}", book_duration);
println!(" 📊 Rate: {:.0} updates/second", 10000.0 / book_duration.as_secs_f64());
println!(
" 📊 Rate: {:.0} updates/second",
10000.0 / book_duration.as_secs_f64()
);
println!(" ⚡ Fast calcs: 2M operations in {:?}", calc_duration);
println!(" 📊 Rate: {:.0}M operations/second", 2.0 / calc_duration.as_secs_f64());
println!(
" 📊 Rate: {:.0}M operations/second",
2.0 / calc_duration.as_secs_f64()
);
// Test 4: JSON Parsing Performance
println!("\n📊 Test 4: JSON Parsing Performance");
println!("==================================");
let sample_market_json = r#"{
"condition_id": "21742633143463906290569050155826241533067272736897614950488156847949938836455",
"question": "Will Donald Trump win the 2024 US Presidential Election?",
@@ -213,35 +241,41 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
]
}"#;
let start = Instant::now();
for _ in 0..10000 {
let _: Result<serde_json::Value, _> = serde_json::from_str(sample_market_json);
}
let json_duration = start.elapsed();
println!(" ⚡ JSON parsing: 10,000 parses in {:?}", json_duration);
println!(" 📊 Rate: {:.0} parses/second", 10000.0 / json_duration.as_secs_f64());
println!(" 📊 Per parse: {:.1}µs", json_duration.as_micros() as f64 / 10000.0);
println!(
" 📊 Rate: {:.0} parses/second",
10000.0 / json_duration.as_secs_f64()
);
println!(
" 📊 Per parse: {:.1}µs",
json_duration.as_micros() as f64 / 10000.0
);
println!("\n🎯 Summary");
println!("=========");
println!("Network Performance:");
println!(" • Competitive with polymarket-rs-client baseline");
println!(" • Network latency dominates end-to-end performance");
println!(" • Geographic location affects results significantly");
println!("\nComputational Performance:");
println!(" • Order book operations: Sub-millisecond");
println!(" • Fast calculations: Sub-microsecond");
println!(" • JSON parsing: Microsecond-scale");
println!(" • Memory efficient: Zero-allocation hot paths");
println!("\n✨ polyfill-rs provides:");
println!(" • Same network performance as alternatives");
println!(" • Superior computational performance");
println!(" • Memory-optimized data structures");
println!(" • Fixed-point arithmetic advantages");
Ok(())
}
+34 -26
View File
@@ -13,9 +13,9 @@ use polyfill_rs::{
types::*,
utils::time,
};
use rust_decimal::prelude::ToPrimitive;
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use rust_decimal::prelude::ToPrimitive;
use std::time::Duration;
use tokio::time::sleep;
use tracing::{error, info, warn};
@@ -92,7 +92,7 @@ impl SnipeStrategy {
fill_engine: FillEngine::new(
min_order_size,
dec!(2.0), // 2% max slippage
5, // 5 bps fee rate
5, // 5 bps fee rate
),
stats: SnipeStats::default(),
}
@@ -105,16 +105,16 @@ impl SnipeStrategy {
if data.token_id == self.token_id {
self.process_book_update(data)?;
}
}
},
StreamMessage::Trade { data } => {
if data.token_id == self.token_id {
self.process_trade(data)?;
}
}
},
StreamMessage::Heartbeat { timestamp: _ } => {
self.check_stale_quotes()?;
}
_ => {}
},
_ => {},
}
Ok(())
}
@@ -123,13 +123,13 @@ impl SnipeStrategy {
fn process_book_update(&mut self, delta: OrderDelta) -> Result<()> {
// Ensure book exists
self.book_manager.get_or_create_book(&self.token_id)?;
// Update local order book
self.book_manager.apply_delta(delta.clone())?;
// Get current book state
let book = self.book_manager.get_book(&self.token_id)?;
// Update best prices
if let Some(best_bid) = book.bids.first() {
self.last_best_bid = Some(best_bid.price);
@@ -137,7 +137,7 @@ impl SnipeStrategy {
if let Some(best_ask) = book.asks.first() {
self.last_best_ask = Some(best_ask.price);
}
self.last_update = time::now_secs();
// Check for trading opportunities
@@ -158,10 +158,10 @@ impl SnipeStrategy {
// Update statistics
self.stats.total_volume += fill.size;
// Calculate P&L if this was our trade
// (In a real implementation, you'd track your own orders)
Ok(())
}
@@ -174,16 +174,14 @@ impl SnipeStrategy {
// Calculate spread
let spread_pct = match (bid, ask) {
(bid, ask) if bid > dec!(0) && ask > bid => {
(ask - bid) / bid * dec!(100)
}
(bid, ask) if bid > dec!(0) && ask > bid => (ask - bid) / bid * dec!(100),
_ => return Ok(()),
};
// Check if spread is within our target
if spread_pct <= self.max_spread_pct {
self.stats.opportunities_detected += 1;
info!(
"Opportunity detected: spread {}% (target: {}%)",
spread_pct, self.max_spread_pct
@@ -200,8 +198,8 @@ impl SnipeStrategy {
fn execute_snipe_order(&mut self, bid: Decimal, ask: Decimal) -> Result<()> {
// Calculate order size (random between min and max)
let random_factor = Decimal::from(rand::random::<u64>() % 100) / Decimal::from(100);
let size = self.min_order_size +
(self.max_order_size - self.min_order_size) * random_factor;
let size =
self.min_order_size + (self.max_order_size - self.min_order_size) * random_factor;
// Determine side based on market conditions
let side = if bid > ask {
@@ -222,7 +220,7 @@ impl SnipeStrategy {
// Get current book for execution simulation
let book = self.book_manager.get_book(&self.token_id)?;
let mut book_impl = polyfill_rs::book::OrderBook::new(self.token_id.clone(), 100);
// Convert to internal book format
for level in &book.bids {
book_impl.apply_delta(OrderDelta {
@@ -234,7 +232,7 @@ impl SnipeStrategy {
sequence: 1,
})?;
}
for level in &book.asks {
book_impl.apply_delta(OrderDelta {
token_id: self.token_id.clone(),
@@ -248,7 +246,9 @@ impl SnipeStrategy {
// Execute order
let start_time = std::time::Instant::now();
let result = self.fill_engine.execute_market_order(&request, &book_impl)?;
let result = self
.fill_engine
.execute_market_order(&request, &book_impl)?;
let fill_time = start_time.elapsed().as_millis() as f64;
// Update statistics
@@ -258,7 +258,8 @@ impl SnipeStrategy {
}
// Update average fill time
let total_time = self.stats.avg_fill_time_ms * (self.stats.orders_filled - 1) as f64 + fill_time;
let total_time =
self.stats.avg_fill_time_ms * (self.stats.orders_filled - 1) as f64 + fill_time;
self.stats.avg_fill_time_ms = total_time / self.stats.orders_filled as f64;
info!(
@@ -327,7 +328,11 @@ impl MockMarketData {
let new_price = self.base_price * (Decimal::from(1) + price_change);
// Generate order book update
let side = if rand::random::<bool>() { Side::BUY } else { Side::SELL };
let side = if rand::random::<bool>() {
Side::BUY
} else {
Side::SELL
};
let size = Decimal::from(rand::random::<u64>() % 1000 + 100);
StreamMessage::BookUpdate {
@@ -338,7 +343,7 @@ impl MockMarketData {
price: new_price,
size,
sequence: self.sequence,
}
},
}
}
}
@@ -372,7 +377,7 @@ async fn main() -> Result<()> {
while message_count < max_messages {
// Generate market update
let update = market_data.generate_update();
// Process update
if let Err(e) = strategy.process_update(update) {
error!("Error processing update: {}", e);
@@ -397,7 +402,10 @@ async fn main() -> Result<()> {
// Print final statistics
let final_stats = strategy.get_stats();
info!("Final statistics:");
info!(" Opportunities detected: {}", final_stats.opportunities_detected);
info!(
" Opportunities detected: {}",
final_stats.opportunities_detected
);
info!(" Orders placed: {}", final_stats.orders_placed);
info!(" Orders filled: {}", final_stats.orders_filled);
info!(" Total volume: {}", final_stats.total_volume);
@@ -405,4 +413,4 @@ async fn main() -> Result<()> {
info!("Snipe trading example completed!");
Ok(())
}
}