dydx_http_public/
http_public.rs1use chrono::{Duration, Utc};
31use nautilus_dydx::{
32 common::{consts::DYDX_TESTNET_HTTP_URL, enums::DydxCandleResolution},
33 http::client::DydxHttpClient,
34};
35use nautilus_model::instruments::Instrument;
36use ustr::Ustr;
37
38#[tokio::main]
39async fn main() -> Result<(), Box<dyn std::error::Error>> {
40 tracing_subscriber::fmt()
41 .with_max_level(tracing::Level::INFO)
42 .init();
43
44 let base_url =
45 std::env::var("DYDX_HTTP_URL").unwrap_or_else(|_| DYDX_TESTNET_HTTP_URL.to_string());
46 let is_testnet = base_url.contains("testnet");
47
48 tracing::info!("Connecting to dYdX HTTP API: {}", base_url);
49 tracing::info!(
50 "Environment: {}",
51 if is_testnet { "TESTNET" } else { "MAINNET" }
52 );
53 tracing::info!("");
54
55 let client = DydxHttpClient::new(Some(base_url), Some(30), None, is_testnet, None)?;
56
57 let start = std::time::Instant::now();
58 let instruments = client.request_instruments(None, None, None).await?;
59 let elapsed = start.elapsed();
60
61 tracing::info!(
62 "SUCCESS: Fetched {} instruments in {:.2}s",
63 instruments.len(),
64 elapsed.as_secs_f64()
65 );
66
67 if !instruments.is_empty() {
68 tracing::info!(" Sample instruments:");
69 for inst in instruments.iter().take(5) {
70 tracing::info!(" - {} ({})", inst.id().symbol, inst.instrument_class());
71 }
72 if instruments.len() > 5 {
73 tracing::info!(" ... and {} more", instruments.len() - 5);
74 }
75 }
76
77 client.cache_instruments(instruments.clone());
78 tracing::info!("Cached {} instruments", instruments.len());
79
80 let symbol = Ustr::from("BTC-USD");
81 let start = std::time::Instant::now();
82 let instrument = client.get_instrument(&symbol);
83 let elapsed = start.elapsed();
84
85 match instrument {
86 Some(inst) => {
87 tracing::info!(
88 "SUCCESS: Found {} in cache in {:.4}ms",
89 inst.id(),
90 elapsed.as_micros() as f64 / 1000.0
91 );
92 tracing::info!(" Type: {}", inst.instrument_class());
93 tracing::info!(" Price precision: {}", inst.price_precision());
94 tracing::info!(" Size precision: {}", inst.size_precision());
95 }
96 None => {
97 tracing::warn!("FAILED: Instrument {} not found in cache", symbol);
98 }
99 }
100
101 let symbol = "BTC-USD";
102 let limit = Some(100);
103
104 let start = std::time::Instant::now();
105 let trades = client.request_trades(symbol, limit).await?;
106 let elapsed = start.elapsed();
107
108 tracing::info!(
109 "SUCCESS: Fetched {} trades for {} in {:.2}s",
110 trades.trades.len(),
111 symbol,
112 elapsed.as_secs_f64()
113 );
114
115 if !trades.trades.is_empty() {
116 let first = &trades.trades[0];
117 let last = &trades.trades[trades.trades.len() - 1];
118 tracing::info!(
119 " First trade: {} @ {} ({})",
120 first.size,
121 first.price,
122 first.side
123 );
124 tracing::info!(
125 " Last trade: {} @ {} ({})",
126 last.size,
127 last.price,
128 last.side
129 );
130 tracing::info!(" Time range: {} to {}", first.created_at, last.created_at);
131 }
132
133 let resolution = DydxCandleResolution::OneMinute;
134 let end_time = Utc::now();
135 let start_time = end_time - Duration::hours(2); let start = std::time::Instant::now();
138 let candles = client
139 .request_candles(symbol, resolution, None, Some(start_time), Some(end_time))
140 .await?;
141 let elapsed = start.elapsed();
142
143 tracing::info!(
144 "SUCCESS: Fetched {} candles for {} ({:?}) in {:.2}s",
145 candles.candles.len(),
146 symbol,
147 resolution,
148 elapsed.as_secs_f64()
149 );
150
151 if !candles.candles.is_empty() {
152 let first = &candles.candles[0];
153 let last = &candles.candles[candles.candles.len() - 1];
154 tracing::info!(
155 " First candle: O={} H={} L={} C={} V={}",
156 first.open,
157 first.high,
158 first.low,
159 first.close,
160 first.base_token_volume
161 );
162 tracing::info!(
163 " Last candle: O={} H={} L={} C={} V={}",
164 last.open,
165 last.high,
166 last.low,
167 last.close,
168 last.base_token_volume
169 );
170 tracing::info!(" Time range: {} to {}", first.started_at, last.started_at);
171 }
172
173 let end_time = Utc::now();
174 let start_time = end_time - Duration::days(7); tracing::info!(
177 " Requesting {:?} bars from {} to {}",
178 resolution,
179 start_time,
180 end_time
181 );
182
183 let start = std::time::Instant::now();
184 let candles_large = client
185 .request_candles(symbol, resolution, None, Some(start_time), Some(end_time))
186 .await?;
187 let elapsed = start.elapsed();
188
189 let expected_bars_large = ((end_time - start_time).num_minutes() as usize).min(10_080);
190 let coverage_large = (candles_large.candles.len() as f64 / expected_bars_large as f64) * 100.0;
191
192 tracing::info!(
193 "SUCCESS: Fetched {} candles in {:.2}s ({:.0} bars/sec)",
194 candles_large.candles.len(),
195 elapsed.as_secs_f64(),
196 candles_large.candles.len() as f64 / elapsed.as_secs_f64()
197 );
198
199 if !candles_large.candles.is_empty() {
200 tracing::info!(" Coverage: {:.1}% of expected bars", coverage_large);
201 tracing::info!(
202 " Time range: {} to {}",
203 candles_large.candles[0].started_at,
204 candles_large.candles[candles_large.candles.len() - 1].started_at
205 );
206 }
207 tracing::info!("");
208
209 tracing::info!("ALL TESTS COMPLETED SUCCESSFULLY");
210 tracing::info!("");
211 tracing::info!("Summary:");
212 tracing::info!(
213 " [PASS] request_instruments: {} instruments",
214 instruments.len()
215 );
216 tracing::info!(" [PASS] get_instrument: Cache lookup works");
217 tracing::info!(
218 " [PASS] get_trades: {} trades fetched",
219 trades.trades.len()
220 );
221 tracing::info!(
222 " [PASS] get_candles (small): {} candles",
223 candles.candles.len()
224 );
225 tracing::info!(
226 " [PASS] get_candles (large): {} candles with {:.1}% coverage",
227 candles_large.candles.len(),
228 coverage_large
229 );
230
231 Ok(())
232}