webull-openapi-python-sdk 1.0.1__py3-none-any.whl → 1.0.3__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 (51) hide show
  1. samples/__init__.py +1 -1
  2. samples/trade/trade_client_v2.py +223 -102
  3. samples/trade/trade_event_client.py +13 -11
  4. webull/__init__.py +1 -1
  5. webull/core/__init__.py +1 -1
  6. webull/core/data/endpoints.json +1 -1
  7. webull/core/http/initializer/client_initializer.py +43 -7
  8. webull/core/http/initializer/config/__init__.py +0 -0
  9. webull/core/http/initializer/config/bean/__init__.py +0 -0
  10. webull/core/http/initializer/config/bean/query_config_request.py +41 -0
  11. webull/core/http/initializer/config/config_operation.py +49 -0
  12. webull/core/http/initializer/token/bean/check_token_request.py +1 -1
  13. webull/core/http/initializer/token/bean/create_token_request.py +1 -1
  14. webull/core/http/initializer/token/bean/refresh_token_request.py +1 -1
  15. webull/core/http/initializer/token/token_operation.py +0 -2
  16. webull/data/__init__.py +1 -1
  17. webull/data/data_client.py +3 -0
  18. webull/data/request/get_batch_historical_bars_request.py +1 -1
  19. webull/data/request/get_historical_bars_request.py +1 -1
  20. webull/data/request/get_instruments_request.py +1 -1
  21. webull/data/request/get_quotes_request.py +1 -1
  22. webull/data/request/get_snapshot_request.py +1 -1
  23. webull/data/request/get_tick_request.py +1 -1
  24. webull/trade/__init__.py +1 -1
  25. webull/trade/request/palce_order_request.py +3 -2
  26. webull/trade/request/place_order_request.py +92 -0
  27. webull/trade/request/v2/cancel_option_request.py +2 -2
  28. webull/trade/request/v2/cancel_order_request.py +2 -2
  29. webull/trade/request/v2/get_account_balance_request.py +1 -1
  30. webull/trade/request/v2/get_account_list.py +3 -0
  31. webull/trade/request/v2/get_account_list_request.py +23 -0
  32. webull/trade/request/v2/get_account_positions_request.py +1 -1
  33. webull/trade/request/v2/get_order_detail_request.py +1 -1
  34. webull/trade/request/v2/get_order_history_request.py +5 -2
  35. webull/trade/request/v2/get_order_open_request.py +32 -0
  36. webull/trade/request/v2/palce_order_request.py +11 -54
  37. webull/trade/request/v2/place_option_request.py +7 -22
  38. webull/trade/request/v2/place_order_request.py +44 -0
  39. webull/trade/request/v2/preview_option_request.py +6 -2
  40. webull/trade/request/v2/preview_order_request.py +7 -37
  41. webull/trade/request/v2/replace_option_request.py +6 -2
  42. webull/trade/request/v2/replace_order_request.py +7 -35
  43. webull/trade/trade/order_operation.py +5 -2
  44. webull/trade/trade/v2/account_info_v2.py +8 -11
  45. webull/trade/trade/v2/order_operation_v2.py +114 -67
  46. {webull_openapi_python_sdk-1.0.1.dist-info → webull_openapi_python_sdk-1.0.3.dist-info}/METADATA +1 -1
  47. {webull_openapi_python_sdk-1.0.1.dist-info → webull_openapi_python_sdk-1.0.3.dist-info}/RECORD +51 -43
  48. {webull_openapi_python_sdk-1.0.1.dist-info → webull_openapi_python_sdk-1.0.3.dist-info}/WHEEL +0 -0
  49. {webull_openapi_python_sdk-1.0.1.dist-info → webull_openapi_python_sdk-1.0.3.dist-info}/licenses/LICENSE +0 -0
  50. {webull_openapi_python_sdk-1.0.1.dist-info → webull_openapi_python_sdk-1.0.3.dist-info}/licenses/NOTICE +0 -0
  51. {webull_openapi_python_sdk-1.0.1.dist-info → webull_openapi_python_sdk-1.0.3.dist-info}/top_level.txt +0 -0
