bybit-connector-ruby 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e337e2d3927cdb53b707d0bfd441323cb293a43e2c3ded843d273c47f439af5
4
- data.tar.gz: c4dfa85d62da8da24fc1cccdc5101631404182a3910de24f65f899ed972771dd
3
+ metadata.gz: 29c7f3e3612cc7bc336a83b1eaf26480ec881b491e7e3c66d042b9a6a23efb71
4
+ data.tar.gz: 7d64066ef1795efbdfc0f13c11bda3f8ea5e99e6f0d627fb4a1baf28bd6de99c
5
5
  SHA512:
6
- metadata.gz: 9bad03bebb0cc8d633b4f014d42da79b592ade8d8f90b77a4a9ed239a0d46ae094aa8ba236a01616abb5b0b7596a85627cccad53ebce950334c544eef3ff0570
7
- data.tar.gz: 310c666e1c0b387b84d91ab4fff0f78f401224eb09f74724bd64e021c4bf5fc1ff4f3458e383ed7a040bba69528602bedbb48f2da8b3d54cf1af30a142fa3f42
6
+ metadata.gz: e767a4025a6b105dad09bd0abb87ad04127183505981a35445e9d699c512ea9c699e769a77bd6b8a899fe7f2a91a073c70d823f822b08383f63ec9d3ef20a728
7
+ data.tar.gz: 312fd1a206d9513423767aa47d1a1009bbd28883d14367928df5799698c31205f72c661b9efcbfc36f1795b97434147c02a6ff3ba0235a744f616072f4e9213b
data/CHANGELOG.md CHANGED
@@ -5,7 +5,136 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## 0.1.0 — 2026-07-20
8
+ ## [0.1.3] - 2026-11-06
9
+
10
+ ### Added
11
+ - `AlphaService#get_lp_order_list(...)`
12
+ - `AlphaService#get_lp_pay_token_list(...)`
13
+ - `AlphaService#get_lp_pay_token_price(...)`
14
+ - `AlphaService#get_lp_pool_info(...)`
15
+ - `AlphaService#get_lp_pool_list(...)`
16
+ - `AlphaService#get_lp_position_list(...)`
17
+ - `AlphaService#execute_lp_redeem(...)`
18
+ - `AlphaService#execute_lp_stake(...)`
19
+ - `AlphaService#execute_prediction_buy(...)`
20
+ - `AlphaService#get_prediction_engine_status(...)`
21
+ - `AlphaService#get_prediction_event_detail(...)`
22
+ - `AlphaService#get_prediction_order_book(...)`
23
+ - `AlphaService#get_prediction_order_estimate(...)`
24
+ - `AlphaService#get_prediction_order_list(...)`
25
+ - `AlphaService#get_prediction_pay_token_list(...)`
26
+ - `AlphaService#get_prediction_portfolio_summary(...)`
27
+ - `AlphaService#get_prediction_position_history(...)`
28
+ - `AlphaService#get_prediction_position_list(...)`
29
+ - `AlphaService#get_prediction_price_history(...)`
30
+ - `AlphaService#execute_prediction_sell(...)`
31
+ - `AlphaService#get_prediction_side_market_list(...)`
32
+ - `AlphaService#get_prediction_group_stage_detail(...)`
33
+ - `AlphaService#get_prediction_match_list(...)`
34
+ - `AlphaService#get_prediction_timeline_stages(...)`
35
+ - `AlphaService#get_prediction_token_price(...)`
36
+ - `AlphaService#get_asset_detail(...)`
37
+ - `AlphaService#get_asset_list(...)`
38
+ - `AlphaService#get_biz_token_details(...)`
39
+ - `AlphaService#get_biz_token_list(...)`
40
+ - `AlphaService#get_biz_token_price_list(...)`
41
+ - `AlphaService#get_order_list(...)`
42
+ - `AlphaService#get_pay_token_list(...)`
43
+ - `AlphaService#execute_purchase(...)`
44
+ - `AlphaService#get_trade_quote(...)`
45
+ - `AlphaService#execute_redeem(...)`
46
+ - `EventService#get_ec_order_history(...)`
47
+ - `EventService#get_ec_active_orders(...)`
48
+ - `EventService#get_ec_position_info(...)`
49
+ - `EventService#get_ec_settlements(...)`
50
+ - `EventService#get_ec_trade_history(...)`
51
+ - `TaxService#batch_create_tax_reports(...)`
52
+ - `TaxService#batch_query_tax_reports(...)`
53
+ - `FiatService#query_balance(...)`
54
+ - `FiatService#query_coin_list(...)`
55
+ - `FiatService#query_trade_history(...)`
56
+ - `FiatService#apply_quote(...)`
57
+ - `FiatService#get_reference_price(...)`
58
+ - `FiatService#confirm_quote(...)`
59
+ - `FiatService#query_trade(...)`
60
+ - `InstitutionalLoanService#ins_loan_coin_delta_amount(...)`
61
+ - `InstitutionalLoanService#ins_loan_delay_liq_status(...)`
62
+ - `ReferralService#get_campaign_rewards(...)`
63
+ - `ReferralService#get_commission_records(...)`
64
+ - `ReferralService#get_user_identity_profile(...)`
65
+ - `ReferralService#get_user_invitations(...)`
66
+ - `SpotMarginService#query_fixed_borrow_penalty_interest(...)`
67
+ - `SpotMarginService#cancel_fixed_borrow_order(...)`
68
+ - `SpotXService#get_launchpool_project_list(...)`
69
+ - `SpotXService#get_launchpool_user_activity_log(...)`
70
+ - `SpotXService#get_launchpool_user_current_staking(...)`
71
+ - `SpotXService#get_launchpool_user_history(...)`
72
+ - `SpotXService#get_puzzle_project_list(...)`
73
+ - `SpotXService#get_token_splash_project_list(...)`
74
+ - `SpotXService#get_token_splash_user_activity_params(...)`
75
+ - `SpreadTradeService#get_history(...)`
76
+ - `SpreadTradeService#get_spread_instruments_info(...)`
77
+ - `SpreadTradeService#get_spread_max_qty(...)`
78
+ - `SpreadTradeService#amend_spread_order(...)`
79
+ - `SpreadTradeService#cancel_spread_order(...)`
80
+ - `SpreadTradeService#cancel_all_spread_orders(...)`
81
+ - `SpreadTradeService#create_spread_order(...)`
82
+ - `SpreadTradeService#get_spread_order_history(...)`
83
+ - `SpreadTradeService#get_spread_open_orders(...)`
84
+ - `SpreadTradeService#get_spread_orderbook(...)`
85
+ - `SpreadTradeService#get_spread_recent_trades(...)`
86
+ - `SpreadTradeService#get_spread_tickers(...)`
87
+ - `StrategyService#create_strategy(...)`
88
+ - `StrategyService#query_list(...)`
89
+ - `StrategyService#query_order_list(...)`
90
+ - `StrategyService#stop_strategy(...)`
91
+
92
+ ### Fixed
93
+ - `AlphaService#get_prediction_side_market_list(...)` now requires `event_id` and accepts the documented filters and pagination options.
94
+
95
+ ### Sources
96
+ - OpenAPI: `705f49bf6dba27ecc5b9b402f46ab2423cfb5dd9`
97
+ - Docs: `9cde0843c270dd1e6009fb4593272f43f60cccf0`
98
+
99
+ ## [0.1.2] - 2026-10-13
100
+
101
+ ### Added
102
+ - `AccountService#demo_apply_money(...)`
103
+ - `AccountService#get_option_asset_info(...)`
104
+ - `AccountService#get_pay_info(...)`
105
+ - `AccountService#get_trade_info_for_analysis(...)`
106
+ - `AssetService#limit_order_callback(...)`
107
+ - `CryptoLoanService#get_fixed_available_inventory(...)`
108
+ - `CryptoLoanService#get_fixed_repayment_history(...)`
109
+ - `CryptoLoanService#supply_fixed(...)`
110
+ - `CryptoLoanService#get_flexible_available_inventory(...)`
111
+ - `EarnService#list_auto_savings(...)`
112
+ - `EarnService#edit_earn_auto_savings(...)`
113
+ - `MarketService#get_option_base_coins(...)`
114
+ - `PositionService#get_symbol_info(...)`
115
+ - `SpotMarginService#get_trade_coin_state(...)`
116
+ - `SpotMarginService#query_fixed_available_inventory(...)`
117
+ - `SpotMarginService#account_fixed_borrow(...)`
118
+ - `SpotMarginService#query_fixed_borrow_contracts(...)`
119
+ - `SpotMarginService#query_fixed_borrow_orders(...)`
120
+ - `SpotMarginService#query_fixed_borrow_market(...)`
121
+ - `SpotMarginService#renew_fixed_borrow(...)`
122
+ - `SpotMarginService#get_trade_flexible_available_inventory(...)`
123
+ - `SpotMarginService#get_trade_auto_repay_mode(...)`
124
+ - `SpotMarginService#query_borrow_liability(...)`
125
+ - `SpotMarginService#get_trade_max_borrowable(...)`
126
+ - `SpotMarginService#get_trade_repayment_available_amount(...)`
127
+ - `SpotMarginService#set_auto_repay_mode(...)`
128
+ - `SpotMarginService#spot_margin_set_leverage(...)`
129
+ - `SpotMarginService#get_trade_state(...)`
130
+ - `SpotMarginService#spot_margin_switch_mode(...)`
131
+ - `UserService#query_referral_code(...)`
132
+
133
+ ### Sources
134
+ - OpenAPI: `08130d57323d390dea58f15418758e2667c74ce6`
135
+ - Docs: `59e3d457dea6b419a14987c19a3aabf4ffb38238`
136
+
137
+ ## [0.1.1] - 2026-07-22
9
138
 
