webull-openapi-python-sdk 1.0.4__py3-none-any.whl → 1.0.6__py3-none-any.whl

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.
Files changed (48) hide show
  1. samples/__init__.py +1 -1
  2. samples/data/data_client.py +43 -0
  3. samples/trade/trade_client_v3.py +420 -0
  4. samples/trade/trade_event_client.py +3 -1
  5. webull/__init__.py +1 -1
  6. webull/core/__init__.py +1 -1
  7. webull/core/data/endpoints.json +1 -1
  8. webull/data/__init__.py +1 -1
  9. webull/data/common/category.py +3 -2
  10. webull/data/common/contract_type.py +20 -0
  11. webull/data/data_client.py +4 -0
  12. webull/data/quotes/crypto_market_data.py +58 -0
  13. webull/data/quotes/futures_market_data.py +89 -0
  14. webull/data/quotes/instrument.py +79 -2
  15. webull/data/quotes/market_data.py +0 -2
  16. webull/data/request/get_crypto_historical_bars_request.py +40 -0
  17. webull/data/request/get_crypto_instruments_request.py +44 -0
  18. webull/data/request/get_crypto_snapshot_request.py +31 -0
  19. webull/data/request/get_futures_depth_request.py +32 -0
  20. webull/data/request/get_futures_historical_bars_request.py +36 -0
  21. webull/data/request/get_futures_instruments_by_code_request.py +36 -0
  22. webull/data/request/get_futures_instruments_request.py +31 -0
  23. webull/data/request/get_futures_products_request.py +25 -0
  24. webull/data/request/get_futures_snapshot_request.py +31 -0
  25. webull/data/request/get_futures_tick_request.py +31 -0
  26. webull/data/request/get_instruments_request.py +13 -1
  27. webull/trade/__init__.py +1 -2
  28. webull/trade/common/category.py +2 -3
  29. webull/trade/request/v2/palce_order_request.py +5 -3
  30. webull/trade/request/v2/place_option_request.py +7 -7
  31. webull/trade/request/v2/place_order_request.py +4 -6
  32. webull/trade/request/v3/__init__.py +0 -0
  33. webull/trade/request/v3/cancel_order_request.py +28 -0
  34. webull/trade/request/v3/get_order_detail_request.py +26 -0
  35. webull/trade/request/v3/get_order_history_request.py +35 -0
  36. webull/trade/request/v3/get_order_open_request.py +29 -0
  37. webull/trade/request/v3/place_order_request.py +56 -0
  38. webull/trade/request/v3/preview_order_request.py +31 -0
  39. webull/trade/request/v3/replace_order_request.py +31 -0
  40. webull/trade/trade/v3/__init__.py +0 -0
  41. webull/trade/trade/v3/order_opration_v3.py +134 -0
  42. webull/trade/trade_client.py +2 -0
  43. {webull_openapi_python_sdk-1.0.4.dist-info → webull_openapi_python_sdk-1.0.6.dist-info}/METADATA +1 -1
  44. {webull_openapi_python_sdk-1.0.4.dist-info → webull_openapi_python_sdk-1.0.6.dist-info}/RECORD +48 -24
  45. {webull_openapi_python_sdk-1.0.4.dist-info → webull_openapi_python_sdk-1.0.6.dist-info}/WHEEL +0 -0
  46. {webull_openapi_python_sdk-1.0.4.dist-info → webull_openapi_python_sdk-1.0.6.dist-info}/licenses/LICENSE +0 -0
  47. {webull_openapi_python_sdk-1.0.4.dist-info → webull_openapi_python_sdk-1.0.6.dist-info}/licenses/NOTICE +0 -0
  48. {webull_openapi_python_sdk-1.0.4.dist-info → webull_openapi_python_sdk-1.0.6.dist-info}/top_level.txt +0 -0
samples/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.0.4"
1
+ __version__ = '1.0.6'
@@ -15,6 +15,7 @@
15
15
  # coding=utf-8
16
16
 
17
17
  from webull.data.common.category import Category
18
+ from webull.data.common.contract_type import ContractType
18
19
  from webull.data.common.timespan import Timespan
19
20
  from webull.core.client import ApiClient
20
21
  from webull.data.data_client import DataClient