webull/data/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  # coding=utf-8
2
2
 
3
- __version__ = '1.0.1'
3
+ __version__ = '1.0.3'
@@ -11,6 +11,9 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+
15
+ # coding=utf-8
16
+
14
17
  import logging
15
18
  import sys
16
19
 
@@ -17,7 +17,7 @@ from webull.core.request import ApiRequest
17
17
 
18
18
  class BatchHistoricalBarsRequest(ApiRequest):
19
19
  def __init__(self):
20
- ApiRequest.__init__(self, "/market-data/batch-bars", version='v2', method="POST", body_params={})
20
+ ApiRequest.__init__(self, "/openapi/market-data/stock/batch-bars", version='v2', method="POST", body_params={})
21
21
 
22
22
  def set_symbols(self, symbol):
23
23
  self.add_body_params("symbols", symbol)
@@ -17,7 +17,7 @@ from webull.core.request import ApiRequest
17
17
 
18
18
  class GetHistoricalBarsRequest(ApiRequest):
19
19
  def __init__(self):
20
- ApiRequest.__init__(self, "/market-data/bars", version='v2', method="GET", query_params={})
20
+ ApiRequest.__init__(self, "/openapi/market-data/stock/bars", version='v2', method="GET", query_params={})
21
21
 
22
22
  def set_symbol(self, symbol):
23
23
  self.add_query_param("symbol", symbol)
@@ -18,7 +18,7 @@ from webull.core.request import ApiRequest
18
18
 
19
19
  class GetInstrumentsRequest(ApiRequest):
20
20
  def __init__(self):
21
- ApiRequest.__init__(self, "/instrument/list", version='v2', method="GET", query_params={})
21
+ ApiRequest.__init__(self, "/openapi/instrument/stock/list", version='v2', method="GET", query_params={})
22
22
 
23
23
  def set_symbols(self, symbols):
24
24
  if isinstance(symbols, str):
@@ -18,7 +18,7 @@ from webull.core.request import ApiRequest
18
18
 
19
19
  class GetQuotesRequest(ApiRequest):
20
20
  def __init__(self):
21
- ApiRequest.__init__(self, "/market-data/quotes", version='v2', method="GET", query_params={})
21
+ ApiRequest.__init__(self, "/openapi/market-data/stock/quotes", version='v2', method="GET", query_params={})
22
22
 
23
23
  def set_symbol(self, symbol):
24
24
  self.add_query_param("symbol", symbol)
@@ -18,7 +18,7 @@ from webull.core.request import ApiRequest
18
18
 
19
19
  class GetSnapshotRequest(ApiRequest):
20
20
  def __init__(self):
21
- ApiRequest.__init__(self, "/market-data/snapshot", version='v2', method="GET", query_params={})
21
+ ApiRequest.__init__(self, "/openapi/market-data/stock/snapshot", version='v2', method="GET", query_params={})
22
22
 
23
23
  def set_symbols(self, symbols):
24
24
  if isinstance(symbols, str):
@@ -18,7 +18,7 @@ from webull.core.request import ApiRequest
18
18
 
19
19
  class GetTickRequest(ApiRequest):
20
20
  def __init__(self):
21
- ApiRequest.__init__(self, "/market-data/tick", version='v2', method="GET", query_params={})
21
+ ApiRequest.__init__(self, "/openapi/market-data/stock/tick", version='v2', method="GET", query_params={})
22
22
 
23
23
  def set_symbol(self, symbol):
24
24
  self.add_query_param("symbol", symbol)
webull/trade/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "1.0.1"
1
+ __version__ = "1.0.3"
2
2
 
@@ -13,13 +13,14 @@
13
13
  # limitations under the License.
14
14
 
15
15
  # coding=utf-8
16
- import inspect
17
- import json
18
16
 
19
17
  from webull.core.context.request_context_holder import RequestContextHolder