10
139
  ### Added
11
140
  - `AccountService#batch_set_collateral(...)`
@@ -34,9 +163,48 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
34
163
  - `AccountService#upgrade_to_uta_pro(...)`
35
164
  - `AffiliateService#get_sub_list(...)`
36
165
  - `AffiliateService#get_user_list(...)`
166
+ - `AssetService#account_coin_balance_query(...)`
167
+ - `AssetService#asset_info_query(...)`
168
+ - `AssetService#cancel_withdraw(...)`
169
+ - `AssetService#coin_convert_limit_query(...)`
170
+ - `AssetService#coin_list_query(...)`
171
+ - `AssetService#convert_execute(...)`
172
+ - `AssetService#convert_history_query(...)`
173
+ - `AssetService#get_asset_overview(...)`
37
174
  - `AssetService#get_coin_balance(...)`
38
175
  - `AssetService#get_coin_greeks(...)`
176
+ - `AssetService#get_coin_info(...)`
177
+ - `AssetService#get_convert_result(...)`
178
+ - `AssetService#get_delivery_record(...)`
179
+ - `AssetService#get_deposit_address(...)`
180
+ - `AssetService#get_portfolio_margin(...)`
181
+ - `AssetService#get_settlement_record(...)`
182
+ - `AssetService#get_sub_member_deposit_address(...)`
183
+ - `AssetService#get_total_members_assets(...)`
184
+ - `AssetService#get_vasp_list(...)`
185
+ - `AssetService#get_withdrawable_amount_by_coin(...)`
186
+ - `AssetService#inter_transfer(...)`
187
+ - `AssetService#inter_transfer_list_query(...)`
188
+ - `AssetService#list_convert_orders(...)`
189
+ - `AssetService#list_convert_orders_by_page(...)`
190
+ - `AssetService#list_deposit_records(...)`
39
191
  - `AssetService#list_funding_history(...)`