@@ -34,6 +35,22 @@ if __name__ == '__main__':
34
35
  if res.status_code == 200:
35
36
  print('get_instrument:', res.json())
36
37
 
38
+ res = data_client.instrument.get_crypto_instrument()
39
+ if res.status_code == 200:
40
+ print('get_crypto_instrument(all):', res.json())
41
+
42
+ res = data_client.instrument.get_crypto_instrument("BTCUSD")
43
+ if res.status_code == 200:
44
+ print('get_crypto_instrument:', res.json())
45
+
46
+ res = data_client.crypto_market_data.get_crypto_snapshot("BTCUSD")
47
+ if res.status_code == 200:
48
+ print('get_crypto_snapshot:', res.json())
49
+
50
+ res = data_client.crypto_market_data.get_crypto_history_bar("BTCUSD", Category.US_CRYPTO.name, Timespan.M1.name)
51
+ if res.status_code == 200:
52
+ print('get_crypto_history_bar:', res.json())
53
+
37
54
  res = data_client.market_data.get_snapshot('AAPL', Category.US_STOCK.name, extend_hour_required=True, overnight_required=True)
38
55
  if res.status_code == 200:
39
56
  print('get_snapshot:', res.json())
@@ -54,4 +71,30 @@ if __name__ == '__main__':
54
71
  if res.status_code == 200:
55
72
  print('get_quotes:', res.json())
56
73
 
74
+ res = data_client.futures_market_data.get_futures_depth("SILZ5", Category.US_FUTURES.name, depth=1)
75
+ if res.status_code == 200:
76
+ print('get_futures_depth:', res.json())
77
+
78
+ res = data_client.futures_market_data.get_futures_history_bars('SILZ5,6BM6', Category.US_FUTURES.name, Timespan.M1.name)
79
+ if res.status_code == 200:
80
+ print('get_futures_history_bars:', res.json())
81
+
82
+ res = data_client.futures_market_data.get_futures_tick("SILZ5", Category.US_FUTURES.name, count=10)
83
+ if res.status_code == 200:
84
+ print('get_futures_tick:', res.json())
85
+
86
+ res = data_client.futures_market_data.get_futures_snapshot("SILZ5,6BM6", Category.US_FUTURES.name)
87
+ if res.status_code == 200:
88
+ print('get_futures_snapshot:', res.json())
57
89
 