20
18
  from webull.core.request import ApiRequest
21
19
 
22
20
  class PlaceOrderRequest(ApiRequest):
21
+ """
22
+ Deprecated. Use :func:`place_order_request` instead.
23
+ """
23
24
  def __init__(self):
24
25
  ApiRequest.__init__(self, "/trade/order/place", version='v2', method="POST", body_params={})
25
26
  self._stock_order = {}
@@ -0,0 +1,92 @@
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
+ import inspect
17
+ import json
18
+
19
+ from webull.core.context.request_context_holder import RequestContextHolder
20
+ from webull.core.request import ApiRequest
21
+
22
+ class PlaceOrderRequest(ApiRequest):
23
+
24
+ def __init__(self):
25
+ ApiRequest.__init__(self, "/trade/order/place", version='v2', method="POST", body_params={})
26
+ self._stock_order = {}
27
+ self.add_body_params("stock_order", self._stock_order)
28
+
29
+ def add_stock_order_params(self, k, v):
30
+ self._stock_order[k] = v
31
+
32
+ def set_category(self, category):
33
+ self.add_body_params("category", category)
34
+
35
+ def set_account_id(self, account_id):
36
+ self.add_body_params("account_id", account_id)
37
+
38
+ def set_client_order_id(self, client_order_id):
39
+ self.add_stock_order_params("client_order_id", client_order_id)
40
+
41
+ def set_side(self, side):
42
+ self.add_stock_order_params("side", side)
43
+
44
+ def set_tif(self, tif):
45
+ self.add_stock_order_params("tif", tif)
46
+
47
+ def set_extended_hours_trading(self, extended_hours_trading):
48
+ self.add_stock_order_params("extended_hours_trading", extended_hours_trading)
49
+
50
+ def set_instrument_id(self, instrument_id):
51
+ self.add_stock_order_params("instrument_id", instrument_id)
52
+
53
+ def set_order_type(self, order_type):
54
+ self.add_stock_order_params("order_type", order_type)
55
+
56
+ def set_limit_price(self, limit_price):
57
+ self.add_stock_order_params("limit_price", limit_price)
58
+
59
+ def set_qty(self, quantity):
60
+ self.add_stock_order_params("qty", quantity)
61
+
62
+ def set_stop_price(self, stop_price):
63
+ self.add_stock_order_params("stop_price", stop_price)
64
+
65
+ def set_trailing_type(self, trailing_type):
66
+ self.add_stock_order_params("trailing_type", trailing_type)
67
+
68
+ def set_trailing_stop_step(self, trailing_stop_step):
69
+ self.add_stock_order_params("trailing_stop_step", trailing_stop_step)
70
+
71
+ def set_stock_order(self, client_order_id, instrument_id, qty, side, tif, extended_hours_trading,
72
+ order_type, limit_price, stop_price, trailing_type,trailing_stop_step):
73
+ self._stock_order.update({k: v for k, v in locals().items() if v is not None and k != 'self'})
74
+
75
+ def add_custom_headers_from_context(self):
76
+ try:
77
+ headers_map = RequestContextHolder.get()
78
+ if not headers_map:
79
+ return
80
+ for key, value in headers_map.items():
81
+ self.add_header(key, value)
82
+ finally:
83
+ RequestContextHolder.clear()
84
+
85
+ def add_custom_headers(self, headers_map):
86
+ if not headers_map:
87
+ return
88
+ for key, value in headers_map.items():
89
+ self.add_header(key, value)
90
+
91
+
92
+
@@ -19,10 +19,10 @@ from webull.core.request import ApiRequest
19
19
 
20
20
  class CancelOptionRequest(ApiRequest):
21
21
  def __init__(self):
22
- super().__init__("/openapi/account/orders/option/cancel", version='v2', method="POST", body_params={})
22
+ super().__init__("/openapi/trade/option/order/cancel", version='v2', method="POST", body_params={})
23
23
 
24
24
  def set_client_order_id(self, client_order_id):