192
+ - `AssetService#list_internal_deposit_records(...)`
193
+ - `AssetService#list_small_balance_coins(...)`
194
+ - `AssetService#list_small_balance_history(...)`
195
+ - `AssetService#list_sub_member_deposit_records(...)`
196
+ - `AssetService#list_withdraw_addresses(...)`
197
+ - `AssetService#list_withdraw_records(...)`
198
+ - `AssetService#quote_apply(...)`
199
+ - `AssetService#send_withdraw(...)`
200
+ - `AssetService#set_default_deposit_to_account(...)`
201
+ - `AssetService#small_asset_convert(...)`
202
+ - `AssetService#small_asset_quote(...)`
203
+ - `AssetService#sub_member_list_query(...)`
204
+ - `AssetService#transfer_coin_list_query(...)`
205
+ - `AssetService#transfer_sub_member_save(...)`
206
+ - `AssetService#universal_transfer(...)`
207
+ - `AssetService#universal_transfer_list_query(...)`
40
208
  - `BrokerService#distribute_award(...)`
41
209
  - `BrokerService#get_award_info(...)`
42
210
  - `BrokerService#get_distribution_record(...)`
@@ -257,3 +425,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
257
425
  - `UserService#sign_agreement(...)`
258
426
  - `UserService#update_api_key(...)`
259
427
  - `UserService#update_sub_api_key(...)`
428
+ - `InstitutionalLoanService#get_product_info(...)`
429
+ - `InstitutionalLoanService#get_margin_coin_info(...)`
430
+ - `InstitutionalLoanService#get_loan_orders(...)`
431
+ - `InstitutionalLoanService#get_repayment_orders(...)`
432
+ - `InstitutionalLoanService#get_ltv(...)`
433
+ - `InstitutionalLoanService#bind_or_unbind_uid(...)`
434
+ - `InstitutionalLoanService#repay_loan(...)`
435
+ - `MiscService#get_announcements(...)`
436
+ - `MiscService#get_system_status(...)`
437
+ - `PreUpgradeService#get_order_history(...)`
438
+ - `PreUpgradeService#get_trade_history(...)`
439
+ - `PreUpgradeService#get_closed_pnl(...)`
440
+ - `PreUpgradeService#get_transaction_log(...)`
441
+ - `PreUpgradeService#get_option_delivery_record(...)`
442
+ - `PreUpgradeService#get_usdc_session_settlement(...)`
443
+ - `Bybit::WebSocket::Client` — public (spot/linear/inverse/option), private,
444
+ and trade streams; HMAC-SHA256 auth, ping/pong, deferred subscribe (topics
445
+ buffered until socket opens; private streams wait for auth OK), idempotent
446
+ `#connect` (second call replays buffered subscriptions), testnet host
447
+ support. Load via `require 'bybit/websocket'` (opt-in dep on
448
+ `websocket-client-simple`).
449
+ - VCR-driven end-to-end specs asserting the exact wire bytes and X-BAPI-SIGN
450
+ header for signed GET (query) and signed POST (body) routing.
451
+ - SimpleCov floor coverage gate for `lib/bybit/rest_api/*_service.rb` — new
452
+ services without matching specs now drop CI.
453
+ - README: WebSocket usage section.
454
+
455
+ ### Fixed
456
+ - `Session#parse_response` now maps HTTP 401/403 → `Bybit::AuthError` and 429
457
+ → `Bybit::RateLimitError` even when the response body is non-JSON
458
+ (CDN/WAF path), matching the contract in README.md#Error-Handling.
459
+ - `BrokerService#list_broker_earnings` — caller-facing kwargs renamed from
460
+ `:begin_` / `:end_` to `:start_date` / `:end_date`; internal rewrite now
461
+ goes through `WireKeys::RESERVED_ALIASES` instead of hand-rolled shim.
data/README.md CHANGED
@@ -1,8 +1,26 @@
1
1
  # bybit-connector-ruby