90
+ res = data_client.instrument.get_futures_products(Category.US_FUTURES.name)
91
+ if res.status_code == 200:
92
+ print('get_futures_products:', res.json())
93
+
94
+ res = data_client.instrument.get_futures_instrument("ESZ5", Category.US_FUTURES.name)
95
+ if res.status_code == 200:
96
+ print('get_futures_instrument:', res.json())
97
+
98
+ res = data_client.instrument.get_futures_instrument_by_code("ES", Category.US_FUTURES.name, ContractType.MONTHLY.name)
99
+ if res.status_code == 200:
100
+ print('get_futures_instrument_by_code:', res.json())
@@ -0,0 +1,420 @@
1
+ # Copyright 2022 Webull
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import json
16
+ import uuid
17
+ from time import sleep
18
+
19
+ from webull.core.client import ApiClient
20
+ from webull.trade.trade_client import TradeClient
21
+
22
+ optional_api_endpoint = "<api_endpoint>"
23
+ your_app_key = "<your_app_key>"
24
+ your_app_secret = "<your_app_secret>"
25
+ region_id = "<region_id>"
26
+ account_id = "<your_account_id>"
27
+ api_client = ApiClient(your_app_key, your_app_secret, region_id)
28
+ api_client.add_endpoint(region_id, optional_api_endpoint)
29
+
30
+
31
+ if __name__ == '__main__':
32
+ trade_client = TradeClient(api_client)
33
+
34
+ res = trade_client.account_v2.get_account_list()
35
+ if res.status_code == 200:
36
+ print('get account list:', res.json())
37
+
38
+ res = trade_client.account_v2.get_account_balance(account_id)
39
+ if res.status_code == 200:
40
+ print('get account balance res:', res.json())
41
+
42
+ res = trade_client.account_v2.get_account_position(account_id)
43
+ if res.status_code == 200:
44
+ print('get account position res:', res.json())
45
+
46
+ # ============================================================
47
+ # Equity Order Example
48
+ # ============================================================
49
+
50
+ # normal equity order
51
+ normal_equity_client_order_id = uuid.uuid4().hex
52
+ print('client order id:', normal_equity_client_order_id)
53
+ new_normal_equity_orders = [
54
+ {
55
+ "combo_type": "NORMAL",
56
+ "client_order_id": normal_equity_client_order_id,
57
+ "symbol": "AAPL",
58
+ "instrument_type": "EQUITY",
59
+ "market": "US",
60
+ "order_type": "LIMIT",
61
+ "limit_price": "188",
62
+ "quantity": "1",
63
+ "support_trading_session": "N",
64
+ "side": "BUY",
65
+ "time_in_force": "DAY",
66
+ "entrust_type": "QTY"
67
+ }
68
+ ]
69
+
70
+ res = trade_client.order_v3.preview_order(account_id, new_normal_equity_orders)
71
+ if res.status_code == 200:
72
+ print('preview normal equity order res:', res.json())
73
+
74
+ res = trade_client.order_v3.place_order(account_id, new_normal_equity_orders)
75
+ if res.status_code == 200:
76
+ print('place normal equity order res:', res.json())
77
+ sleep(3)
78
+
79
+ replace_normal_equity_orders = [
80
+ {
81
+ "client_order_id": normal_equity_client_order_id,
82
+ "quantity": "100",
83
+ "limit_price": "200"
84
+ }
85
+ ]
86
+ res = trade_client.order_v3.replace_order(account_id, replace_normal_equity_orders)
87
+ if res.status_code == 200:
88
+ print('replace normal equity order res:', res.json())
89
+ sleep(3)
90
+
91
+ res = trade_client.order_v3.cancel_order(account_id, normal_equity_client_order_id)
92
+ if res.status_code == 200:
93
+ print('cancel normal equity order res:', res.json())
94
+
95
+ res = trade_client.order_v3.get_order_open(account_id=account_id)
96
+ if res.status_code == 200:
97
+ print("order_open_res=" + json.dumps(res.json(), indent=4))
98
+
99
+ res = trade_client.order_v3.get_order_history(account_id)
100
+ if res.status_code == 200:
101
+ print('get order history res:', res.json())
102
+
103
+ res = trade_client.order_v3.get_order_detail(account_id, normal_equity_client_order_id)
104
+ if res.status_code == 200:
105
+ print('get order detail res:', res.json())
106
+
107
+
108
+
109
+ # combo equity order
110
+ master_equity_client_order_id = uuid.uuid4().hex
111
+ stop_profit_equity_client_order_id = uuid.uuid4().hex
112
+ stop_loss_equity_client_order_id = uuid.uuid4().hex
113
+ print('normal_equity_master_client_order_id:', master_equity_client_order_id)
114
+ print('stop_profit_equity_client_order_id:', stop_profit_equity_client_order_id)
115
+ print('stop_loss_equity_client_order_id:', stop_loss_equity_client_order_id)
116
+ new_combo_orders = [
117
+ {
118
+ "client_order_id": master_equity_client_order_id,
119
+ "combo_type": "MASTER",
120
+ "symbol": "F",
121
+ "instrument_type": "EQUITY",
122
+ "market": "US",
123
+ "order_type": "LIMIT",
124
+ "quantity": "1",
125
+ "support_trading_session": "N",
126
+ "limit_price": "10.5",
127
+ "side": "BUY",
128
+ "entrust_type": "QTY",
129
+ "time_in_force": "DAY"
130
+ },
131
+ {
132
+ "client_order_id": stop_profit_equity_client_order_id,
133
+ "combo_type": "STOP_PROFIT",
134
+ "symbol": "F",
135
+ "instrument_type": "EQUITY",
136
+ "market": "US",
137
+ "order_type": "LIMIT",
138
+ "quantity": "1",
139
+ "support_trading_session": "N",
140
+ "limit_price": "11.5",
141
+ "side": "SELL",
142
+ "entrust_type": "QTY",
143
+ "time_in_force": "DAY"
144
+ },
145
+ {
146
+ "client_order_id": stop_loss_equity_client_order_id,
147
+ "combo_type": "STOP_LOSS",
148
+ "symbol": "F",
149
+ "instrument_type": "EQUITY",
150
+ "market": "US",
151
+ "order_type": "STOP_LOSS",
152
+ "quantity": "1",
153
+ "support_trading_session": "N",
154
+ "stop_price": "10",
155
+ "side": "SELL",
156
+ "entrust_type": "QTY",
157
+ "time_in_force": "DAY"
158
+ }
159
+ ]
160
+
161
+ res = trade_client.order_v3.preview_order(account_id, new_combo_orders)
162
+ if res.status_code == 200:
163
+ print('preview combo equity order res:', res.json())
164
+
165
+ res = trade_client.order_v3.place_order(account_id, new_combo_orders)
166
+ if res.status_code == 200:
167
+ print('place combo equity order res:', res.json())
168
+ sleep(3)
169
+
170
+ replace_combo_orders = [
171
+ {
172
+ "client_order_id": master_equity_client_order_id,
173
+ "quantity": "2"
174
+ },
175
+ {
176
+ "client_order_id": stop_profit_equity_client_order_id,
177
+ "quantity": "2"
178
+ },
179
+ {
180
+ "client_order_id": stop_loss_equity_client_order_id,
181
+ "quantity": "2"
182
+ }
183
+ ]
184
+ res = trade_client.order_v3.replace_order(account_id, replace_combo_orders)
185
+ if res.status_code == 200:
186
+ print('replace combo equity order res:', res.json())
187
+ sleep(3)
188
+
189
+ res = trade_client.order_v3.cancel_order(account_id, master_equity_client_order_id)
190
+ if res.status_code == 200:
191
+ print('cancel master equity order res:', res.json())
192
+
193
+ res = trade_client.order_v3.get_order_history(account_id)
194
+ if res.status_code == 200:
195
+ print('get order history res:', res.json())
196
+
197
+ res = trade_client.order_v3.get_order_open(account_id=account_id)
198
+ if res.status_code == 200:
199
+ print("order_open_res=" + json.dumps(res.json(), indent=4))
200
+
201
+ res = trade_client.order_v3.get_order_detail(account_id, master_equity_client_order_id)
202
+ if res.status_code == 200:
203
+ print('get master order detail res:', res.json())
204
+
205
+
206
+
207
+
208
+ # ============================================================
209
+ # Option Order Example
210
+ # ============================================================
211
+
212
+ # normal option order
213
+ normal_option_client_order_id = uuid.uuid4().hex
214
+ new_normal_option_orders = [
215
+ {
216
+ "client_order_id": normal_option_client_order_id,
217
+ "combo_type": "NORMAL",
218
+ "order_type": "LIMIT",
219
+ "quantity": "1",
220
+ "limit_price": "21.25",
221
+ "option_strategy": "SINGLE",
222
+ "side": "BUY",
223
+ "time_in_force": "GTC",
224
+ "entrust_type": "QTY",
225
+ "legs": [
226
+ {
227
+ "side": "BUY",
228
+ "quantity": "1",
229
+ "symbol": "TSLA",
230
+ "strike_price": "400",
231
+ "option_expire_date": "2025-12-26",
232
+ "instrument_type": "OPTION",
233
+ "option_type": "CALL",
234
+ "market": "US"
235
+ }
236
+ ]
237
+ }
238
+ ]
239
+
240
+ # preview
241
+ res = trade_client.order_v3.preview_order(account_id, new_normal_option_orders)
242
+ if res.status_code == 200:
243
+ print("preview normal option order res:" + json.dumps(res.json(), indent=4))
244
+
245
+ # place
246
+ res = trade_client.order_v3.place_order(account_id, new_normal_option_orders)
247
+ if res.status_code == 200:
248
+ print("place normal option order res:" + json.dumps(res.json(), indent=4))
249
+ sleep(3)
250
+
251
+ # replace for Webull HK
252
+ # replace_normal_option_orders = [
253
+ # {
254
+ # "client_order_id": normal_option_client_order_id,
255
+ # "quantity": "2",
256
+ # "limit_price": "11.3"
257
+ # }
258
+ # ]
259
+ # res = trade_client.order_v3.replace_option(account_id, replace_normal_option_orders)
260
+ # if res.status_code == 200:
261
+ # print("replace normal option order res:" + json.dumps(res.json(), indent=4))
262
+ # sleep(5)
263
+
264
+ # replace for Webull US
265
+ res = trade_client.order_v3.get_order_detail(account_id, normal_option_client_order_id)
266
+ if res.status_code == 200:
267
+ print('get normal option order detail res:', res.json())
268
+ data = res.json() or {}
269
+ leg_id = (
270
+ data.get("orders", [{}])[0]
271
+ .get("legs", [{}])[0]
272
+ .get("id")
273
+ )
274
+ print('get normal option order detail id :', leg_id)
275
+
276
+ # If it is a multi-leg option, you need to manually match it to the corresponding sub-leg orderId.
277
+ if leg_id:
278
+ replace_normal_option_orders = [
279
+ {
280
+ "client_order_id": normal_option_client_order_id,
281
+ "quantity": "2",
282
+ "limit_price": "21.3",
283
+ "legs": [
284
+ {
285
+ "id": leg_id,
286
+ "quantity": "2"
287
+ }
288
+ ]
289
+ }
290
+ ]
291
+ res = trade_client.order_v3.replace_order(account_id, replace_normal_option_orders)
292
+ if res.status_code == 200:
293
+ print("replace normal option order res:" + json.dumps(res.json(), indent=4))
294
+ sleep(3)
295
+
296
+ # cancel
297
+ res = trade_client.order_v3.cancel_order(account_id, normal_option_client_order_id)
298
+ if res.status_code == 200:
299
+ print("cancel normal option order res:" + json.dumps(res.json(), indent=4))
300
+
301
+ res = trade_client.order_v3.get_order_history(account_id)
302
+ if res.status_code == 200:
303
+ print('get order history res:', res.json())
304
+
305
+ res = trade_client.order_v3.get_order_open(account_id=account_id)
306
+ if res.status_code == 200:
307
+ print("order_open_res=" + json.dumps(res.json(), indent=4))
308
+
309
+ res = trade_client.order_v3.get_order_detail(account_id, normal_option_client_order_id)
310
+ if res.status_code == 200:
311
+ print('get option order detail res:', res.json())
312
+
313
+
314
+
315
+ # ============================================================
316
+ # Crypto Order Example
317
+ # For the cryptocurrency example, please use a cryptocurrency account ID.
318
+ # ============================================================
319
+
320
+ # normal crypto order
321
+ normal_crypto_client_order_id = uuid.uuid4().hex
322
+ print('client order id:', normal_crypto_client_order_id)
323
+ new_normal_crypto_orders = [
324
+ {
325
+ "combo_type": "NORMAL",
326
+ "client_order_id": normal_crypto_client_order_id,
327
+ "symbol": "BTCUSD",
328
+ "instrument_type": "CRYPTO",
329
+ "market": "US",
330
+ "order_type": "LIMIT",
331
+ "limit_price": "80000",
332
+ "quantity": "0.003",
333
+ "side": "BUY",
334
+ "time_in_force": "DAY",
335
+ "entrust_type": "QTY"
336
+ }
337
+ ]
338
+
339
+ res = trade_client.order_v3.place_order(account_id, new_normal_crypto_orders)
340
+ if res.status_code == 200:
341
+ print('place normal crypto order res:', res.json())
342
+ sleep(3)
343
+
344
+ res = trade_client.order_v3.cancel_order(account_id, normal_crypto_client_order_id)
345
+ if res.status_code == 200:
346
+ print('cancel normal crypto order res:', res.json())
347
+
348
+ res = trade_client.order_v3.get_order_open(account_id=account_id)
349
+ if res.status_code == 200:
350
+ print("order_open_res=" + json.dumps(res.json(), indent=4))
351
+
352
+ res = trade_client.order_v3.get_order_history(account_id)
353
+ if res.status_code == 200:
354
+ print('get order history res:', res.json())
355
+
356
+ res = trade_client.order_v3.get_order_detail(account_id, normal_crypto_client_order_id)
357
+ if res.status_code == 200:
358
+ print('get order detail res:', res.json())
359
+
360
+
361
+
362
+ # ============================================================
363
+ # Futures Order Example
364
+ # ============================================================
365
+
366
+ # normal futures order
367
+ normal_futures_client_order_id = uuid.uuid4().hex
368
+ print('futures client order id:', normal_futures_client_order_id)
369
+ new_normal_futures_orders = [
370
+ {
371
+ "combo_type": "NORMAL",
372
+ "client_order_id": normal_futures_client_order_id,
373
+ "symbol": "ESZ5",
374
+ "instrument_type": "FUTURES",
375
+ "market": "US",
376
+ "order_type": "LIMIT",
377
+ "limit_price": "4500",
378
+ "quantity": "1",
379
+ "side": "BUY",
380
+ "time_in_force": "DAY",
381
+ "entrust_type": "QTY"
382
+ }
383
+ ]
384
+ res = trade_client.order_v3.place_order(account_id, new_normal_futures_orders)
385
+ if res.status_code == 200:
386
+ print('place normal futures order res:', res.json())
387
+ sleep(3)
388
+
389
+ # normal futures order replace
390
+ replace_normal_futures_orders = [
391
+ {
392
+ "client_order_id": normal_futures_client_order_id,
393
+ "quantity": "2",
394
+ "limit_price": "4550"
395
+ }
396
+ ]
397
+ res = trade_client.order_v3.replace_order(account_id, replace_normal_futures_orders)
398
+ if res.status_code == 200:
399
+ print('replace normal futures order res:', res.json())
400
+ sleep(3)
401
+
402
+ # normal futures order cancel
403
+ res = trade_client.order_v3.cancel_order(account_id, normal_futures_client_order_id)
404
+ if res.status_code == 200:
405
+ print('cancel normal futures order res:', res.json())
406
+
407
+ # get futures order detail
408
+ res = trade_client.order_v3.get_order_detail(account_id, normal_futures_client_order_id)
409
+ if res.status_code == 200:
410
+ print('get futures order detail res:', res.json())
411
+
412
+ # get futures open orders
413
+ res = trade_client.order_v3.get_order_open(account_id, page_size=10)
414
+ if res.status_code == 200:
415
+ print("order_open_res=" + json.dumps(res.json(), indent=4))
416
+
417
+ # get futures order history
418
+ res = trade_client.order_v3.get_order_history(account_id, page_size=10)
419
+ if res.status_code == 200:
420
+ print('get order history res:', res.json())
@@ -37,7 +37,9 @@ if __name__ == '__main__':
37
37
 