25
25
  self.add_body_params("client_order_id", client_order_id)
26
26
 
27
27
  def set_account_id(self, account_id):
28
- self.add_query_param("account_id", account_id)
28
+ self.add_body_params("account_id", account_id)
@@ -18,10 +18,10 @@ from webull.core.request import ApiRequest
18
18
 
19
19
  class CancelOrderRequest(ApiRequest):
20
20
  def __init__(self):
21
- ApiRequest.__init__(self, "/openapi/account/orders/cancel", version='v2', method="POST", body_params={})
21
+ ApiRequest.__init__(self, "/openapi/trade/stock/order/cancel", version='v2', method="POST", body_params={})
22
22
 
23
23
  def set_account_id(self, account_id):
24
- self.add_query_param("account_id", account_id)
24
+ self.add_body_params("account_id", account_id)
25
25
 
26
26
  def set_client_order_id(self, client_order_id):
27
27
  self.add_body_params("client_order_id", client_order_id)
@@ -18,7 +18,7 @@ from webull.core.request import ApiRequest
18
18
 
19
19
  class AccountBalanceRequest(ApiRequest):
20
20
  def __init__(self):
21
- ApiRequest.__init__(self, "/openapi/account/balance", version='v2', method="GET", query_params={})
21
+ ApiRequest.__init__(self, "/openapi/assets/balance", version='v2', method="GET", query_params={})
22
22
 
23
23
  def set_account_id(self, account_id):
24
24
  self.add_query_param("account_id", account_id)
@@ -17,6 +17,9 @@ from webull.core.request import ApiRequest
17
17
 
18
18
 
19
19
  class GetAccountList(ApiRequest):
20
+ """
21
+ Deprecated. Use :func:`get_account_list_request` instead.
22
+ """
20
23
  def __init__(self):
21
24
  ApiRequest.__init__(self, "/openapi/account/list", version='v2', method="GET", query_params={})
22
25
 
@@ -0,0 +1,23 @@
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
+ from webull.core.request import ApiRequest
17
+
18
+
19
+ class GetAccountListRequest(ApiRequest):
20
+ def __init__(self):
21
+ ApiRequest.__init__(self, "/openapi/account/list", version='v2', method="GET", query_params={})
22
+
23
+
@@ -18,7 +18,7 @@ from webull.core.request import ApiRequest
18
18
 
19
19
  class AccountPositionsRequest(ApiRequest):
20
20
  def __init__(self):
21
- ApiRequest.__init__(self, "/openapi/account/positions", version='v2', method="GET", query_params={})
21
+ ApiRequest.__init__(self, "/openapi/assets/positions", version='v2', method="GET", query_params={})
22
22
 
23
23
  def set_account_id(self, account_id):
24
24
  self.add_query_param("account_id", account_id)
@@ -17,7 +17,7 @@ from webull.core.request import ApiRequest
17
17
 
18
18
  class OrderDetailRequest(ApiRequest):
19
19
  def __init__(self):
20
- ApiRequest.__init__(self, "/openapi/account/orders/detail", version='v2', method="GET", query_params={})
20
+ ApiRequest.__init__(self, "/openapi/trade/order/detail", version='v2', method="GET", query_params={})
21
21
 
22
22
  def set_account_id(self, account_id):
23
23
  self.add_query_param("account_id", account_id)
@@ -17,7 +17,7 @@ from webull.core.request import ApiRequest
17
17
 
18
18
  class OrderHistoryRequest(ApiRequest):
19
19
  def __init__(self):
20
- ApiRequest.__init__(self, "/openapi/account/orders/history", version='v2', method="GET", query_params={})
20
+ ApiRequest.__init__(self, "/openapi/trade/order/history", version='v2', method="GET", query_params={})
21
21
 
22
22
  def set_account_id(self, account_id):
23
23
  self.add_query_param("account_id", account_id)
@@ -32,4 +32,7 @@ class OrderHistoryRequest(ApiRequest):
32
32
  self.add_query_param("end_date", end_date)