2
2
 
3
+ [![Gem Version](https://img.shields.io/gem/v/bybit-connector-ruby)](https://rubygems.org/gems/bybit-connector-ruby) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/bybit-exchange/bybit.ruby.api/blob/main/LICENSE)
4
+
3
5
  Official lightweight Ruby connector for the [Bybit V5 REST API](https://bybit-exchange.github.io/docs/v5/intro).
4
6
 
5
- `bybit-connector-ruby` wraps the Bybit V5 HTTP endpoints as a set of typed Ruby methods with keyword-arg signatures. Its goal is the same as [`pybit`](https://github.com/bybit-exchange/pybit) on the Python side: an easy-to-use, high-performance connector with a small dependency footprint.
7
+ `bybit-connector-ruby` wraps the Bybit V5 HTTP endpoints as a set of typed Ruby methods with keyword-arg signatures.
8
+ ## Prerequisites
9
+
10
+ Before you write any code you need a Bybit API key. Two accounts to know
11
+ about:
12
+
13
+ - **Testnet** — [testnet.bybit.com](https://testnet.bybit.com) → sign up →
14
+ API Management → *Create New Key*. This is where you should point every
15
+ new integration until you're confident about behavior. Testnet balances
16
+ are virtual; nothing you do here touches real funds.
17
+ - **Mainnet** — [bybit.com](https://www.bybit.com) → API Management. Real
18
+ money. Enable only the permissions you actually need (spot / derivatives /
19
+ withdrawals) and prefer IP-restricted keys.
20
+
21
+ Testnet and mainnet keys are **separate** — an API key issued on one won't
22
+ work against the other. The SDK selects the environment via
23
+ `testnet: true|false` (or an explicit `base_url:` override).
6
24
 
7
25
  ## Installation
8
26
 
@@ -23,30 +41,43 @@ gem 'bybit-connector-ruby'
23
41
  ```ruby
24
42
  require 'bybit'
25
43
 
44
+ # All calls below run against testnet — swap testnet: false for mainnet
45
+ # once you're happy with the behavior.
26
46
  Bybit.configure do |c|
27
- c.api_key = ENV['BYBIT_KEY']
28
- c.api_secret = ENV['BYBIT_SECRET']
29
- c.testnet = true # omit / false for mainnet
47
+ c.api_key = ENV['BYBIT_TESTNET_KEY']
48
+ c.api_secret = ENV['BYBIT_TESTNET_SECRET']
49
+ c.testnet = true
30
50
  end
31
51
 
32
52
  client = Bybit::Client.new
33
53
 
34
- # Public endpoint — no auth needed
54
+ # 1. Public endpoint — no auth needed.
35
55
  puts client.market.get_server_time
36
56
 
37
- # Signed endpoint — apiKey + apiSecret required
57
+ # 2. Signed endpoint — api_key + api_secret required.
38
58
  wallet = client.account.get_wallet_balance(account_type: 'UNIFIED')
39
59
  puts wallet['result']['list']
40
60
 
41
- # Place an order
61
+ # 3. Place a LIMIT order well below market so it sits on the book and does
62
+ # NOT fill (safe to run repeatedly). Adjust `price:` if BTC ever trades
63
+ # at $10k again — otherwise this stays a resting order you can cancel.
42
64
  order = client.trade.create_order(
43
65
  category: 'linear', symbol: 'BTCUSDT',
44
66
  side: 'Buy', order_type: 'Limit', qty: '0.01',
45
- price: '30000', time_in_force: 'GTC',
67
+ price: '10000', time_in_force: 'GTC'
46
68
  )
47
- puts "orderId: #{order['result']['orderId']}"
69
+ order_id = order['result']['orderId']
70
+ puts "orderId: #{order_id}"
71
+
72
+ # 4. Cancel it before moving on.
73
+ client.trade.cancel_order(category: 'linear', symbol: 'BTCUSDT', order_id: order_id)
48
74
  ```
49
75
 
76
+ > ⚠️ **Before switching `testnet: false`**: verify the price / qty in
77
+ > `create_order` won't cross the top of the book — a Limit Buy at $10k on
78
+ > mainnet becomes a market fill instantly (if BTC ever drops that low),
79
+ > and a Limit Sell at $1M does the reverse.
80
+
50
81
  See `examples/quickstart.rb` for a runnable script.
51
82
 
52
83
  ## Configuration
@@ -58,12 +89,17 @@ Bybit.configure do |c|
58
89
  c.api_key = ENV['BYBIT_KEY']
59
90
  c.api_secret = ENV['BYBIT_SECRET']
60
91
  c.testnet = false # default false
61
- c.recv_window = '5000' # ms, X-BAPI-RECV-WINDOW header
92
+ c.recv_window = '5000' # milliseconds — Bybit rejects requests
93
+ # whose signed timestamp is older than
94
+ # this window. Bump to 10000+ if your
95
+ # clock drifts or the network is noisy.
62
96
  c.timeout = 10 # Faraday timeout, seconds
63
97
  end
64
98
  ```
65
99
 
66
- Or pass overrides to `Client.new`:
100
+ Or pass overrides to `Client.new` — **per-client overrides win over
101
+ `Bybit.configure`**, so you can share defaults globally and still spin up a
102
+ dedicated client with a different key or environment:
67
103
 
68
104
  ```ruby
69
105
  client = Bybit::Client.new(api_key: '...', api_secret: '...', testnet: true)
@@ -92,16 +128,27 @@ Each API group is a property on `Bybit::Client`:
92
128
  - `client.trade` — orders (create / amend / cancel / batch / history)
93
129
  - `client.position` — positions, leverage, TP/SL, move-position
94
130
  - `client.account` — wallet, margin, collateral, fee-rate, transaction log
131
+ - `client.alpha` — Alpha liquidity pools, prediction markets, and on-chain token trading
95
132
  - `client.asset` — coin balance, coin greeks, funding history
96
133
  - `client.user` — sub-accounts, API-key management
97
134
  - `client.affiliate` — sub-affiliate lists
98
135
  - `client.broker` — broker earnings, distributions
99
136
  - `client.crypto_loan` — flexible / fixed crypto loans
137
+ - `client.event` — event contracts, positions, settlements, and executions
138
+ - `client.fiat` — fiat convert balances, quotes, trades, and history
139
+ - `client.institutional_loan` — /v5/ins-loan/* (OTC institutional loans)
100
140
  - `client.rfq` — request-for-quote (block trades)
101
141
  - `client.spot_margin` — UTA spot margin
142
+ - `client.spot_x` — Launchpool, Puzzle Hunt, and Token Splash
143
+ - `client.spread_trade` — spread instruments, orders, orderbook, and executions
144
+ - `client.strategy` — strategy creation, queries, and lifecycle operations
145
+ - `client.tax` — private tax report generation and status queries
102
146
  - `client.earn` — earn, liquidity mining, RWA, PWM, hold-to-earn
103
147
  - `client.p2p` — P2P advertise / order / chat
104
148
  - `client.bot` — DCA / grid / futures-combo / futures-grid / martingale
149
+ - `client.pre_upgrade` — /v5/pre-upgrade/* historical queries for Classic → UTA upgrades
150
+ - `client.referral` — campaign rewards, commissions, profiles, and invitations
151
+ - `client.misc` — /v5/announcements/index, /v5/system/status
105
152
 
106
153
  ## Error Handling
107
154
 
@@ -139,6 +186,12 @@ Full hierarchy:
139
186
 
140
187
  Every `ApiError` exposes `#ret_code`, `#ret_msg`, `#result`, `#time`, `#http_status`. See the [Bybit V5 error-code list](https://bybit-exchange.github.io/docs/v5/error) for meanings.
141
188
 
189
+ > The `sleep 1 && retry` shown above is fine for exploration, **not** for
190
+ > production — Bybit will escalate throttling on tight retry loops. For
191
+ > real workloads, wire a `Faraday::Retry` middleware with exponential
192
+ > backoff via the "bring your own Faraday connection" hook in
193
+ > [Configuration](#configuration) above.
194
+
142
195
  ## Return Value
143
196
 
144
197
  Every service method returns the raw parsed JSON as a `Hash`:
@@ -151,14 +204,106 @@ response['result'] # => { 'category' => 'spot', 'symbol' => 'BTCUSDT', 'list
151
204
  response['time'] # => 1234567890000
152
205
  ```
153
206
 
154
- ## Testnet
207
+ > Keys are **strings, not symbols** — `response[:result]` is `nil`. This is
208
+ > a common first-hour gotcha; pass through `JSON.parse` semantics rather
209
+ > than converting.
210
+
211
+ ## Method Reference
212
+
213
+ Method names follow the Bybit V5 endpoint slug in snake_case, grouped by
214
+ domain. A few illustrative mappings:
215
+
216
+ | Bybit V5 path | SDK method |
217
+ | ------------------------------------- | ----------------------------------------- |
218
+ | `GET /v5/market/kline` | `client.market.get_kline` |
219
+ | `GET /v5/market/tickers` | `client.market.get_tickers` |
220
+ | `POST /v5/order/create` | `client.trade.create_order` |
221
+ | `POST /v5/order/cancel` | `client.trade.cancel_order` |
222
+ | `GET /v5/position/list` | `client.position.get_positions` |
223
+ | `GET /v5/account/wallet-balance` | `client.account.get_wallet_balance` |
224
+
225
+ For the full list, generate YARD docs locally:
226
+
227
+ ```
228
+ bundle exec yard doc
229
+ open doc/index.html
230
+ ```
231
+
232
+ or browse the published copy on
233
+ [rubydoc.info/gems/bybit-connector-ruby](https://rubydoc.info/gems/bybit-connector-ruby).
234
+
235
+ ## Pagination
236
+
237
+ Bybit V5 uses **opaque cursor pagination** — the response's
238
+ `result['nextPageCursor']` (empty string when the page is the last one)
239
+ feeds back in as the `cursor:` argument on the next call:
240
+
241
+ ```ruby
242
+ cursor = nil
243
+ loop do
244
+ resp = client.trade.get_order_history(category: 'linear', limit: 50, cursor: cursor)
245
+ resp['result']['list'].each { |order| process(order) }
246
+ cursor = resp['result']['nextPageCursor']
247
+ break if cursor.nil? || cursor.empty?
248
+ end
249
+ ```
250
+
251
+ The same pattern works for `get_positions`, `get_execution_history`,
252
+ `get_transaction_log`, and every other paginated endpoint.
253
+
254
+ ## WebSockets
155
255
 
156
- Toggle `testnet: true` for [https://testnet.bybit.com](https://testnet.bybit.com):
256
+ Hosts (mirror the REST split):
257
+
258
+ - Mainnet — `wss://stream.bybit.com/v5/{public/<category>|private|trade}`
259
+ - Testnet — `wss://stream-testnet.bybit.com/v5/{public/<category>|private|trade}`
260
+
261
+ WebSocket support ships behind an opt-in require so REST-only consumers don't
262
+ load the underlying `websocket-client-simple` dependency at boot. Four
263
+ callbacks are available; all are optional but you'll almost always want at
264
+ least `on_message`.
157
265
 
158
266
  ```ruby
159
- client = Bybit::Client.new(api_key: ENV['BYBIT_TESTNET_KEY'], api_secret: ENV['BYBIT_TESTNET_SECRET'], testnet: true)
267
+ require 'bybit/websocket'
268
+
269
+ # Public stream — no auth needed.
270
+ public_ws = Bybit::WebSocket::Client.new(
271
+ channel: :linear, # :spot / :linear / :inverse / :option
272
+ testnet: true,
273
+ on_open: -> { puts 'connected' },
274
+ on_message: ->(msg) { puts msg.inspect }, # your handler
275
+ on_close: ->(_ev) { puts 'closed' },
276
+ on_error: ->(err) { warn "ws error: #{err}" }
277
+ ).connect
278
+
279
+ public_ws.subscribe('tickers.BTCUSDT', 'orderbook.1.BTCUSDT')
280
+
281
+ # Private stream — HMAC-SHA256 auth over "GET/realtime" + expiry.
282
+ private_ws = Bybit::WebSocket::Client.new(
283
+ channel: :private,
284
+ testnet: true,
285
+ api_key: ENV['BYBIT_TESTNET_KEY'],
286
+ api_secret: ENV['BYBIT_TESTNET_SECRET'],
287
+ on_message: ->(msg) { puts msg.inspect } # your handler
288
+ ).connect
289
+
290
+ # Subscribe returns immediately; the actual `op:subscribe` frame is deferred
291
+ # until the private-stream auth reply lands, so you can call subscribe
292
+ # anytime — before or after `#connect`.
293
+ private_ws.subscribe('position', 'order', 'wallet')
294
+
295
+ # Later:
296
+ private_ws.unsubscribe('wallet')
297
+ private_ws.disconnect
160
298
  ```
161
299
 
300
+ Supported channels: `:spot`, `:linear`, `:inverse`, `:option`, `:private`,
301
+ `:trade`. `testnet: true` swaps in the `stream-testnet.bybit.com` host.
302
+ Pings ship every 20 seconds — Bybit closes idle sockets after ~20s of
303
+ silence. There is no automatic reconnect on network drop: callers listening
304
+ on `on_close` can invoke `#connect` again to reopen the socket and replay
305
+ the buffered `#subscriptions`.
306
+
162
307
  ## Development
163
308
 
164
309
  ```
@@ -1,29 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # End-to-end quickstart — public + signed calls + rescue matrix.
4
- # Run with: BYBIT_KEY=... BYBIT_SECRET=... ruby examples/quickstart.rb
3
+ # End-to-end quickstart — mirrors README's Quick Start:
4
+ # 1. public unsigned call
5
+ # 2. signed GET (wallet balance)
6
+ # 3. safe LIMIT order well below market (does not fill)
7
+ # 4. cancel that order
8
+ # Run with:
9
+ # BYBIT_TESTNET_KEY=... BYBIT_TESTNET_SECRET=... ruby examples/quickstart.rb
5
10
 
6
11
  require 'bybit'
7
12
 
8
13
  Bybit.configure do |c|
9
- c.api_key = ENV['BYBIT_KEY']
10
- c.api_secret = ENV['BYBIT_SECRET']
11
- c.testnet = true # flip to false for mainnet
14
+ c.api_key = ENV.fetch('BYBIT_TESTNET_KEY')
15
+ c.api_secret = ENV.fetch('BYBIT_TESTNET_SECRET')
16
+ c.testnet = true # flip to false for mainnet — see README warning
12
17
  end
13
18
 
14
19
  client = Bybit::Client.new
15
20
 
16
- # 1. Public endpoint — server time (no auth needed)
21
+ # 1. Public endpoint — server time (no auth needed).
17
22
  puts '--- server time ---'
18
23
  puts client.market.get_server_time.inspect
19
24
 
20
- # 2. Signed endpoint — wallet balance
25
+ # 2. Signed endpoint — wallet balance.
21
26
  puts '--- wallet balance ---'
22
27
  begin
23
28
  wallet = client.account.get_wallet_balance(account_type: 'UNIFIED')
24
29
  puts wallet['result']['list'].inspect
25
30
  rescue Bybit::AuthError => e
26
31
  warn "auth failed: [#{e.ret_code}] #{e.ret_msg}"
32
+ exit 1
27
33
  rescue Bybit::RateLimitError => e
28
34
  warn "rate-limited: #{e.ret_msg}"
29
35
  rescue Bybit::TimeoutError => e
@@ -33,3 +39,26 @@ rescue Bybit::NetworkError => e
33
39
  rescue Bybit::ApiError => e
34
40
  warn "api error [#{e.ret_code}]: #{e.ret_msg}"
35
41
  end
42
+
43
+ # 3. Place a LIMIT order well below market so it sits on the book and does
44
+ # NOT fill (safe to run repeatedly). Adjust price if BTC ever trades that
45
+ # low; otherwise this stays a resting order you can cancel below.
46
+ puts '--- place limit order ---'
47
+ begin
48
+ order = client.trade.create_order(
49
+ category: 'linear', symbol: 'BTCUSDT',
50
+ side: 'Buy', order_type: 'Limit', qty: '0.01',
51
+ price: '10000', time_in_force: 'GTC'
52
+ )
53
+ order_id = order['result']['orderId']
54
+ puts "orderId: #{order_id}"
55
+
56
+ # 4. Cancel it before exiting so we don't leave test orders on the book.
57
+ puts '--- cancel order ---'
58
+ cancel = client.trade.cancel_order(
59
+ category: 'linear', symbol: 'BTCUSDT', order_id: order_id
60
+ )
61
+ puts cancel['result'].inspect
62
+ rescue Bybit::ApiError => e
63
+ warn "api error [#{e.ret_code}]: #{e.ret_msg}"
64
+ end
data/lib/bybit/client.rb CHANGED
@@ -8,13 +8,24 @@ require 'bybit/rest_api/bot_service'
8
8
  require 'bybit/rest_api/broker_service'
9
9
  require 'bybit/rest_api/crypto_loan_service'
10
10
  require 'bybit/rest_api/earn_service'
11
+ require 'bybit/rest_api/institutional_loan_service'
11
12
  require 'bybit/rest_api/market_service'
13
+ require 'bybit/rest_api/misc_service'
12
14
  require 'bybit/rest_api/p2p_service'
13
15
  require 'bybit/rest_api/position_service'
16
+ require 'bybit/rest_api/pre_upgrade_service'
14
17
  require 'bybit/rest_api/rfq_service'
15
18
  require 'bybit/rest_api/spot_margin_service'
16
19
  require 'bybit/rest_api/trade_service'
17
20
  require 'bybit/rest_api/user_service'
21
+ require 'bybit/rest_api/alpha_service'
22
+ require 'bybit/rest_api/event_service'
23
+ require 'bybit/rest_api/fiat_service'
24
+ require 'bybit/rest_api/referral_service'
25
+ require 'bybit/rest_api/spot_x_service'
26
+ require 'bybit/rest_api/spread_trade_service'
27
+ require 'bybit/rest_api/strategy_service'
28
+ require 'bybit/rest_api/tax_service'
18
29
  # gen-sdk-ruby:service-requires:end
19
30
 
20
31
  module Bybit
@@ -33,8 +44,10 @@ module Bybit
33
44
 
34
45
  class Client
35
46
  # gen-sdk-ruby:client-readers:start
36
- attr_reader :account, :affiliate, :asset, :bot, :broker, :crypto_loan, :earn,
37
- :market, :p2p, :position, :rfq, :spot_margin, :trade, :user
47
+ attr_reader :account, :affiliate, :alpha, :asset, :bot, :broker, :crypto_loan, :earn,
48
+ :event, :fiat, :institutional_loan, :market, :misc, :p2p, :position,
49
+ :pre_upgrade, :referral, :rfq, :spot_margin, :spot_x, :spread_trade,
50
+ :strategy, :tax, :trade, :user
38
51
 
39
52
  # gen-sdk-ruby:client-readers:end
40
53
 
@@ -45,20 +58,35 @@ module Bybit
45
58
  @config = cfg
46
59
 
47
60
  # gen-sdk-ruby:client-inits:start
48
- @account = RestApi::AccountService.new(session)
49
- @affiliate = RestApi::AffiliateService.new(session)
50
- @asset = RestApi::AssetService.new(session)
51
- @bot = RestApi::BotService.new(session)
52
- @broker = RestApi::BrokerService.new(session)
53
- @crypto_loan = RestApi::CryptoLoanService.new(session)
54
- @earn = RestApi::EarnService.new(session)
55
- @market = RestApi::MarketService.new(session)
56
- @p2p = RestApi::P2pService.new(session)
57
- @position = RestApi::PositionService.new(session)
58
- @rfq = RestApi::RfqService.new(session)
59
- @spot_margin = RestApi::SpotMarginService.new(session)
60
- @trade = RestApi::TradeService.new(session)
61
- @user = RestApi::UserService.new(session)
61
+ {
62
+ account: RestApi::AccountService,
63
+ affiliate: RestApi::AffiliateService,
64
+ alpha: RestApi::AlphaService,
65
+ asset: RestApi::AssetService,
66
+ bot: RestApi::BotService,
67
+ broker: RestApi::BrokerService,
68
+ crypto_loan: RestApi::CryptoLoanService,
69
+ earn: RestApi::EarnService,
70
+ event: RestApi::EventService,
71
+ fiat: RestApi::FiatService,
72
+ institutional_loan: RestApi::InstitutionalLoanService,
73
+ market: RestApi::MarketService,
74
+ misc: RestApi::MiscService,
75
+ p2p: RestApi::P2pService,
76
+ position: RestApi::PositionService,
77
+ pre_upgrade: RestApi::PreUpgradeService,
78
+ referral: RestApi::ReferralService,
79
+ rfq: RestApi::RfqService,
80
+ spot_margin: RestApi::SpotMarginService,
81
+ spot_x: RestApi::SpotXService,
82
+ spread_trade: RestApi::SpreadTradeService,
83
+ strategy: RestApi::StrategyService,
84
+ tax: RestApi::TaxService,
85
+ trade: RestApi::TradeService,
86
+ user: RestApi::UserService
87
+ }.each do |name, service_class|
88
+ instance_variable_set("@#{name}", service_class.new(session))
89
+ end
62
90
  # gen-sdk-ruby:client-inits:end
63
91
  end
64
92
 
data/lib/bybit/error.rb CHANGED
@@ -22,16 +22,24 @@ module Bybit
22
22
 
23
23
  # Raised when the server returns HTTP 200 + retCode != 0 (the V5 norm),
24
24
  # or when a transport-level error is enriched with a Bybit body payload.
25
+ # Accepts either a V5 response Hash (extracts retCode/retMsg/result/time)
26
+ # or a plain String message (used for HTTP-status mapping when the CDN/WAF
27
+ # returns a non-JSON body — e.g. 401/403/429 → AuthError/RateLimitError
28
+ # without a decodable retCode).
25
29
  class ApiError < Error
26
30
  attr_reader :ret_code, :ret_msg, :result, :time, :http_status
27
31
 
28
32
  def initialize(response, http_status: nil)
29
- @ret_code = response['retCode']
30
- @ret_msg = response['retMsg']
31
- @result = response['result']
32
- @time = response['time']
33
33
  @http_status = http_status
34
- super("[#{@ret_code}] #{@ret_msg}")
34
+ if response.is_a?(Hash)
35
+ @ret_code = response['retCode']
36
+ @ret_msg = response['retMsg']
37
+ @result = response['result']
38
+ @time = response['time']
39
+ super("[#{@ret_code}] #{@ret_msg}")
40
+ else
41
+ super(response.to_s)
42
+ end
35
43
  end
36
44
  end
37
45