38
38
  # Create EventsClient instance
39
39
  trade_events_client = TradeEventsClient(your_app_key, your_app_secret, region_id)
40
- # For non production environment, you need to set the domain name of the subscription service through eventsclient. For example, the domain name of the UAT environment is set here
40
+ # [Important] For non production environment, you need to set the domain name of the subscription service through events client. For example, the domain name of the UAT environment is set here
41
+ # [Important] For non production environment, you need to set the domain name of the subscription service through events client. For example, the domain name of the UAT environment is set here
42
+ # [Important] For non production environment, you need to set the domain name of the subscription service through events client. For example, the domain name of the UAT environment is set here
41
43
  # trade_events_client = TradeEventsClient(your_app_key, your_app_secret, region_id, host=optional_api_endpoint)
42
44
  trade_events_client.on_log = _on_log
43
45
 
webull/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.0.4"
1
+ __version__ = '1.0.6'
webull/core/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "1.0.4"
1
+ __version__ = '1.0.6'
2
2
 
3
3
  import logging
4
4
 
@@ -4,7 +4,7 @@
4
4
  "region_mapping": {
5
5
  "us": {
6
6
  "api": "api.webull.com",
7
- "quotes-api": "usquotes-api.webullfintech.com",
7
+ "quotes-api": "data-api.webull.com",
8
8
  "events-api": "events-api.webull.com"
9
9
  },
10
10
  "hk": {
webull/data/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  # coding=utf-8
2
2
 
3
- __version__ = '1.0.4'
3
+ __version__ = '1.0.6'
@@ -20,7 +20,8 @@ class Category(EasyEnum):
20
20
  US_STOCK = (1, 'US STOCK')
21
21
  US_OPTION = (2, 'US OPTION')
22
22
  HK_STOCK = (3, 'HK STOCK')
23
- CRYPTO = (4, 'CRYPTO')
24
23
  US_ETF = (5, 'US ETF')
25
24
  HK_ETF = (6, 'HK ETF')
26
- CN_STOCK = (7, "CN STOCK")
25
+ CN_STOCK = (7, "CN STOCK")
26
+ US_CRYPTO = (8, "US CRYPTO")
27
+ US_FUTURES = (12, "US FUTURES")
@@ -0,0 +1,20 @@
1
+ # Copyright 2022 Webull
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # coding=utf-8
16
+
17
+ from webull.core.common.easy_enum import EasyEnum
18
+ class ContractType(EasyEnum):
19
+ MONTHLY = (1, "MONTHLY")
20
+ MAIN = (2, "MAIN")
@@ -18,6 +18,8 @@ import logging
18
18
  import sys
19
19
 
20
20
  from webull.core.http.initializer.client_initializer import ClientInitializer
21
+ from webull.data.quotes.crypto_market_data import CryptoMarketData
22
+ from webull.data.quotes.futures_market_data import FuturesMarketData
21
23
  from webull.data.quotes.instrument import Instrument
22
24
  from webull.data.quotes.market_data import MarketData
23
25
 
@@ -28,6 +30,8 @@ class DataClient:
28
30
  ClientInitializer.initializer(api_client)
29
31
  self.instrument = Instrument(api_client)
30
32
  self.market_data = MarketData(api_client)
33
+ self.crypto_market_data = CryptoMarketData(api_client)
34
+ self.futures_market_data = FuturesMarketData(api_client)
31
35
 
32
36
  def _init_logger(self, api_client):
33
37
  # No logger configured, using default console and local file logging.
@@ -0,0 +1,58 @@
1
+ # Copyright 2022 Webull
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ from webull.data.common.category import Category
15
+ from webull.data.request.get_crypto_historical_bars_request import GetCryptoHistoricalBarsRequest
16
+ from webull.data.request.get_crypto_snapshot_request import GetCryptoSnapshotRequest
17
+
18
+
19
+ class CryptoMarketData:
20
+ def __init__(self, api_client):
21
+ self.client = api_client
22
+
23
+ def get_crypto_history_bar(self, symbols, category, timespan, count='200', real_time_required=None):
24
+ """
25
+ Returns to Instrument in the window aggregated data.
26
+ According to the last N K-lines of the stock code, it supports various granularity K-lines such as m1 and m5.
27
+ Currently, only the K-line with the previous weight is provided for the daily K-line and above,
28
+ and only the un-weighted K-line is provided for the minute K.
29
+
30
+ :param symbols: List of security codes (e.g., single: 00700; multiple: BTCUSD,ETHUSD or ['BTCUSD','ETHUSD']).
31
+ :param category: Security type. Fixed value: "US_CRYPTO"
32
+ :param timespan: K-line time granularity
33
+ :param count: The number of lines: the default is 200, and the maximum limit is 1200
34
+ :param real_time_required: Returns the latest trade quote data. By default, the most recent market data is returned.
35
+ By default, only intraday candlestick data is returned.
36
+ """
37
+ crypto_history_bar_request = GetCryptoHistoricalBarsRequest()
38
+ crypto_history_bar_request.set_symbols(symbols)
39
+ crypto_history_bar_request.set_category(category)
40
+ crypto_history_bar_request.set_timespan(timespan)
41
+ crypto_history_bar_request.set_count(count)
42
+ crypto_history_bar_request.set_real_time_required(real_time_required)
43
+ response = self.client.get_response(crypto_history_bar_request)
44
+ return response
45
+
46
+ def get_crypto_snapshot(self, symbols, category=Category.US_CRYPTO.name):
47
+ """
48
+ Query the latest crypto market snapshots in batches according to the security code list.
49
+
50
+ :param symbols: List of security codes (e.g., single: 00700; multiple: BTCUSD,ETHUSD or ['BTCUSD','ETHUSD']).
51
+ Up to 20 symbols can be subscribed per request.
52
+ :param category: Security type. Fixed value: "US_CRYPTO".
53
+ """
54
+ crypto_snapshot_request = GetCryptoSnapshotRequest()
55
+ crypto_snapshot_request.set_symbols(symbols)
56
+ crypto_snapshot_request.set_category(category)
57
+ response = self.client.get_response(crypto_snapshot_request)
58
+ return response