33
33
 
34
34
  def set_last_client_order_id(self, last_client_order_id):
35
- self.add_query_param("last_client_order_id", last_client_order_id)
35
+ self.add_query_param("last_client_order_id", last_client_order_id)
36
+
37
+ def set_last_order_id(self, last_order_id):
38
+ self.add_query_param("last_order_id", last_order_id)
@@ -0,0 +1,32 @@
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
+ from webull.core.request import ApiRequest
16
+
17
+
18
+ class OrderOpenRequest(ApiRequest):
19
+ def __init__(self):
20
+ ApiRequest.__init__(self, "/openapi/trade/order/open", version='v2', method="GET", query_params={})
21
+
22
+ def set_account_id(self, account_id):
23
+ self.add_query_param("account_id", account_id)
24
+
25
+ def set_page_size(self, page_size):
26
+ self.add_query_param("page_size", page_size)
27
+
28
+ def set_last_order_id(self, last_order_id):
29
+ self.add_query_param("last_order_id", last_order_id)
30
+
31
+ def set_last_client_order_id(self, last_client_order_id):
32
+ self.add_query_param("last_client_order_id", last_client_order_id)
@@ -11,54 +11,27 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- import json
15
14
  # coding=utf-8
16
- from typing import List
17
15
 
18
- from webull.core.context.request_context_holder import RequestContextHolder
19
16
  from webull.core.request import ApiRequest
20
17
 
21
18
 
22
- class CloseContract:
23
- def __init__(self, contract_id: str, quantity: str):
24
- self.contract_id = contract_id
25
- self.quantity = quantity
26
-
27
- def to_dict(self):
28
- return {
29
- "contract_id": self.contract_id,
30
- "quantity": self.quantity
31
- }
32
-
33
19
  class PlaceOrderRequest(ApiRequest):
20
+ """
21
+ Deprecated. Use :func:`place_order_request` instead.
22
+ """
34
23
  def __init__(self):
35
- super().__init__("/openapi/account/orders/place", version='v2', method="POST", body_params={})
36
- self._new_orders = []
37
- self._current_order = {}
38
- self.add_body_params("new_orders", self._new_orders)
24
+ super().__init__("/openapi/trade/stock/order/place", version='v2', method="POST", body_params={})
39
25
 
40
- def add_new_order_params(self, key, value):
41
- self._current_order[key] = value
26
+ def set_new_orders(self, new_orders):
27
+ self.add_body_params("new_orders", new_orders)
42
28
 
43
29
  def set_account_id(self, account_id):
44
- self.add_query_param("account_id", account_id)
45
-
46
- def set_close_contracts(self, close_contracts: List[CloseContract]):
47
- if not isinstance(close_contracts, list):
48
- raise TypeError("close_contracts must be a list of CloseContract objects.")
49
- self.add_new_order_params("close_contracts", [contract.to_dict() for contract in close_contracts])
50
-
51
- def set_new_orders(self, current_order):
52
- self._current_order.update({k: v for k, v in current_order.items() if v is not None and k != 'self'})
53
- if 'close_contracts' in current_order and current_order['close_contracts'] is not None:
54
- self.set_close_contracts(current_order['close_contracts'])
30
+ self.add_body_params("account_id", account_id)
55
31
 
56
- def finalize_order(self):
57
- if self._current_order:
58
- self._new_orders.append(self._current_order)
59
- self._current_order = {}
60
- else:
61
- raise ValueError("No order fields have been set.")
32
+ def set_client_combo_order_id(self, client_combo_order_id):
33
+ if client_combo_order_id:
34
+ self.add_body_params("client_combo_order_id", client_combo_order_id)
62
35
 
63
36
  def add_custom_headers_from_order(self, new_orders):
64
37
  if not new_orders:
@@ -68,20 +41,4 @@ class PlaceOrderRequest(ApiRequest):
68
41
  market = new_orders.get("market")
69
42
  category = market + "_" + "STOCK"
