1use nautilus_bybit::{
31 common::enums::{BybitKlineInterval, BybitProductType},
32 http::{
33 client::BybitHttpClient,
34 query::{
35 BybitInstrumentsInfoParamsBuilder, BybitKlinesParamsBuilder, BybitTradesParamsBuilder,
36 },
37 },
38};
39
40#[tokio::main]
41async fn main() -> anyhow::Result<()> {
42 tracing_subscriber::fmt()
43 .with_max_level(tracing::Level::DEBUG)
44 .init();
45
46 println!("=== Bybit HTTP Client Demo ===\n");
47
48 test_public_endpoints().await?;
50
51 let api_key = std::env::var("BYBIT_API_KEY").ok();
53 let api_secret = std::env::var("BYBIT_API_SECRET").ok();
54
55 if let (Some(key), Some(secret)) = (api_key, api_secret) {
56 println!("\n=== Testing Authenticated Endpoints ===");
57 test_authenticated_endpoints(&key, &secret).await?;
58 } else {
59 println!(
60 "\n[SKIP] Skipping authenticated endpoints (set BYBIT_API_KEY and BYBIT_API_SECRET to test)"
61 );
62 }
63
64 Ok(())
65}
66
67async fn test_public_endpoints() -> anyhow::Result<()> {
68 let client = BybitHttpClient::new(None, Some(60), None, None, None)?;
69
70 println!("1. Testing GET /v5/market/time");
72 match client.http_get_server_time().await {
73 Ok(response) => {
74 println!(
75 " [OK] Server time: {} (seconds)",
76 response.result.time_second
77 );
78 println!(" [OK] Server time: {} (nanos)", response.result.time_nano);
79 }
80 Err(e) => {
81 println!(" [ERROR] {e}");
82 return Err(e.into());
83 }
84 }
85
86 println!("\n2. Testing GET /v5/market/instruments-info (linear)");
88 let params = BybitInstrumentsInfoParamsBuilder::default()
89 .category(BybitProductType::Linear)
90 .symbol("BTCUSDT")
91 .build()?;
92
93 match client.http_get_instruments_linear(¶ms).await {
94 Ok(response) => {
95 println!(" [OK] Found {} instruments", response.result.list.len());
96 if let Some(first) = response.result.list.first() {
97 println!(" [OK] First instrument: {}", first.symbol);
98 println!(" [OK] Status: {:?}", first.status);
99 }
100 }
101 Err(e) => {
102 println!(" [ERROR] {e}");
103 return Err(e.into());
104 }
105 }
106
107 println!("\n3. Testing GET /v5/market/instruments-info (spot)");
109 let params = BybitInstrumentsInfoParamsBuilder::default()
110 .category(BybitProductType::Spot)
111 .limit(5u32)
112 .build()?;
113
114 match client.http_get_instruments_spot(¶ms).await {
115 Ok(response) => {
116 println!(" [OK] Found {} instruments", response.result.list.len());
117 for instrument in response.result.list.iter().take(3) {
118 println!(" - {}: {:?}", instrument.symbol, instrument.status);
119 }
120 }
121 Err(e) => {
122 println!(" [ERROR] {e}");
123 return Err(e.into());
124 }
125 }
126
127 println!("\n4. Testing GET /v5/market/kline");
129 let params = BybitKlinesParamsBuilder::default()
130 .category(BybitProductType::Linear)
131 .symbol("BTCUSDT")
132 .interval(BybitKlineInterval::Minute1)
133 .limit(5u32)
134 .build()?;
135
136 match client.http_get_klines(¶ms).await {
137 Ok(response) => {
138 println!(" [OK] Found {} klines", response.result.list.len());
139 if let Some(first) = response.result.list.first() {
140 println!(
141 " [OK] First kline: O={}, H={}, L={}, C={}",
142 first.open, first.high, first.low, first.close
143 );
144 }
145 }
146 Err(e) => {
147 println!(" [ERROR] {e}");
148 return Err(e.into());
149 }
150 }
151
152 println!("\n5. Testing GET /v5/market/recent-trade");
154 let params = BybitTradesParamsBuilder::default()
155 .category(BybitProductType::Linear)
156 .symbol("BTCUSDT")
157 .limit(5u32)
158 .build()?;
159
160 match client.http_get_recent_trades(¶ms).await {
161 Ok(response) => {
162 println!(" [OK] Found {} recent trades", response.result.list.len());
163 for trade in response.result.list.iter().take(3) {
164 println!(
165 " - Price: {}, Size: {}, Side: {:?}",
166 trade.price, trade.size, trade.side
167 );
168 }
169 }
170 Err(e) => {
171 println!(" [ERROR] {e}");
172 return Err(e.into());
173 }
174 }
175
176 println!("\n[SUCCESS] All public endpoint tests passed!");
177 Ok(())
178}
179
180async fn test_authenticated_endpoints(api_key: &str, api_secret: &str) -> anyhow::Result<()> {
181 let base_url = std::env::var("BYBIT_BASE_URL")
182 .unwrap_or_else(|_| "https://api-testnet.bybit.com".to_string());
183
184 let client = BybitHttpClient::with_credentials(
185 api_key.to_string(),
186 api_secret.to_string(),
187 Some(base_url),
188 Some(60),
189 None,
190 None,
191 None,
192 )?;
193
194 println!("\n1. Testing GET /v5/order/realtime (open orders)");
196 match client
197 .http_get_open_orders(BybitProductType::Linear, Some("BTCUSDT"))
198 .await
199 {
200 Ok(response) => {
201 println!(" [OK] Found {} open orders", response.result.list.len());
202 for order in response.result.list.iter().take(3) {
203 println!(
204 " - Order: {} | {:?} | {} @ {}",
205 order.order_id, order.side, order.qty, order.price
206 );
207 }
208 }
209 Err(e) => {
210 println!(" [WARN] Error (may be expected if no orders): {e}");
211 }
212 }
213
214 println!("\n2. Testing POST /v5/order/create (order placement)");
216 println!(" [SKIP] Skipping actual order placement to avoid unintended trades");
217 println!(" [INFO] Uncomment in code to test order placement");
218
219 println!("\n[SUCCESS] Authenticated endpoint tests completed!");
245 Ok(())
246}