bybit-connector-ruby 0.1.0

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.
@@ -0,0 +1,289 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bybit
4
+ module RestApi
5
+ class TradeService < BaseService
6
+ # Get Trade History
7
+ #
8
+ # GET /v5/execution/list
9
+ #
10
+ # @param category [String] Product type
11
+ # @option kwargs [String] :symbol Symbol name
12
+ # @option kwargs [String] :order_id Order ID
13
+ # @option kwargs [String] :order_link_id User customised order ID
14
+ # @option kwargs [String] :base_coin Base coin
15
+ # @option kwargs [String] :settle_coin Settle coin
16
+ # @option kwargs [Integer] :start_time The start timestamp (ms)
17
+ # @option kwargs [Integer] :end_time The end timestamp (ms)
18
+ # @option kwargs [String] :exec_type Execution type
19
+ # @option kwargs [Integer] :limit Limit for data size per page
20
+ # @option kwargs [String] :cursor Cursor for pagination
21
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
22
+ # @see https://bybit-exchange.github.io/docs/v5/order/execution
23
+ def get_execution_history(category:, **kwargs)
24
+ params = kwargs.merge(category: category)
25
+ params = Bybit::Utils::WireKeys.camelize(params)
26
+ @session.sign_request(method: :get, path: '/v5/execution/list', params: params)
27
+ end
28
+
29
+ # Amend an open unfilled or partially filled order.
30
+ #
31
+ # POST /v5/order/amend
32
+ #
33
+ # @param category [String] Product type
34
+ # @param symbol [String] Symbol name
35
+ # @option kwargs [String] :order_id Order ID
36
+ # @option kwargs [String] :order_link_id User customised order ID
37
+ # @option kwargs [String] :order_iv Implied volatility (options)
38
+ # @option kwargs [String] :trigger_price Trigger price
39
+ # @option kwargs [String] :qty Order quantity
40
+ # @option kwargs [String] :price Order price
41
+ # @option kwargs [String] :tpsl_mode TP/SL mode
42
+ # @option kwargs [String] :take_profit Take profit price
43
+ # @option kwargs [String] :stop_loss Stop loss price
44
+ # @option kwargs [String] :tp_trigger_by Take profit trigger price type
45
+ # @option kwargs [String] :sl_trigger_by Stop loss trigger price type
46
+ # @option kwargs [String] :trigger_by Trigger price type
47
+ # @option kwargs [String] :tp_limit_price Take profit limit price
48
+ # @option kwargs [String] :sl_limit_price Stop loss limit price
49
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
50
+ # @see https://bybit-exchange.github.io/docs/v5/order/amend-order
51
+ def amend_order(category:, symbol:, **kwargs)
52
+ params = kwargs.merge(category: category, symbol: symbol)
53
+ params = Bybit::Utils::WireKeys.camelize(params)
54
+ @session.sign_request(method: :post, path: '/v5/order/amend', body: params)
55
+ end
56
+
57
+ # Batch amend multiple orders in a single request.
58
+ #
59
+ # POST /v5/order/amend-batch
60
+ #
61
+ # @param category [String] Product type
62
+ # @param request [Array] Array of order amend objects
63
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
64
+ # @see https://bybit-exchange.github.io/docs/v5/order/batch-amend
65
+ def batch_amend_orders(category:, request:, **kwargs)
66
+ params = kwargs.merge(category: category, request: request)
67
+ params = Bybit::Utils::WireKeys.camelize(params)
68
+ @session.sign_request(method: :post, path: '/v5/order/amend-batch', body: params)
69
+ end
70
+
71
+ # Batch cancel multiple orders in a single request.
72
+ #
73
+ # POST /v5/order/cancel-batch
74
+ #
75
+ # @param category [String] Product type
76
+ # @param request [Array] Array of order cancel objects
77
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
78
+ # @see https://bybit-exchange.github.io/docs/v5/order/batch-cancel
79
+ def batch_cancel_orders(category:, request:, **kwargs)
80
+ params = kwargs.merge(category: category, request: request)
81
+ params = Bybit::Utils::WireKeys.camelize(params)
82
+ @session.sign_request(method: :post, path: '/v5/order/cancel-batch', body: params)
83
+ end
84
+
85
+ # Batch place multiple orders in a single request.
86
+ #
87
+ # POST /v5/order/create-batch
88
+ #
89
+ # @param category [String] Product type
90
+ # @param request [Array] Array of order create objects
91
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
92
+ # @see https://bybit-exchange.github.io/docs/v5/order/batch-place
93
+ def batch_create_orders(category:, request:, **kwargs)
94
+ params = kwargs.merge(category: category, request: request)
95
+ params = Bybit::Utils::WireKeys.camelize(params)
96
+ @session.sign_request(method: :post, path: '/v5/order/create-batch', body: params)
97
+ end
98
+
99
+ # Cancel all open orders for a product line, symbol, or coin.
100
+ #
101
+ # POST /v5/order/cancel-all
102
+ #
103
+ # @param category [String] Product type
104
+ # @option kwargs [String] :symbol Symbol name
105
+ # @option kwargs [String] :base_coin Base coin
106
+ # @option kwargs [String] :settle_coin Settle coin
107
+ # @option kwargs [String] :order_filter Order filter
108
+ # @option kwargs [String] :stop_order_type Stop order type
109
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
110
+ # @see https://bybit-exchange.github.io/docs/v5/order/cancel-all
111
+ def cancel_all_orders(category:, **kwargs)
112
+ params = kwargs.merge(category: category)
113
+ params = Bybit::Utils::WireKeys.camelize(params)
114
+ @session.sign_request(method: :post, path: '/v5/order/cancel-all', body: params)
115
+ end
116
+
117
+ # Cancel a single open order by orderId or orderLinkId.
118
+ #
119
+ # POST /v5/order/cancel
120
+ #
121
+ # @param category [String] Product type
122
+ # @param symbol [String] Symbol name
123
+ # @option kwargs [String] :order_id Order ID
124
+ # @option kwargs [String] :order_link_id User customised order ID
125
+ # @option kwargs [String] :order_filter Order filter
126
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
127
+ # @see https://bybit-exchange.github.io/docs/v5/order/cancel-order
128
+ def cancel_order(category:, symbol:, **kwargs)
129
+ params = kwargs.merge(category: category, symbol: symbol)
130
+ params = Bybit::Utils::WireKeys.camelize(params)
131
+ @session.sign_request(method: :post, path: '/v5/order/cancel', body: params)
132
+ end
133
+
134
+ # Place a new order for spot, linear, inverse, or option products.
135
+ #
136
+ # POST /v5/order/create
137
+ #
138
+ # @param category [String] Product type
139
+ # @param symbol [String] Symbol name
140
+ # @param side [String] Buy or Sell
141
+ # @param order_type [String] Market or Limit
142
+ # @param qty [String] Order quantity
143
+ # @option kwargs [Integer] :is_leverage Whether to borrow (spot margin)
144
+ # @option kwargs [String] :market_unit Unit for spot market order quantity
145
+ # @option kwargs [String] :slippage_tolerance_type Slippage tolerance type
146
+ # @option kwargs [String] :slippage_tolerance Slippage tolerance value
147
+ # @option kwargs [String] :price Order price
148
+ # @option kwargs [Integer] :trigger_direction Conditional order trigger direction
149
+ # @option kwargs [String] :order_filter Order filter
150
+ # @option kwargs [String] :trigger_price Trigger price
151
+ # @option kwargs [String] :trigger_by Trigger price type
152
+ # @option kwargs [String] :order_iv Implied volatility (options)
153
+ # @option kwargs [String] :time_in_force Time in force
154
+ # @option kwargs [Integer] :position_idx Position mode index
155
+ # @option kwargs [String] :order_link_id User customised order ID
156
+ # @option kwargs [String] :take_profit Take profit price
157
+ # @option kwargs [String] :stop_loss Stop loss price
158
+ # @option kwargs [String] :tp_trigger_by Take profit trigger price type
159
+ # @option kwargs [String] :sl_trigger_by Stop loss trigger price type
160
+ # @option kwargs [Boolean] :reduce_only Reduce-only flag
161
+ # @option kwargs [Boolean] :close_on_trigger Close on trigger flag
162
+ # @option kwargs [String] :smp_type Self match prevention type
163
+ # @option kwargs [Boolean] :mmp Market maker protection flag (options)
164
+ # @option kwargs [String] :tpsl_mode TP/SL mode
165
+ # @option kwargs [String] :tp_limit_price Take profit limit price
166
+ # @option kwargs [String] :sl_limit_price Stop loss limit price
167
+ # @option kwargs [String] :tp_order_type Take profit order type
168
+ # @option kwargs [String] :sl_order_type Stop loss order type
169
+ # @option kwargs [String] :bbo_side_type BBO side type
170
+ # @option kwargs [String] :bbo_level BBO level
171
+ # @option kwargs [Boolean] :rpi_taker_access RPI taker access flag
172
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
173
+ # @see https://bybit-exchange.github.io/docs/v5/order/create-order
174
+ def create_order(category:, symbol:, side:, order_type:, qty:, **kwargs)
175
+ params = kwargs.merge(category: category, symbol: symbol, side: side, order_type: order_type, qty: qty)
176
+ params = Bybit::Utils::WireKeys.camelize(params)
177
+ @session.sign_request(method: :post, path: '/v5/order/create', body: params)
178
+ end
179
+
180
+ # Set DCP time window (alias endpoint for Disconnected Cancel All Protection).
181
+ #
182
+ # POST /v5/order/disconnected-cancel-all
183
+ #
184
+ # @param time_window [Integer] DCP time window in seconds
185
+ # @option kwargs [String] :product Product type for DCP
186
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
187
+ # @see https://bybit-exchange.github.io/docs/v5/order/dcp
188
+ def set_dcp_time_window(time_window:, **kwargs)
189
+ params = kwargs.merge(time_window: time_window)
190
+ params = Bybit::Utils::WireKeys.camelize(params)
191
+ @session.sign_request(method: :post, path: '/v5/order/disconnected-cancel-all', body: params)
192
+ end
193
+
194
+ # Query unfilled or partially filled orders in real-time.
195
+ #
196
+ # GET /v5/order/realtime
197
+ #
198
+ # @param category [String] Product type
199
+ # @option kwargs [String] :symbol Symbol name
200
+ # @option kwargs [String] :base_coin Base coin
201
+ # @option kwargs [String] :settle_coin Settle coin
202
+ # @option kwargs [String] :order_id Order ID
203
+ # @option kwargs [String] :order_link_id User customised order ID
204
+ # @option kwargs [Integer] :open_only Open-only filter
205
+ # @option kwargs [String] :order_filter Order filter
206
+ # @option kwargs [Integer] :limit Limit for data size per page
207
+ # @option kwargs [String] :cursor Cursor for pagination
208
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
209
+ # @see https://bybit-exchange.github.io/docs/v5/order/open-order
210
+ def get_open_orders(category:, **kwargs)
211
+ params = kwargs.merge(category: category)
212
+ params = Bybit::Utils::WireKeys.camelize(params)
213
+ @session.sign_request(method: :get, path: '/v5/order/realtime', params: params)
214
+ end
215
+
216
+ # Query historical orders that have been fully filled or cancelled.
217
+ #
218
+ # GET /v5/order/history
219
+ #
220
+ # @param category [String] Product type
221
+ # @option kwargs [String] :symbol Symbol name
222
+ # @option kwargs [String] :base_coin Base coin
223
+ # @option kwargs [String] :settle_coin Settle coin
224
+ # @option kwargs [String] :order_id Order ID
225
+ # @option kwargs [String] :order_link_id User customised order ID
226
+ # @option kwargs [String] :order_filter Order filter
227
+ # @option kwargs [String] :order_status Order status
228
+ # @option kwargs [Integer] :start_time Start time (ms)
229
+ # @option kwargs [Integer] :end_time End time (ms)
230
+ # @option kwargs [Integer] :limit Limit for data size per page
231
+ # @option kwargs [String] :cursor Cursor for pagination
232
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
233
+ # @see https://bybit-exchange.github.io/docs/v5/order/order-list
234
+ def get_order_history(category:, **kwargs)
235
+ params = kwargs.merge(category: category)
236
+ params = Bybit::Utils::WireKeys.camelize(params)
237
+ @session.sign_request(method: :get, path: '/v5/order/history', params: params)
238
+ end
239
+
240
+ # Query the available borrow quota for spot margin trading.
241
+ #
242
+ # GET /v5/order/spot-borrow-check
243
+ #
244
+ # @param category [String] Product type
245
+ # @param symbol [String] Symbol name
246
+ # @param side [String] Buy or Sell
247
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
248
+ # @see https://bybit-exchange.github.io/docs/v5/order/spot-borrow-quota
249
+ def get_spot_borrow_quota(category:, symbol:, side:, **kwargs)
250
+ params = kwargs.merge(category: category, symbol: symbol, side: side)
251
+ params = Bybit::Utils::WireKeys.camelize(params)
252
+ @session.sign_request(method: :get, path: '/v5/order/spot-borrow-check', params: params)
253
+ end
254
+
255
+ # Pre-check an order before submission to validate parameters and margin.
256
+ #
257
+ # POST /v5/order/pre-check
258
+ #
259
+ # @param category [String] Product type
260
+ # @param symbol [String] Symbol name
261
+ # @param side [String] Buy or Sell
262
+ # @param order_type [String] Market or Limit
263
+ # @param qty [String] Order quantity
264
+ # @option kwargs [String] :price Order price
265
+ # @option kwargs [Integer] :is_leverage Whether to borrow (spot margin)
266
+ # @option kwargs [String] :time_in_force Time in force
267
+ # @option kwargs [Integer] :position_idx Position mode index
268
+ # @option kwargs [String] :order_link_id User customised order ID
269
+ # @option kwargs [String] :take_profit Take profit price
270
+ # @option kwargs [String] :stop_loss Stop loss price
271
+ # @option kwargs [String] :tp_trigger_by Take profit trigger price type
272
+ # @option kwargs [String] :sl_trigger_by Stop loss trigger price type
273
+ # @option kwargs [Boolean] :reduce_only Reduce-only flag
274
+ # @option kwargs [String] :tpsl_mode TP/SL mode
275
+ # @option kwargs [String] :tp_limit_price Take profit limit price
276
+ # @option kwargs [String] :sl_limit_price Stop loss limit price
277
+ # @option kwargs [String] :tp_order_type Take profit order type
278
+ # @option kwargs [String] :sl_order_type Stop loss order type
279
+ # @option kwargs [String] :order_iv Implied volatility (options)
280
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
281
+ # @see https://bybit-exchange.github.io/docs/v5/order/pre-check-order
282
+ def pre_check_order(category:, symbol:, side:, order_type:, qty:, **kwargs)
283
+ params = kwargs.merge(category: category, symbol: symbol, side: side, order_type: order_type, qty: qty)
284
+ params = Bybit::Utils::WireKeys.camelize(params)
285
+ @session.sign_request(method: :post, path: '/v5/order/pre-check', body: params)
286
+ end
287
+ end
288
+ end
289
+ end
@@ -0,0 +1,254 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bybit
4
+ module RestApi
5
+ class UserService < BaseService
6
+ # Create Sub API Key.
7
+ #
8
+ # POST /v5/user/create-sub-api
9
+ #
10
+ # @param subuid [Integer] Sub UID
11
+ # @param read_only [Integer] Read-only permission flag (0: read-write, 1: read-only)
12
+ # @param permissions [Hash] API key permission settings. Bybit V5 expects
13
+ # PascalCase group keys — e.g. `{ 'ContractTrade' => ['Order'], 'Spot' => ['Order'], 'Wallet' => ['AccountTransfer'] }`.
14
+ # The SDK passes this hash through VERBATIM (no snake→camel conversion)
15
+ # so callers must use the docs-spelling of each group name.
16
+ # @option kwargs [String] :ips Bound IP addresses (comma-separated)
17
+ # @option kwargs [String] :note API key note
18
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
19
+ # @see https://bybit-exchange.github.io/docs/v5/user/create-subuid-apikey
20
+ def create_sub_api_key(subuid:, read_only:, permissions:, **kwargs)
21
+ params = kwargs.merge(subuid: subuid, read_only: read_only)
22
+ params = Bybit::Utils::WireKeys.camelize(params)
23
+ # `permissions` is intentionally re-attached AFTER camelize — Bybit V5
24
+ # wants PascalCase group keys (ContractTrade / Spot / Wallet / ...)
25
+ # which a naive snake→camel pass would corrupt.
26
+ params[:permissions] = permissions
27
+ @session.sign_request(method: :post, path: '/v5/user/create-sub-api', body: params)
28
+ end
29
+
30
+ # Create Sub UID.
31
+ #
32
+ # POST /v5/user/create-sub-member
33
+ #
34
+ # @param username [String] Sub-account username
35
+ # @param member_type [Integer] Sub-account type (1: normal, 6: custodial)
36
+ # @option kwargs [String] :password Sub-account login password
37
+ # @option kwargs [Integer] :switch Quick login toggle
38
+ # @option kwargs [Boolean] :is_uta Whether to create as UTA account
39
+ # @option kwargs [String] :note Sub-account note
40
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
41
+ # @see https://bybit-exchange.github.io/docs/v5/user/create-subuid
42
+ def create_sub_member(username:, member_type:, **kwargs)
43
+ params = kwargs.merge(username: username, member_type: member_type)
44
+ params = Bybit::Utils::WireKeys.camelize(params)
45
+ @session.sign_request(method: :post, path: '/v5/user/create-sub-member', body: params)
46
+ end
47
+
48
+ # Delete Master API Key.
49
+ #
50
+ # POST /v5/user/delete-api
51
+ #
52
+ # @option kwargs [String] :apikey API key to delete
53
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
54
+ # @see https://bybit-exchange.github.io/docs/v5/user/rm-master-apikey
55
+ def delete_api_key(**kwargs)
56
+ params = kwargs.dup
57
+ params = Bybit::Utils::WireKeys.camelize(params)
58
+ @session.sign_request(method: :post, path: '/v5/user/delete-api', body: params)
59
+ end
60
+
61
+ # Delete Sub-account API Key.
62
+ #
63
+ # POST /v5/user/delete-sub-api
64
+ #
65
+ # @param subuid [Integer] Sub UID
66
+ # @option kwargs [String] :apikey Sub-account API key to delete
67
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
68
+ # @see https://bybit-exchange.github.io/docs/v5/user/rm-sub-apikey
69
+ def delete_sub_api_key(subuid:, **kwargs)
70
+ params = kwargs.merge(subuid: subuid)
71
+ params = Bybit::Utils::WireKeys.camelize(params)
72
+ @session.sign_request(method: :post, path: '/v5/user/delete-sub-api', body: params)
73
+ end
74
+
75
+ # Delete Sub-account.
76
+ #
77
+ # POST /v5/user/del-submember
78
+ #
79
+ # @param subuid [Integer] Sub UID to delete
80
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
81
+ def delete_sub_member(subuid:, **kwargs)
82
+ params = kwargs.merge(subuid: subuid)
83
+ params = Bybit::Utils::WireKeys.camelize(params)
84
+ @session.sign_request(method: :post, path: '/v5/user/del-submember', body: params)
85
+ end
86
+
87
+ # Freeze or unfreeze a Sub UID.
88
+ #
89
+ # POST /v5/user/frozen-sub-member
90
+ #
91
+ # @param subuid [Integer] Sub UID
92
+ # @param frozen [Integer] Freeze flag (0: unfreeze, 1: freeze)
93
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
94
+ # @see https://bybit-exchange.github.io/docs/v5/user/froze-subuid
95
+ def frozen_sub_member(subuid:, frozen:, **kwargs)
96
+ params = kwargs.merge(subuid: subuid, frozen: frozen)
97
+ params = Bybit::Utils::WireKeys.camelize(params)
98
+ @session.sign_request(method: :post, path: '/v5/user/frozen-sub-member', body: params)
99
+ end
100
+
101
+ # Get Affiliate User Info.
102
+ #
103
+ # GET /v5/user/aff-customer-info
104
+ #
105
+ # @param uid [String] Affiliate user UID
106
+ # @option kwargs [String] :coin Coin filter
107
+ # @option kwargs [String] :business Business type filter
108
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
109
+ def get_affiliate_custom_open_info(uid:, **kwargs)
110
+ params = kwargs.merge(uid: uid)
111
+ params = Bybit::Utils::WireKeys.camelize(params)
112
+ @session.sign_request(method: :get, path: '/v5/user/aff-customer-info', params: params)
113
+ end
114
+
115
+ # Get Member Account Type.
116
+ #
117
+ # GET /v5/user/get-member-type
118
+ #
119
+ # @option kwargs [String] :member_ids Comma-separated member IDs
120
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
121
+ def get_member_account_type(**kwargs)
122
+ params = kwargs.dup
123
+ params = Bybit::Utils::WireKeys.camelize(params)
124
+ @session.sign_request(method: :get, path: '/v5/user/get-member-type', params: params)
125
+ end
126
+
127
+ # List Sub-account API Keys.
128
+ #
129
+ # GET /v5/user/sub-apikeys
130
+ #
131
+ # @param subuid [Integer] Sub UID
132
+ # @option kwargs [Integer] :limit Page limit
133
+ # @option kwargs [String] :cursor Pagination cursor
134
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
135
+ # @see https://bybit-exchange.github.io/docs/v5/user/list-sub-apikeys
136
+ def list_sub_api_keys(subuid:, **kwargs)
137
+ params = kwargs.merge(subuid: subuid)
138
+ params = Bybit::Utils::WireKeys.camelize(params)
139
+ @session.sign_request(method: :get, path: '/v5/user/sub-apikeys', params: params)
140
+ end
141
+
142
+ # Get API Key Information.
143
+ #
144
+ # GET /v5/user/query-api
145
+ #
146
+ # @see https://bybit-exchange.github.io/docs/v5/user/apikey-info
147
+ def get_api_key_info
148
+ @session.sign_request(method: :get, path: '/v5/user/query-api')
149
+ end
150
+
151
+ # Query Escrow Sub-accounts (Fund Management).
152
+ #
153
+ # GET /v5/user/escrow_sub_members
154
+ #
155
+ # @option kwargs [Integer] :next_cursor Pagination cursor
156
+ # @option kwargs [Integer] :page_size Page size
157
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
158
+ def list_escrow_sub_members(**kwargs)
159
+ params = kwargs.dup
160
+ params = Bybit::Utils::WireKeys.camelize(params)
161
+ @session.sign_request(method: :get, path: '/v5/user/escrow_sub_members', params: params)
162
+ end
163
+
164
+ # Query Referrals.
165
+ #
166
+ # GET /v5/user/invitation/referrals
167
+ #
168
+ # @option kwargs [String] :cursor Pagination cursor
169
+ # @option kwargs [Integer] :size Page size
170
+ # @option kwargs [String] :status Referral status filter
171
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
172
+ def list_referrals(**kwargs)
173
+ params = kwargs.dup
174
+ params = Bybit::Utils::WireKeys.camelize(params)
175
+ @session.sign_request(method: :get, path: '/v5/user/invitation/referrals', params: params)
176
+ end
177
+
178
+ # Query Sub UID List.
179
+ #
180
+ # GET /v5/user/query-sub-members
181
+ #
182
+ # @see https://bybit-exchange.github.io/docs/v5/user/subuid-list
183
+ def list_sub_member_uids
184
+ @session.sign_request(method: :get, path: '/v5/user/query-sub-members')
185
+ end
186
+
187
+ # List Sub-accounts (paginated variant — /v5/user/submembers).
188
+ # Distinct from #list_sub_member_uids (/v5/user/query-sub-members).
189
+ #
190
+ # GET /v5/user/submembers
191
+ #
192
+ # @option kwargs [Integer] :page_size Page size
193
+ # @option kwargs [Integer] :next_cursor Pagination cursor
194
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
195
+ def list_sub_members(**kwargs)
196
+ params = kwargs.dup
197
+ params = Bybit::Utils::WireKeys.camelize(params)
198
+ @session.sign_request(method: :get, path: '/v5/user/submembers', params: params)
199
+ end
200
+
201
+ # Sign Agreement
202
+ #
203
+ # POST /v5/user/agreement
204
+ #
205
+ # @param category [Integer] Agreement category
206
+ # @param agree [Boolean] Whether to agree
207
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
208
+ def sign_agreement(category:, agree:, **kwargs)
209
+ params = kwargs.merge(category: category, agree: agree)
210
+ params = Bybit::Utils::WireKeys.camelize(params)
211
+ @session.sign_request(method: :post, path: '/v5/user/agreement', body: params)
212
+ end
213
+
214
+ # Modify Master API Key
215
+ #
216
+ # POST /v5/user/update-api
217
+ #
218
+ # @option kwargs [Integer] :read_only Read-only flag
219
+ # @option kwargs [String] :ips Bound IP list
220
+ # @option kwargs [Hash] :permissions Permissions object
221
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
222
+ # @see https://bybit-exchange.github.io/docs/v5/user/modify-master-apikey
223
+ def update_api_key(**kwargs)
224
+ params = kwargs.dup
225
+ params = Bybit::Utils::WireKeys.camelize(params)
226
+ @session.sign_request(method: :post, path: '/v5/user/update-api', body: params)
227
+ end
228
+
229
+ # Modify Sub-account API Key
230
+ #
231
+ # POST /v5/user/update-sub-api
232
+ #
233
+ # @param subuid [Integer] Sub UID
234
+ # @param read_only [Integer] Read-only flag
235
+ # @option kwargs [String] :apikey Sub-account API key
236
+ # @option kwargs [String] :ips Bound IP list
237
+ # @option kwargs [Hash] :permissions Permissions object. Bybit V5 expects
238
+ # PascalCase group keys (`ContractTrade` / `Spot` / `Wallet` / ...). This
239
+ # hash is passed through VERBATIM — no snake→camel conversion.
240
+ # @option kwargs [String] :note Note
241
+ # @return [Hash] Bybit V5 ApiResponse envelope (retCode / retMsg / result / retExtInfo / time).
242
+ # @see https://bybit-exchange.github.io/docs/v5/user/modify-sub-apikey
243
+ def update_sub_api_key(subuid:, read_only:, **kwargs)
244
+ permissions = kwargs.delete(:permissions)
245
+ params = kwargs.merge(subuid: subuid, read_only: read_only)
246
+ params = Bybit::Utils::WireKeys.camelize(params)
247
+ # See `create_sub_api_key` — permissions is re-attached AFTER camelize
248
+ # so PascalCase group keys survive the wire trip intact.
249
+ params[:permissions] = permissions unless permissions.nil?
250
+ @session.sign_request(method: :post, path: '/v5/user/update-sub-api', body: params)
251
+ end
252
+ end
253
+ end
254
+ end