70
43
  if category is not None:
71
- self.add_header("category", category)
72
-
73
- def add_custom_headers_from_context(self):
74
- try:
75
- headers_map = RequestContextHolder.get()
76
- if not headers_map:
77
- return
78
- for key, value in headers_map.items():
79
- self.add_header(key, value)
80
- finally:
81
- RequestContextHolder.clear()
82
-
83
- def add_custom_headers(self, headers_map):
84
- if not headers_map:
85
- return
86
- for key, value in headers_map.items():
87
- self.add_header(key, value)
44
+ self.add_header("category", category)
@@ -11,9 +11,7 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- import json
15
14
 
16
- from webull.core.context.request_context_holder import RequestContextHolder
17
15
  # coding=utf-8
18
16
 
19
17
  from webull.core.request import ApiRequest
@@ -21,16 +19,19 @@ from webull.core.request import ApiRequest
21
19
 
22
20
  class PlaceOptionRequest(ApiRequest):
23
21
  def __init__(self):
24
- super().__init__("/openapi/account/orders/option/place", version='v2', method="POST", body_params={})
22
+ super().__init__("/openapi/trade/option/order/place", version='v2', method="POST", body_params={})
25
23
 
26
24
  def set_new_orders(self, new_orders):
27
25
  self.add_body_params("new_orders", new_orders)
28
26
 
29
27
  def set_account_id(self, account_id):
30
- self.add_query_param("account_id", account_id)
28
+ self.add_body_params("account_id", account_id)
31
29
 
32
- def add_custom_headers_from_order(self, new_orders):
30
+ def set_client_combo_order_id(self, client_combo_order_id):
31
+ if client_combo_order_id:
32
+ self.add_body_params("client_combo_order_id", client_combo_order_id)
33
33
 
34
+ def add_custom_headers_from_order(self, new_orders):
34
35
  if not new_orders:
35
36
  return
36
37
 
@@ -45,20 +46,4 @@ class PlaceOptionRequest(ApiRequest):
45
46
  market = sub_order.get("market")
46
47
  category = market + "_" + instrument_type
47
48
  if category is not None:
48
- self.add_header("category", category)
49
-
50
- def add_custom_headers_from_context(self):
51
- try:
52
- headers_map = RequestContextHolder.get()
53
- if not headers_map:
54
- return
55
- for key, value in headers_map.items():
56
- self.add_header(key, value)
57
- finally:
58
- RequestContextHolder.clear()
59
-
60
- def add_custom_headers(self, headers_map):
61
- if not headers_map:
62
- return
63
- for key, value in headers_map.items():
64
- self.add_header(key, value)
49
+ self.add_header("category", category)
@@ -0,0 +1,44 @@
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
+ # coding=utf-8
15
+
16
+ from webull.core.request import ApiRequest
17
+
18
+
19
+ class PlaceOrderRequest(ApiRequest):
20
+ def __init__(self):
21
+ super().__init__("/openapi/trade/stock/order/place", version='v2', method="POST", body_params={})
22
+ self._new_orders = []
23
+ self._current_order = {}
24
+ self.add_body_params("new_orders", self._new_orders)
25
+
26
+ def set_new_orders(self, new_orders):
27
+ self.add_body_params("new_orders", new_orders)
28
+
29
+ def set_account_id(self, account_id):
30
+ self.add_body_params("account_id", account_id)
31
+
32
+ def set_client_combo_order_id(self, client_combo_order_id):
33
+ if client_combo_order_id:
34
+ self.add_body_params("client_combo_order_id", client_combo_order_id)
35
+
36
+ def add_custom_headers_from_order(self, new_orders):
37
+ if not new_orders:
38
+ return
39
+
40
+ if not isinstance(new_orders, (list, tuple)):
41
+ market = new_orders.get("market")
42
+ category = market + "_" + "STOCK"
43
+ if category is not None:
44
+ self.add_header("category", category)
@@ -19,10 +19,14 @@ from webull.core.request import ApiRequest
19
19
 
