Skip to main content

bybit/http/
market.rs

1use rust_decimal::{Decimal, serde::str_option::deserialize as option_decimal};
2use serde::{Deserialize, Serialize};
3use serde_aux::prelude::{
4    deserialize_number_from_string as number,
5    deserialize_option_number_from_string as option_number,
6};
7
8use crate::{
9    ContractType, CopyTrading, CurAuctionPhase, Side, Status, Timestamp,
10    enums::{Category, Interval},
11    serde::{empty_string_as_none, string_to_bool},
12};
13
14#[derive(Debug, Serialize, Clone)]
15pub struct GetKLinesParams {
16    pub category: Category,
17    pub symbol: String,
18    pub interval: Interval,
19    pub start: Option<Timestamp>,
20    pub end: Option<Timestamp>,
21    pub limit: Option<u64>,
22}
23
24#[derive(Debug, Deserialize, PartialEq)]
25#[serde(tag = "category")]
26pub enum KLine {
27    #[serde(rename = "inverse")]
28    Inverse { symbol: String, list: Vec<KLineRow> },
29    #[serde(rename = "linear")]
30    Linear { symbol: String, list: Vec<KLineRow> },
31    #[serde(rename = "option")]
32    Option { symbol: String, list: Vec<KLineRow> },
33    #[serde(rename = "spot")]
34    Spot { symbol: String, list: Vec<KLineRow> },
35}
36
37#[derive(Debug, Deserialize, PartialEq)]
38pub struct KLineRow {
39    /// Start time of the candle (ms)
40    #[serde(rename = "startTime", deserialize_with = "number")]
41    pub start_time: Timestamp,
42    /// Open price
43    #[serde(rename = "openPrice")]
44    pub open_price: Decimal,
45    /// Highest price
46    #[serde(rename = "highPrice")]
47    pub high_price: Decimal,
48    /// Lowest price
49    #[serde(rename = "lowPrice")]
50    pub low_price: Decimal,
51    /// Close price. Is the last traded price when the candle is not closed
52    #[serde(rename = "closePrice")]
53    pub close_price: Decimal,
54    /// Trade volume. Unit of contract: pieces of contract. Unit of spot: quantity of coins
55    #[serde(rename = "volume")]
56    pub volume: Decimal,
57    /// Turnover. Unit of figure: quantity of quota coin
58    #[serde(rename = "turnover")]
59    pub turnover: Decimal,
60}
61
62#[derive(Debug, Serialize, Clone)]
63pub struct GetTickersParams {
64    pub category: Category,
65    pub symbol: Option<String>,
66    pub base_coin: Option<String>,
67    pub exp_date: Option<String>,
68}
69
70#[derive(Debug, Deserialize, PartialEq)]
71#[serde(tag = "category")]
72pub enum Ticker {
73    #[serde(rename = "inverse")]
74    Inverse { list: Vec<LinearInverseTicker> },
75    #[serde(rename = "linear")]
76    Linear { list: Vec<LinearInverseTicker> },
77    #[serde(rename = "option")]
78    Option { list: Vec<OptionTicker> },
79    #[serde(rename = "spot")]
80    Spot { list: Vec<SpotTicker> },
81}
82
83#[derive(Debug, Deserialize, PartialEq)]
84#[serde(rename_all = "camelCase")]
85pub struct LinearInverseTicker {
86    /// Symbol name
87    pub symbol: String,
88    /// Last price
89    pub last_price: Decimal,
90    /// Mark price
91    pub mark_price: Decimal,
92    /// Index price
93    pub index_price: Decimal,
94    /// Market price 24 hours ago
95    pub prev_price24h: Decimal,
96    /// Percentage change of market price in the last 24 hours
97    pub price24h_pcnt: Decimal,
98    /// The highest price in the last 24 hours
99    pub high_price24h: Decimal,
100    /// The lowest price in the last 24 hours
101    pub low_price24h: Decimal,
102    /// Market price an hour ago
103    pub prev_price1h: Decimal,
104    /// Open interest size
105    pub open_interest: Decimal,
106    /// Open interest value
107    pub open_interest_value: Decimal,
108    /// Turnover for 24h
109    pub turnover24h: Decimal,
110    /// Volume for 24h
111    pub volume24h: Decimal,
112    /// Funding rate
113    #[serde(default, deserialize_with = "option_decimal")]
114    pub funding_rate: Option<Decimal>,
115    /// Next funding timestamp (ms)
116    #[serde(deserialize_with = "number")]
117    pub next_funding_time: Timestamp,
118    /// Predicated delivery price. It has value when 30 min before delivery
119    #[serde(default, deserialize_with = "option_decimal")]
120    pub predicted_delivery_price: Option<Decimal>,
121    /// Basis rate. Unique field for inverse futures & USDC futures
122    #[serde(default, deserialize_with = "option_decimal")]
123    pub basis_rate: Option<Decimal>,
124    /// Basis. Unique field for inverse futures & USDC futures
125    #[serde(default, deserialize_with = "option_decimal")]
126    pub basis: Option<Decimal>,
127    /// Delivery fee rate. Unique field for inverse futures & USDC futures
128    #[serde(default, deserialize_with = "option_decimal")]
129    pub delivery_fee_rate: Option<Decimal>,
130    /// Delivery date time (UTC+0). Unique field for inverse futures & USDC futures
131    #[serde(deserialize_with = "option_number")]
132    pub delivery_time: Option<Timestamp>,
133    /// Best bid price
134    pub bid1_price: Decimal,
135    /// Best bid size
136    pub bid1_size: Decimal,
137    /// Best ask price
138    pub ask1_price: Decimal,
139    /// Best ask size
140    pub ask1_size: Decimal,
141    /// Estimated pre-market contract open price. The value is meaningless when entering continuous trading phase.
142    #[serde(default, deserialize_with = "option_decimal")]
143    pub pre_open_price: Option<Decimal>,
144    /// Estimated pre-market contract open qty. The value is meaningless when entering continuous trading phase.
145    #[serde(default, deserialize_with = "option_decimal")]
146    pub pre_qty: Option<Decimal>,
147    /// Enum: NotStarted, Finished, CallAuction, CallAuctionNoCancel, CrossMatching, ContinuousTrading.
148    #[serde(default, deserialize_with = "empty_string_as_none")]
149    pub cur_pre_listing_phase: Option<CurAuctionPhase>,
150}
151
152#[derive(Debug, Deserialize, PartialEq)]
153#[serde(rename_all = "camelCase")]
154pub struct OptionTicker {
155    /// Symbol name
156    pub symbol: String,
157    /// Best bid price
158    pub bid1_price: Decimal,
159    /// Best bid size
160    pub bid1_size: Decimal,
161    /// Best bid iv
162    pub bid1_iv: Decimal,
163    /// Best ask price
164    pub ask1_price: Decimal,
165    /// Best ask size
166    pub ask1_size: Decimal,
167    /// Best ask iv
168    pub ask1_iv: Decimal,
169    /// Last price
170    pub last_price: Decimal,
171    /// The highest price in the last 24 hours
172    pub high_price24h: Decimal,
173    /// The lowest price in the last 24 hours
174    pub low_price24h: Decimal,
175    /// Mark price
176    pub mark_price: Decimal,
177    /// Index price
178    pub index_price: Decimal,
179    /// Mark price iv
180    pub mark_iv: Decimal,
181    /// Underlying price
182    pub underlying_price: Decimal,
183    /// Open interest size
184    pub open_interest: Decimal,
185    /// Turnover for 24h
186    pub turnover24h: Decimal,
187    /// Volume for 24h
188    pub volume24h: Decimal,
189    /// Total volume
190    pub total_volume: Decimal,
191    /// Total turnover
192    pub total_turnover: Decimal,
193    /// Delta
194    pub delta: Decimal,
195    /// Gamma
196    pub gamma: Decimal,
197    /// Vega
198    pub vega: Decimal,
199    /// Theta
200    pub theta: Decimal,
201    /// Predicated delivery price. It has value when 30 min before delivery
202    pub predicted_delivery_price: Decimal,
203    /// The change in the last 24 hours
204    pub change24h: Decimal,
205}
206
207#[derive(Debug, Deserialize, PartialEq)]
208#[serde(rename_all = "camelCase")]
209pub struct SpotTicker {
210    /// Symbol name
211    pub symbol: String,
212    /// Best bid price
213    pub bid1_price: Decimal,
214    /// Best bid size
215    pub bid1_size: Decimal,
216    /// Best ask price
217    pub ask1_price: Decimal,
218    /// Best ask size
219    pub ask1_size: Decimal,
220    /// Last price
221    pub last_price: Decimal,
222    /// Market price 24 hours ago
223    pub prev_price24h: Decimal,
224    /// Percentage change of market price in the last 24 hours
225    pub price24h_pcnt: Decimal,
226    /// The highest price in the last 24 hours
227    pub high_price24h: Decimal,
228    /// The lowest price in the last 24 hours
229    pub low_price24h: Decimal,
230    /// Turnover for 24h
231    pub turnover24h: Decimal,
232    /// Volume for 24h
233    pub volume24h: Decimal,
234    /// USD index price
235    /// - used to calculate USD value of the assets in Unified account
236    /// - non-collateral margin coin returns ""
237    /// - Only those trading pairs like "XXX/USDT" or "XXX/USDC" have the value
238    #[serde(default, deserialize_with = "option_decimal")]
239    pub usd_index_price: Option<Decimal>,
240}
241
242#[derive(Debug, Serialize, Clone)]
243pub struct GetOrderbookParams {
244    pub category: Category,
245    pub symbol: String,
246    /// Limit size for each bid and ask
247    /// - spot: [1, 1000]. Default: 1.
248    /// - linear&inverse: [1, 1000]. Default: 25.
249    /// - option: [1, 25]. Default: 1.
250    pub limit: Option<u64>,
251}
252
253#[derive(Debug, Deserialize, PartialEq)]
254pub struct Orderbook {
255    /// Symbol name
256    #[serde(rename = "s")]
257    pub symbol: String,
258    /// Bid, buy side. Sorted by price in descending order
259    #[serde(rename = "b")]
260    pub bids: Vec<OrderbookLevel>,
261    /// Ask, sell side. Sorted by price in ascending order
262    #[serde(rename = "a")]
263    pub asks: Vec<OrderbookLevel>,
264    /// The timestamp (ms) that the system generates the data
265    pub ts: Timestamp,
266    /// Update ID, is a sequence. Occasionally, you'll receive "u"=1, which is a snapshot
267    /// data due to the restart of the service. So please overwrite your local orderbook
268    #[serde(rename = "u")]
269    pub update_id: i64,
270    /// Cross sequence. You can use this field to compare different levels orderbook data,
271    /// and for the smaller seq, then it means the data is generated earlier
272    pub seq: i64,
273    /// Cross timestamp (ms). Spot only
274    #[serde(default)]
275    pub cts: Option<Timestamp>,
276}
277
278#[derive(Debug, Deserialize, PartialEq)]
279pub struct OrderbookLevel {
280    /// Price
281    pub price: Decimal,
282    /// Size
283    pub size: Decimal,
284}
285
286#[derive(Debug, Serialize, Clone)]
287#[serde(rename_all = "camelCase")]
288pub struct GetTradesParams {
289    pub category: Category,
290    /// required for spot/linear/inverse
291    /// optional for option
292    pub symbol: Option<String>,
293    /// Apply to option only
294    /// If the field is not passed, return BTC data by default
295    pub base_coin: Option<String>,
296    /// optionType false string Option type. Call or Put. Apply to option only
297    pub option_type: Option<u64>,
298    /// spot: [1,60], default: 60
299    /// others: [1,1000], default: 500
300    pub limit: Option<u64>,
301}
302
303#[derive(Debug, Deserialize, PartialEq)]
304#[serde(tag = "category")]
305pub enum Trade {
306    #[serde(rename = "inverse")]
307    Inverse { list: Vec<InverseLinearSpotTrade> },
308    #[serde(rename = "linear")]
309    Linear { list: Vec<InverseLinearSpotTrade> },
310    #[serde(rename = "option")]
311    Option { list: Vec<OptionTrade> },
312    #[serde(rename = "spot")]
313    Spot { list: Vec<InverseLinearSpotTrade> },
314}
315
316#[derive(Debug, Deserialize, PartialEq)]
317#[serde(rename_all = "camelCase")]
318pub struct InverseLinearSpotTrade {
319    /// Execution ID
320    pub exec_id: String,
321    /// Symbol name
322    pub symbol: String,
323    /// Trade price
324    pub price: Decimal,
325    /// Trade size
326    pub size: Decimal,
327    /// Side of taker Buy, Sell
328    pub side: Side,
329    /// Trade time (ms)
330    #[serde(deserialize_with = "number")]
331    pub time: Timestamp,
332    /// boolean Whether the trade is block trade
333    pub is_block_trade: bool,
334    /// Whether the trade is RPI trade
335    #[serde(rename = "isRPITrade")]
336    pub is_rpi_trade: bool,
337}
338
339#[derive(Debug, Deserialize, PartialEq)]
340#[serde(rename_all = "camelCase")]
341pub struct OptionTrade {
342    /// Execution ID
343    pub exec_id: String,
344    /// Symbol name
345    pub symbol: String,
346    /// Trade price
347    pub price: Decimal,
348    /// Trade size
349    pub size: Decimal,
350    /// Side of taker Buy, Sell
351    pub side: Side,
352    /// Trade time (ms)
353    #[serde(deserialize_with = "number")]
354    pub time: Timestamp,
355    /// boolean Whether the trade is block trade
356    pub is_block_trade: bool,
357    /// Whether the trade is RPI trade
358    #[serde(rename = "isRPITrade")]
359    pub is_rpi_trade: bool,
360    /// Mark price
361    #[serde(rename = "mP")]
362    pub mark_price: Decimal,
363    /// Index price
364    #[serde(rename = "iP")]
365    pub index_price: Decimal,
366    /// Mark iv
367    #[serde(rename = "mIv")]
368    pub mark_iv: Decimal,
369    /// iv
370    #[serde(rename = "iv")]
371    pub iv: Decimal,
372}
373
374#[derive(Debug, Deserialize, PartialEq)]
375#[serde(rename_all = "camelCase")]
376pub struct ServerTime {
377    /// Bybit server timestamp (sec)
378    #[serde(deserialize_with = "number")]
379    pub time_second: u64,
380    /// Bybit server timestamp (nano)
381    #[serde(deserialize_with = "number")]
382    pub time_nano: u64,
383}
384
385#[derive(Debug, Serialize, Clone)]
386pub struct GetInstrumentsInfoParams {
387    pub category: Category,
388    pub symbol: Option<String>,
389    pub status: Option<Status>,
390    pub base_coin: Option<String>,
391    pub limit: Option<i64>,
392    pub cursor: Option<String>,
393}
394
395#[derive(Debug, Deserialize, PartialEq)]
396#[serde(tag = "category")]
397pub enum InstrumentsInfo {
398    #[serde(rename = "inverse", rename_all = "camelCase")]
399    Inverse {
400        next_page_cursor: String,
401        list: Vec<InverseLinearInstrumentsInfo>,
402    },
403    #[serde(rename = "linear", rename_all = "camelCase")]
404    Linear {
405        next_page_cursor: String,
406        list: Vec<InverseLinearInstrumentsInfo>,
407    },
408    #[serde(rename = "option", rename_all = "camelCase")]
409    Option {
410        next_page_cursor: String,
411        list: Vec<OptionInstrumentsInfo>,
412    },
413    #[serde(rename = "spot", rename_all = "camelCase")]
414    Spot {
415        #[serde(default, deserialize_with = "empty_string_as_none")]
416        next_page_cursor: Option<String>,
417        list: Vec<SpotInstrumentsInfo>,
418    },
419}
420
421#[derive(Debug, Deserialize, PartialEq)]
422#[serde(rename_all = "camelCase")]
423pub struct InverseLinearInstrumentsInfo {
424    pub symbol: String,
425    pub contract_type: ContractType,
426    pub status: Status,
427    pub base_coin: String,
428    pub quote_coin: String,
429    #[serde(deserialize_with = "number")]
430    pub launch_time: Timestamp,
431    #[serde(deserialize_with = "number")]
432    pub delivery_time: Timestamp,
433    #[serde(deserialize_with = "option_decimal")]
434    pub delivery_fee_rate: Option<Decimal>,
435    #[serde(deserialize_with = "number")]
436    pub price_scale: i64,
437    pub leverage_filter: LeverageFilter,
438    pub price_filter: PriceFilter,
439    pub lot_size_filter: LotSizeFilter,
440    pub unified_margin_trade: bool,
441    pub funding_interval: i64,
442    pub settle_coin: String,
443    pub copy_trading: CopyTrading,
444    pub upper_funding_rate: Decimal,
445    pub lower_funding_rate: Decimal,
446    pub risk_parameters: RiskParameters,
447    pub is_pre_listing: bool,
448    pub pre_listing_info: Option<PreListingInfo>,
449}
450
451#[derive(Debug, Deserialize, PartialEq)]
452#[serde(rename_all = "camelCase")]
453pub struct OptionInstrumentsInfo {
454    pub symbol: String,
455    pub contract_type: ContractType,
456    pub status: Status,
457    pub base_coin: String,
458    pub quote_coin: String,
459    #[serde(deserialize_with = "number")]
460    pub launch_time: i64,
461    #[serde(deserialize_with = "number")]
462    pub delivery_time: i64,
463    #[serde(deserialize_with = "option_decimal")]
464    pub delivery_fee_rate: Option<Decimal>,
465    #[serde(deserialize_with = "number")]
466    pub price_scale: i64,
467    pub leverage_filter: LeverageFilter,
468    pub price_filter: PriceFilter,
469    pub lot_size_filter: LotSizeFilter,
470    pub unified_margin_trade: bool,
471    pub funding_interval: i64,
472    pub settle_coin: String,
473    pub copy_trading: CopyTrading,
474    pub upper_funding_rate: Decimal,
475    pub lower_funding_rate: Decimal,
476    pub risk_parameters: RiskParameters,
477    pub is_pre_listing: bool,
478    pub pre_listing_info: Option<PreListingInfo>,
479}
480
481#[derive(Debug, Deserialize, PartialEq)]
482#[serde(rename_all = "camelCase")]
483pub struct SpotInstrumentsInfo {
484    /// Symbol name
485    pub symbol: String,
486    /// Base coin
487    pub base_coin: String,
488    /// Quote coin
489    pub quote_coin: String,
490    /// Whether or not this is an innovation zone token. 0: false, 1: true
491    #[serde(deserialize_with = "string_to_bool")]
492    pub innovation: bool,
493    /// Instrument status
494    pub status: Status,
495    /// Margin trade symbol or not
496    /// This is to identify if the symbol support margin trading under different account modes
497    /// You may find some symbols not supporting margin buy or margin sell, so you need to go to Collateral Info (UTA) to check if that coin is borrowable
498    pub margin_trading: String,
499    /// Whether or not it has an special treatment label. 0: false, 1: true
500    #[serde(deserialize_with = "string_to_bool")]
501    pub st_tag: bool,
502    /// Size attributes
503    pub lot_size_filter: SpotLotSizeFilter,
504    /// Price attributes
505    pub price_filter: SpotPriceFilter,
506    /// Risk parameters for limit order price, refer to announcement
507    pub risk_parameters: RiskParameters,
508}
509
510#[derive(Debug, Deserialize, PartialEq)]
511#[serde(rename_all = "camelCase")]
512pub struct LeverageFilter {
513    pub min_leverage: Decimal,
514    pub max_leverage: Decimal,
515    pub leverage_step: Decimal,
516}
517
518#[derive(Debug, Deserialize, PartialEq)]
519#[serde(rename_all = "camelCase")]
520pub struct PriceFilter {
521    pub min_price: Decimal,
522    pub max_price: Decimal,
523    pub tick_size: Decimal,
524}
525
526#[derive(Debug, Deserialize, PartialEq)]
527#[serde(rename_all = "camelCase")]
528pub struct SpotPriceFilter {
529    /// The step to increase/reduce order price
530    pub tick_size: Decimal,
531}
532
533#[derive(Debug, Deserialize, PartialEq)]
534#[serde(rename_all = "camelCase")]
535pub struct LotSizeFilter {
536    pub min_notional_value: Decimal,
537    pub max_order_qty: Decimal,
538    pub max_mkt_order_qty: Decimal,
539    pub min_order_qty: Decimal,
540    pub qty_step: Decimal,
541    pub post_only_max_order_qty: Decimal,
542}
543
544#[derive(Debug, Deserialize, PartialEq)]
545#[serde(rename_all = "camelCase")]
546pub struct SpotLotSizeFilter {
547    /// The precision of base coin
548    pub base_precision: Decimal,
549    /// The precision of quote coin
550    pub quote_precision: Decimal,
551    /// Minimum order quantity
552    pub min_order_qty: Decimal,
553    /// Maximum order quantity
554    pub max_order_qty: Decimal,
555    /// Minimum order amount
556    pub min_order_amt: Decimal,
557    /// Maximum order amount
558    pub max_order_amt: Decimal,
559}
560
561#[derive(Debug, Deserialize, PartialEq)]
562#[serde(rename_all = "camelCase")]
563pub struct RiskParameters {
564    pub price_limit_ratio_x: Decimal,
565    pub price_limit_ratio_y: Decimal,
566}
567
568#[derive(Debug, Deserialize, PartialEq)]
569#[serde(rename_all = "camelCase")]
570pub struct PreListingInfo {
571    pub cur_auction_phase: CurAuctionPhase,
572    pub phases: Vec<Phase>,
573    pub auction_fee_info: AuctionFeeInfo,
574}
575
576#[derive(Debug, Deserialize, PartialEq)]
577#[serde(rename_all = "camelCase")]
578pub struct Phase {
579    pub phase: CurAuctionPhase,
580    #[serde(deserialize_with = "option_number")]
581    pub start_time: Option<Timestamp>,
582    #[serde(deserialize_with = "option_number")]
583    pub end_time: Option<Timestamp>,
584}
585
586#[derive(Debug, Deserialize, PartialEq)]
587#[serde(rename_all = "camelCase")]
588pub struct AuctionFeeInfo {
589    pub auction_fee_rate: Decimal,
590    pub taker_fee_rate: Decimal,
591    pub maker_fee_rate: Decimal,
592}