20
20
  class PreviewOptionRequest(ApiRequest):
21
21
  def __init__(self):
22
- super().__init__("/openapi/account/orders/option/preview", version='v2', method="POST", body_params={})
22
+ super().__init__("/openapi/trade/option/order/preview", version='v2', method="POST", body_params={})
23
23
 
24
24
  def set_new_orders(self, new_orders):
25
25
  self.add_body_params("new_orders", new_orders)
26
26
 
27
27
  def set_account_id(self, account_id):
28
- self.add_query_param("account_id", account_id)
28
+ self.add_body_params("account_id", account_id)
29
+
30
+ def set_client_combo_order_id(self, client_combo_order_id):
31
+ if client_combo_order_id:
32
+ self.add_body_params("client_combo_order_id", client_combo_order_id)
@@ -11,49 +11,19 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- from typing import List
15
14
 
16
15
  from webull.core.request import ApiRequest
17
16
 
18
-
19
- class CloseContract:
20
- def __init__(self, contract_id: str, quantity: str):
21
- self.contract_id = contract_id
22
- self.quantity = quantity
23
-
24
- def to_dict(self):
25
- return {
26
- "contract_id": self.contract_id,
27
- "quantity": self.quantity
28
- }
29
-
30
-
31
17
  class PreviewOrderRequest(ApiRequest):
32
18
  def __init__(self):
33
- super().__init__("/openapi/account/orders/preview", version='v2', method="POST", body_params={})
34
- self._new_orders = []
35
- self._current_order = {}
36
- self.add_body_params("new_orders", self._new_orders)
19
+ super().__init__("/openapi/trade/stock/order/preview", version='v2', method="POST", body_params={})
37
20
 
38
- def add_new_order_params(self, k, v):
39
- self._current_order[k] = v
21
+ def set_new_orders(self, new_orders):
22
+ self.add_body_params("new_orders", new_orders)
40
23
 
41
24
  def set_account_id(self, account_id):
42
- self.add_query_param("account_id", account_id)
43
-
44
- def set_close_contracts(self, close_contracts: List[CloseContract]):
45
- if not isinstance(close_contracts, list):
46
- raise TypeError("close_contracts must be a list of CloseContract objects.")
47
- self.add_new_order_params("close_contracts", [contract.to_dict() for contract in close_contracts])
48
-
49
- def set_new_orders(self, current_order):
50
- self._current_order.update({k: v for k, v in current_order.items() if v is not None and k != 'self'})
51
- if 'close_contracts' in current_order and current_order['close_contracts'] is not None:
52
- self.set_close_contracts(current_order['close_contracts'])
25
+ self.add_body_params("account_id", account_id)
53
26
 
54
- def finalize_order(self):
55
- if self._current_order:
56
- self._new_orders.append(self._current_order)
57
- self._current_order = {}
58
- else:
59
- raise ValueError("No order fields have been set.")
27
+ def set_client_combo_order_id(self, client_combo_order_id):
28
+ if client_combo_order_id:
29
+ self.add_body_params("client_combo_order_id", client_combo_order_id)
@@ -19,10 +19,14 @@ from webull.core.request import ApiRequest
19
19
 
20
20
  class ReplaceOptionRequest(ApiRequest):
21
21
  def __init__(self):
22
- super().__init__("/openapi/account/orders/option/replace", version='v2', method="POST", body_params={})
22
+ super().__init__("/openapi/trade/option/order/replace", version='v2', method="POST", body_params={})
23
23
 
24
24
  def set_modify_orders(self, modify_orders):
25
25
  self.add_body_params("modify_orders", modify_orders)
26
26
 
27
27
  def set_account_id(self, account_id):
28
- self.add_query_param("account_id", account_id)
28
+ self.add_body_params("account_id", account_id)
29
+
30
+ def set_client_combo_order_id(self, client_combo_order_id):
31
+ if client_combo_order_id:
32
+ self.add_body_params("client_combo_order_id", client_combo_order_id)