webull-openapi-python-sdk 1.0.0__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.
- samples/__init__.py +1 -0
- samples/data/__init__.py +1 -0
- samples/data/data_client.py +57 -0
- samples/data/data_streaming_client.py +86 -0
- samples/data/data_streaming_client_async.py +101 -0
- samples/trade/__init__.py +0 -0
- samples/trade/trade_client.py +163 -0
- samples/trade/trade_client_v2.py +181 -0
- samples/trade/trade_event_client.py +47 -0
- webull/__init__.py +1 -0
- webull/core/__init__.py +12 -0
- webull/core/auth/__init__.py +0 -0
- webull/core/auth/algorithm/__init__.py +0 -0
- webull/core/auth/algorithm/sha_hmac1.py +65 -0
- webull/core/auth/algorithm/sha_hmac256.py +75 -0
- webull/core/auth/composer/__init__.py +0 -0
- webull/core/auth/composer/default_signature_composer.py +125 -0
- webull/core/auth/credentials.py +46 -0
- webull/core/auth/signers/__init__.py +0 -0
- webull/core/auth/signers/app_key_signer.py +72 -0
- webull/core/auth/signers/signer.py +48 -0
- webull/core/auth/signers/signer_factory.py +58 -0
- webull/core/cache/__init__.py +225 -0
- webull/core/client.py +410 -0
- webull/core/common/__init__.py +0 -0
- webull/core/common/api_type.py +19 -0
- webull/core/common/easy_enum.py +35 -0
- webull/core/common/region.py +7 -0
- webull/core/compat.py +85 -0
- webull/core/context/__init__.py +0 -0
- webull/core/context/request_context_holder.py +33 -0
- webull/core/data/endpoints.json +22 -0
- webull/core/data/retry_config.json +15 -0
- webull/core/endpoint/__init__.py +8 -0
- webull/core/endpoint/chained_endpoint_resolver.py +57 -0
- webull/core/endpoint/default_endpoint_resolver.py +60 -0
- webull/core/endpoint/local_config_regional_endpoint_resolver.py +77 -0
- webull/core/endpoint/resolver_endpoint_request.py +46 -0
- webull/core/endpoint/user_customized_endpoint_resolver.py +55 -0
- webull/core/exception/__init__.py +0 -0
- webull/core/exception/error_code.py +23 -0
- webull/core/exception/error_msg.py +21 -0
- webull/core/exception/exceptions.py +53 -0
- webull/core/headers.py +57 -0
- webull/core/http/__init__.py +0 -0
- webull/core/http/initializer/__init__.py +0 -0
- webull/core/http/initializer/client_initializer.py +79 -0
- webull/core/http/initializer/token/__init__.py +0 -0
- webull/core/http/initializer/token/bean/__init__.py +0 -0
- webull/core/http/initializer/token/bean/access_token.py +40 -0
- webull/core/http/initializer/token/bean/check_token_request.py +44 -0
- webull/core/http/initializer/token/bean/create_token_request.py +45 -0
- webull/core/http/initializer/token/bean/refresh_token_request.py +44 -0
- webull/core/http/initializer/token/token_manager.py +208 -0
- webull/core/http/initializer/token/token_operation.py +72 -0
- webull/core/http/method_type.py +43 -0
- webull/core/http/protocol_type.py +43 -0
- webull/core/http/request.py +121 -0
- webull/core/http/response.py +166 -0
- webull/core/request.py +278 -0
- webull/core/retry/__init__.py +0 -0
- webull/core/retry/backoff_strategy.py +102 -0
- webull/core/retry/retry_condition.py +214 -0
- webull/core/retry/retry_policy.py +63 -0
- webull/core/retry/retry_policy_context.py +51 -0
- webull/core/utils/__init__.py +0 -0
- webull/core/utils/common.py +62 -0
- webull/core/utils/data.py +25 -0
- webull/core/utils/desensitize.py +33 -0
- webull/core/utils/validation.py +49 -0
- webull/core/vendored/__init__.py +0 -0
- webull/core/vendored/requests/__init__.py +94 -0
- webull/core/vendored/requests/__version__.py +28 -0
- webull/core/vendored/requests/_internal_utils.py +56 -0
- webull/core/vendored/requests/adapters.py +539 -0
- webull/core/vendored/requests/api.py +166 -0
- webull/core/vendored/requests/auth.py +307 -0
- webull/core/vendored/requests/certs.py +34 -0
- webull/core/vendored/requests/compat.py +85 -0
- webull/core/vendored/requests/cookies.py +555 -0
- webull/core/vendored/requests/exceptions.py +136 -0
- webull/core/vendored/requests/help.py +134 -0
- webull/core/vendored/requests/hooks.py +48 -0
- webull/core/vendored/requests/models.py +960 -0
- webull/core/vendored/requests/packages/__init__.py +17 -0
- webull/core/vendored/requests/packages/certifi/__init__.py +17 -0
- webull/core/vendored/requests/packages/certifi/__main__.py +16 -0
- webull/core/vendored/requests/packages/certifi/cacert.pem +4433 -0
- webull/core/vendored/requests/packages/certifi/core.py +51 -0
- webull/core/vendored/requests/packages/chardet/__init__.py +53 -0
- webull/core/vendored/requests/packages/chardet/big5freq.py +400 -0
- webull/core/vendored/requests/packages/chardet/big5prober.py +61 -0
- webull/core/vendored/requests/packages/chardet/chardistribution.py +247 -0
- webull/core/vendored/requests/packages/chardet/charsetgroupprober.py +120 -0
- webull/core/vendored/requests/packages/chardet/charsetprober.py +159 -0
- webull/core/vendored/requests/packages/chardet/cli/__init__.py +1 -0
- webull/core/vendored/requests/packages/chardet/cli/chardetect.py +99 -0
- webull/core/vendored/requests/packages/chardet/codingstatemachine.py +102 -0
- webull/core/vendored/requests/packages/chardet/compat.py +48 -0
- webull/core/vendored/requests/packages/chardet/cp949prober.py +63 -0
- webull/core/vendored/requests/packages/chardet/enums.py +90 -0
- webull/core/vendored/requests/packages/chardet/escprober.py +115 -0
- webull/core/vendored/requests/packages/chardet/escsm.py +260 -0
- webull/core/vendored/requests/packages/chardet/eucjpprober.py +106 -0
- webull/core/vendored/requests/packages/chardet/euckrfreq.py +209 -0
- webull/core/vendored/requests/packages/chardet/euckrprober.py +61 -0
- webull/core/vendored/requests/packages/chardet/euctwfreq.py +401 -0
- webull/core/vendored/requests/packages/chardet/euctwprober.py +60 -0
- webull/core/vendored/requests/packages/chardet/gb2312freq.py +297 -0
- webull/core/vendored/requests/packages/chardet/gb2312prober.py +60 -0
- webull/core/vendored/requests/packages/chardet/hebrewprober.py +306 -0
- webull/core/vendored/requests/packages/chardet/jisfreq.py +339 -0
- webull/core/vendored/requests/packages/chardet/jpcntx.py +247 -0
- webull/core/vendored/requests/packages/chardet/langbulgarianmodel.py +242 -0
- webull/core/vendored/requests/packages/chardet/langcyrillicmodel.py +347 -0
- webull/core/vendored/requests/packages/chardet/langgreekmodel.py +239 -0
- webull/core/vendored/requests/packages/chardet/langhebrewmodel.py +214 -0
- webull/core/vendored/requests/packages/chardet/langhungarianmodel.py +239 -0
- webull/core/vendored/requests/packages/chardet/langthaimodel.py +213 -0
- webull/core/vendored/requests/packages/chardet/langturkishmodel.py +207 -0
- webull/core/vendored/requests/packages/chardet/latin1prober.py +159 -0
- webull/core/vendored/requests/packages/chardet/mbcharsetprober.py +105 -0
- webull/core/vendored/requests/packages/chardet/mbcsgroupprober.py +68 -0
- webull/core/vendored/requests/packages/chardet/mbcssm.py +586 -0
- webull/core/vendored/requests/packages/chardet/sbcharsetprober.py +146 -0
- webull/core/vendored/requests/packages/chardet/sbcsgroupprober.py +87 -0
- webull/core/vendored/requests/packages/chardet/sjisprober.py +106 -0
- webull/core/vendored/requests/packages/chardet/universaldetector.py +300 -0
- webull/core/vendored/requests/packages/chardet/utf8prober.py +96 -0
- webull/core/vendored/requests/packages/chardet/version.py +23 -0
- webull/core/vendored/requests/packages/urllib3/__init__.py +114 -0
- webull/core/vendored/requests/packages/urllib3/_collections.py +346 -0
- webull/core/vendored/requests/packages/urllib3/connection.py +405 -0
- webull/core/vendored/requests/packages/urllib3/connectionpool.py +910 -0
- webull/core/vendored/requests/packages/urllib3/contrib/__init__.py +0 -0
- webull/core/vendored/requests/packages/urllib3/contrib/_appengine_environ.py +44 -0
- webull/core/vendored/requests/packages/urllib3/contrib/_securetransport/__init__.py +0 -0
- webull/core/vendored/requests/packages/urllib3/contrib/_securetransport/bindings.py +607 -0
- webull/core/vendored/requests/packages/urllib3/contrib/_securetransport/low_level.py +360 -0
- webull/core/vendored/requests/packages/urllib3/contrib/appengine.py +303 -0
- webull/core/vendored/requests/packages/urllib3/contrib/ntlmpool.py +125 -0
- webull/core/vendored/requests/packages/urllib3/contrib/pyopenssl.py +484 -0
- webull/core/vendored/requests/packages/urllib3/contrib/securetransport.py +818 -0
- webull/core/vendored/requests/packages/urllib3/contrib/socks.py +206 -0
- webull/core/vendored/requests/packages/urllib3/exceptions.py +260 -0
- webull/core/vendored/requests/packages/urllib3/fields.py +192 -0
- webull/core/vendored/requests/packages/urllib3/filepost.py +112 -0
- webull/core/vendored/requests/packages/urllib3/packages/__init__.py +19 -0
- webull/core/vendored/requests/packages/urllib3/packages/backports/__init__.py +0 -0
- webull/core/vendored/requests/packages/urllib3/packages/backports/makefile.py +67 -0
- webull/core/vendored/requests/packages/urllib3/packages/ordered_dict.py +273 -0
- webull/core/vendored/requests/packages/urllib3/packages/six.py +882 -0
- webull/core/vendored/requests/packages/urllib3/packages/socks.py +887 -0
- webull/core/vendored/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py +19 -0
- webull/core/vendored/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py +170 -0
- webull/core/vendored/requests/packages/urllib3/poolmanager.py +467 -0
- webull/core/vendored/requests/packages/urllib3/request.py +164 -0
- webull/core/vendored/requests/packages/urllib3/response.py +721 -0
- webull/core/vendored/requests/packages/urllib3/util/__init__.py +68 -0
- webull/core/vendored/requests/packages/urllib3/util/connection.py +148 -0
- webull/core/vendored/requests/packages/urllib3/util/queue.py +35 -0
- webull/core/vendored/requests/packages/urllib3/util/request.py +132 -0
- webull/core/vendored/requests/packages/urllib3/util/response.py +101 -0
- webull/core/vendored/requests/packages/urllib3/util/retry.py +426 -0
- webull/core/vendored/requests/packages/urllib3/util/selectors.py +601 -0
- webull/core/vendored/requests/packages/urllib3/util/ssl_.py +396 -0
- webull/core/vendored/requests/packages/urllib3/util/timeout.py +256 -0
- webull/core/vendored/requests/packages/urllib3/util/url.py +252 -0
- webull/core/vendored/requests/packages/urllib3/util/wait.py +164 -0
- webull/core/vendored/requests/packages.py +28 -0
- webull/core/vendored/requests/sessions.py +750 -0
- webull/core/vendored/requests/status_codes.py +105 -0
- webull/core/vendored/requests/structures.py +119 -0
- webull/core/vendored/requests/utils.py +916 -0
- webull/core/vendored/six.py +905 -0
- webull/data/__init__.py +3 -0
- webull/data/common/__init__.py +0 -0
- webull/data/common/category.py +26 -0
- webull/data/common/connect_ack.py +29 -0
- webull/data/common/direction.py +25 -0
- webull/data/common/exchange_code.py +33 -0
- webull/data/common/exercise_style.py +22 -0
- webull/data/common/expiration_cycle.py +26 -0
- webull/data/common/instrument_status.py +23 -0
- webull/data/common/option_type.py +20 -0
- webull/data/common/subscribe_type.py +22 -0
- webull/data/common/timespan.py +29 -0
- webull/data/data_client.py +35 -0
- webull/data/data_streaming_client.py +89 -0
- webull/data/internal/__init__.py +0 -0
- webull/data/internal/default_retry_policy.py +84 -0
- webull/data/internal/exceptions.py +60 -0
- webull/data/internal/quotes_client.py +314 -0
- webull/data/internal/quotes_decoder.py +40 -0
- webull/data/internal/quotes_payload_decoder.py +35 -0
- webull/data/internal/quotes_topic.py +36 -0
- webull/data/quotes/__init__.py +0 -0
- webull/data/quotes/instrument.py +33 -0
- webull/data/quotes/market_data.py +187 -0
- webull/data/quotes/market_streaming_data.py +66 -0
- webull/data/quotes/subscribe/__init__.py +0 -0
- webull/data/quotes/subscribe/ask_bid_result.py +49 -0
- webull/data/quotes/subscribe/basic_result.py +45 -0
- webull/data/quotes/subscribe/broker_result.py +33 -0
- webull/data/quotes/subscribe/message_pb2.py +37 -0
- webull/data/quotes/subscribe/order_result.py +30 -0
- webull/data/quotes/subscribe/payload_type.py +19 -0
- webull/data/quotes/subscribe/quote_decoder.py +28 -0
- webull/data/quotes/subscribe/quote_result.py +47 -0
- webull/data/quotes/subscribe/snapshot_decoder.py +30 -0
- webull/data/quotes/subscribe/snapshot_result.py +69 -0
- webull/data/quotes/subscribe/tick_decoder.py +29 -0
- webull/data/quotes/subscribe/tick_result.py +47 -0
- webull/data/request/__init__.py +0 -0
- webull/data/request/get_batch_historical_bars_request.py +43 -0
- webull/data/request/get_corp_action_request.py +47 -0
- webull/data/request/get_eod_bars_request.py +32 -0
- webull/data/request/get_historical_bars_request.py +43 -0
- webull/data/request/get_instruments_request.py +30 -0
- webull/data/request/get_quotes_request.py +35 -0
- webull/data/request/get_snapshot_request.py +38 -0
- webull/data/request/get_tick_request.py +37 -0
- webull/data/request/subscribe_request.py +43 -0
- webull/data/request/unsubscribe_request.py +42 -0
- webull/trade/__init__.py +2 -0
- webull/trade/common/__init__.py +0 -0
- webull/trade/common/account_type.py +22 -0
- webull/trade/common/category.py +29 -0
- webull/trade/common/combo_ticker_type.py +23 -0
- webull/trade/common/combo_type.py +31 -0
- webull/trade/common/currency.py +24 -0
- webull/trade/common/forbid_reason.py +27 -0
- webull/trade/common/instrument_type.py +27 -0
- webull/trade/common/markets.py +27 -0
- webull/trade/common/order_entrust_type.py +21 -0
- webull/trade/common/order_side.py +23 -0
- webull/trade/common/order_status.py +25 -0
- webull/trade/common/order_tif.py +24 -0
- webull/trade/common/order_type.py +30 -0
- webull/trade/common/trade_policy.py +22 -0
- webull/trade/common/trading_date_type.py +24 -0
- webull/trade/common/trailing_type.py +23 -0
- webull/trade/events/__init__.py +0 -0
- webull/trade/events/default_retry_policy.py +64 -0
- webull/trade/events/events_pb2.py +43 -0
- webull/trade/events/events_pb2_grpc.py +66 -0
- webull/trade/events/signature_composer.py +61 -0
- webull/trade/events/types.py +21 -0
- webull/trade/request/__init__.py +0 -0
- webull/trade/request/cancel_order_request.py +28 -0
- webull/trade/request/get_account_balance_request.py +28 -0
- webull/trade/request/get_account_positions_request.py +30 -0
- webull/trade/request/get_account_profile_request.py +26 -0
- webull/trade/request/get_app_subscriptions.py +28 -0
- webull/trade/request/get_open_orders_request.py +30 -0
- webull/trade/request/get_order_detail_request.py +27 -0
- webull/trade/request/get_today_orders_request.py +31 -0
- webull/trade/request/get_trade_calendar_request.py +30 -0
- webull/trade/request/get_trade_instrument_detail_request.py +24 -0
- webull/trade/request/get_trade_security_detail_request.py +42 -0
- webull/trade/request/get_tradeable_instruments_request.py +27 -0
- webull/trade/request/palce_order_request.py +91 -0
- webull/trade/request/place_order_request_v2.py +58 -0
- webull/trade/request/replace_order_request.py +73 -0
- webull/trade/request/replace_order_request_v2.py +38 -0
- webull/trade/request/v2/__init__.py +0 -0
- webull/trade/request/v2/cancel_option_request.py +28 -0
- webull/trade/request/v2/cancel_order_request.py +28 -0
- webull/trade/request/v2/get_account_balance_request.py +28 -0
- webull/trade/request/v2/get_account_list.py +23 -0
- webull/trade/request/v2/get_account_positions_request.py +24 -0
- webull/trade/request/v2/get_order_detail_request.py +26 -0
- webull/trade/request/v2/get_order_history_request.py +35 -0
- webull/trade/request/v2/palce_order_request.py +87 -0
- webull/trade/request/v2/place_option_request.py +64 -0
- webull/trade/request/v2/preview_option_request.py +28 -0
- webull/trade/request/v2/preview_order_request.py +59 -0
- webull/trade/request/v2/replace_option_request.py +28 -0
- webull/trade/request/v2/replace_order_request.py +57 -0
- webull/trade/trade/__init__.py +0 -0
- webull/trade/trade/account_info.py +83 -0
- webull/trade/trade/order_operation.py +246 -0
- webull/trade/trade/trade_calendar.py +37 -0
- webull/trade/trade/trade_instrument.py +72 -0
- webull/trade/trade/v2/__init__.py +0 -0
- webull/trade/trade/v2/account_info_v2.py +55 -0
- webull/trade/trade/v2/order_operation_v2.py +206 -0
- webull/trade/trade_client.py +43 -0
- webull/trade/trade_events_client.py +233 -0
- webull_openapi_python_sdk-1.0.0.dist-info/METADATA +28 -0
- webull_openapi_python_sdk-1.0.0.dist-info/RECORD +295 -0
- webull_openapi_python_sdk-1.0.0.dist-info/WHEEL +5 -0
- webull_openapi_python_sdk-1.0.0.dist-info/licenses/LICENSE +202 -0
- webull_openapi_python_sdk-1.0.0.dist-info/licenses/NOTICE +56 -0
- webull_openapi_python_sdk-1.0.0.dist-info/top_level.txt +2 -0
samples/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
samples/data/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# coding=utf-8
|
|
@@ -0,0 +1,57 @@
|
|
|
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.data.common.category import Category
|
|
18
|
+
from webull.data.common.timespan import Timespan
|
|
19
|
+
from webull.core.client import ApiClient
|
|
20
|
+
from webull.data.data_client import DataClient
|
|
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
|
+
api_client = ApiClient(your_app_key, your_app_secret, region_id)
|
|
27
|
+
api_client.add_endpoint(region_id, optional_api_endpoint)
|
|
28
|
+
|
|
29
|
+
if __name__ == '__main__':
|
|
30
|
+
data_client = DataClient(api_client)
|
|
31
|
+
|
|
32
|
+
trading_sessions = ["PRE", "RTH", "ATH", "OVN"]
|
|
33
|
+
res = data_client.instrument.get_instrument("AAPL", Category.US_STOCK.name)
|
|
34
|
+
if res.status_code == 200:
|
|
35
|
+
print('get_instrument:', res.json())
|
|
36
|
+
|
|
37
|
+
res = data_client.market_data.get_snapshot('AAPL', Category.US_STOCK.name, extend_hour_required=True, overnight_required=True)
|
|
38
|
+
if res.status_code == 200:
|
|
39
|
+
print('get_snapshot:', res.json())
|
|
40
|
+
|
|
41
|
+
res = data_client.market_data.get_history_bar('AAPL', Category.US_STOCK.name, Timespan.M1.name)
|
|
42
|
+
if res.status_code == 200:
|
|
43
|
+
print('get_history_bar:', res.json())
|
|
44
|
+
|
|
45
|
+
res = data_client.market_data.get_batch_history_bar(['AAPL', 'TSLA'], Category.US_STOCK.name, Timespan.M1.name, 1)
|
|
46
|
+
if res.status_code == 200:
|
|
47
|
+
print('get_batch_history_bar:', res.json())
|
|
48
|
+
|
|
49
|
+
res = data_client.market_data.get_tick("AAPL", Category.US_STOCK.name, trading_sessions=trading_sessions)
|
|
50
|
+
if res.status_code == 200:
|
|
51
|
+
print('get_tick:', res.json())
|
|
52
|
+
|
|
53
|
+
res = data_client.market_data.get_quotes("AAPL", Category.US_STOCK.name, depth=1, overnight_required=True)
|
|
54
|
+
if res.status_code == 200:
|
|
55
|
+
print('get_quotes:', res.json())
|
|
56
|
+
|
|
57
|
+
|
|
@@ -0,0 +1,86 @@
|
|
|
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
|
+
import logging
|
|
18
|
+
import uuid
|
|
19
|
+
from logging.handlers import TimedRotatingFileHandler
|
|
20
|
+
|
|
21
|
+
from webull.data.common.category import Category
|
|
22
|
+
from webull.data.common.subscribe_type import SubscribeType
|
|
23
|
+
from webull.data.data_streaming_client import DataStreamingClient
|
|
24
|
+
|
|
25
|
+
your_app_key = "</your_app_key>"
|
|
26
|
+
your_app_secret = "</your_app_secret>"
|
|
27
|
+
optional_api_endpoint = "</optional_quotes_endpoint>"
|
|
28
|
+
optional_quotes_endpoint = "</optional_quotes_endpoint>"
|
|
29
|
+
region_id = '<region_id>'
|
|
30
|
+
|
|
31
|
+
session_id = uuid.uuid4().hex
|
|
32
|
+
data_streaming_client = DataStreamingClient(your_app_key, your_app_secret, region_id, session_id,
|
|
33
|
+
http_host=optional_api_endpoint,
|
|
34
|
+
mqtt_host=optional_quotes_endpoint)
|
|
35
|
+
|
|
36
|
+
if __name__ == '__main__':
|
|
37
|
+
def my_connect_success_func(client, api_client, quotes_session_id):
|
|
38
|
+
print("connect success with session_id:%s" % quotes_session_id)
|
|
39
|
+
# subscribe
|
|
40
|
+
symbols = ['00700']
|
|
41
|
+
sub_types = [SubscribeType.QUOTE.name, SubscribeType.SNAPSHOT.name, SubscribeType.TICK.name]
|
|
42
|
+
client.subscribe( symbols, Category.HK_STOCK.name, sub_types)
|
|
43
|
+
|
|
44
|
+
def my_quotes_message_func(client, topic, quotes):
|
|
45
|
+
print("receive message: topic:%s, quotes:%s" % (topic, quotes))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def my_subscribe_success_func(client, api_client, quotes_session_id):
|
|
49
|
+
print("subscribe success with session_id:%s" % quotes_session_id)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# set connect success callback func
|
|
53
|
+
data_streaming_client.on_connect_success = my_connect_success_func
|
|
54
|
+
# set quotes receiving callback func
|
|
55
|
+
data_streaming_client.on_quotes_message = my_quotes_message_func
|
|
56
|
+
# set subscribe success callback func
|
|
57
|
+
data_streaming_client.on_subscribe_success = my_subscribe_success_func
|
|
58
|
+
|
|
59
|
+
# logger = logging.getLogger("webull.data")
|
|
60
|
+
# logger.setLevel(logging.INFO)
|
|
61
|
+
# formatter = logging.Formatter("%(thread)d %(threadName)s %(asctime)s %(name)s %(levelname)s %(message)s")
|
|
62
|
+
# # stream
|
|
63
|
+
# stream_handler = logging.StreamHandler()
|
|
64
|
+
# logger.addHandler(stream_handler)
|
|
65
|
+
# # file
|
|
66
|
+
# file_handler = TimedRotatingFileHandler(
|
|
67
|
+
# filename="webull_data_streaming_sdk.log",
|
|
68
|
+
# when='H',
|
|
69
|
+
# interval=1,
|
|
70
|
+
# backupCount=72,
|
|
71
|
+
# encoding='utf-8'
|
|
72
|
+
# )
|
|
73
|
+
# file_handler.setFormatter(formatter)
|
|
74
|
+
# logger.addHandler(file_handler)
|
|
75
|
+
# # Specify log
|
|
76
|
+
# data_streaming_client.connect_and_loop_forever(customer_logger=logger)
|
|
77
|
+
|
|
78
|
+
# decode:optional, decoder is set by default; you can also use sub-defined parser to override
|
|
79
|
+
# data_streaming_client.register_payload_decoder(PAYLOAD_TYPE_QUOTE, QuoteDecoder())
|
|
80
|
+
# data_streaming_client.register_payload_decoder(PAYLOAD_TYPE_SHAPSHOT, SnapshotDecoder())
|
|
81
|
+
# data_streaming_client.register_payload_decoder(PAYLOAD_TYPE_TICK, TickDecoder())
|
|
82
|
+
|
|
83
|
+
# the sync mode, blocking in current thread
|
|
84
|
+
data_streaming_client.connect_and_loop_forever()
|
|
85
|
+
|
|
86
|
+
|
|
@@ -0,0 +1,101 @@
|
|
|
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
|
+
import time
|
|
18
|
+
import uuid
|
|
19
|
+
|
|
20
|
+
from webull.data.common.category import Category
|
|
21
|
+
from webull.data.common.subscribe_type import SubscribeType
|
|
22
|
+
from webull.data.data_streaming_client import DataStreamingClient
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
your_app_key = "</your_app_key>"
|
|
26
|
+
your_app_secret = "</your_app_secret>"
|
|
27
|
+
optional_api_endpoint = "</optional_quotes_endpoint>"
|
|
28
|
+
optional_quotes_endpoint = "</optional_quotes_endpoint>"
|
|
29
|
+
region_id = '<region_id>'
|
|
30
|
+
|
|
31
|
+
session_id = uuid.uuid4().hex
|
|
32
|
+
data_streaming_client = DataStreamingClient(your_app_key, your_app_secret, region_id, session_id,
|
|
33
|
+
http_host=optional_api_endpoint,
|
|
34
|
+
mqtt_host=optional_quotes_endpoint)
|
|
35
|
+
|
|
36
|
+
if __name__ == '__main__':
|
|
37
|
+
def my_connect_success_func(client, api_client, quotes_session_id):
|
|
38
|
+
print("connect success with session_id:%s" % quotes_session_id)
|
|
39
|
+
# subscribe
|
|
40
|
+
symbols = ['00700']
|
|
41
|
+
sub_types = [SubscribeType.QUOTE.name, SubscribeType.SNAPSHOT.name, SubscribeType.TICK.name]
|
|
42
|
+
client.subscribe(symbols, Category.HK_STOCK.name, sub_types)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def my_quotes_message_func(client, topic, quotes):
|
|
46
|
+
print("receive message: topic:%s, quotes:%s" % (topic, quotes))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def my_subscribe_success_func(client, api_client, quotes_session_id):
|
|
50
|
+
print("subscribe success with session_id:%s" % quotes_session_id)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# set connect success callback func
|
|
54
|
+
data_streaming_client.on_connect_success = my_connect_success_func
|
|
55
|
+
# set quotes receiving callback func
|
|
56
|
+
data_streaming_client.on_quotes_message = my_quotes_message_func
|
|
57
|
+
# set subscribe success callback func
|
|
58
|
+
data_streaming_client.on_subscribe_success = my_subscribe_success_func
|
|
59
|
+
|
|
60
|
+
# the async mode, processing in another thread
|
|
61
|
+
data_streaming_client.connect_and_loop_start()
|
|
62
|
+
|
|
63
|
+
ticker = 60
|
|
64
|
+
print("will remove subscription after %s seconds..." % ticker)
|
|
65
|
+
time.sleep(ticker)
|
|
66
|
+
|
|
67
|
+
subscribe_success = data_streaming_client.get_subscribe_success()
|
|
68
|
+
quotes_session_id = data_streaming_client.get_session_id()
|
|
69
|
+
if subscribe_success:
|
|
70
|
+
print("start remove subscription...")
|
|
71
|
+
data_streaming_client.unsubscribe(unsubscribe_all=True)
|
|
72
|
+
print("remove subscription finish")
|
|
73
|
+
else:
|
|
74
|
+
print("Do not remove subscription, subscribe_success:%s", subscribe_success)
|
|
75
|
+
|
|
76
|
+
start_time = time.time()
|
|
77
|
+
wait_time = 1
|
|
78
|
+
while True:
|
|
79
|
+
elapsed = int(time.time() - start_time)
|
|
80
|
+
if elapsed >= ticker:
|
|
81
|
+
print("Wait completed, start subscribing...")
|
|
82
|
+
break
|
|
83
|
+
print("Waiting {} seconds before subscription... (elapsed {}s / {}s)".format(wait_time, elapsed, ticker))
|
|
84
|
+
time.sleep(wait_time)
|
|
85
|
+
|
|
86
|
+
# subscribe
|
|
87
|
+
connect_success = data_streaming_client.get_connect_success()
|
|
88
|
+
if connect_success:
|
|
89
|
+
symbols = ['00700']
|
|
90
|
+
sub_types = [SubscribeType.QUOTE.name, SubscribeType.SNAPSHOT.name, SubscribeType.TICK.name]
|
|
91
|
+
data_streaming_client.subscribe(symbols, Category.HK_STOCK.name, sub_types)
|
|
92
|
+
print("add subscription...")
|
|
93
|
+
else:
|
|
94
|
+
print("Do not add subscription, connect_success:%s", connect_success)
|
|
95
|
+
|
|
96
|
+
print("will stop processing after %s seconds" % ticker)
|
|
97
|
+
time.sleep(ticker)
|
|
98
|
+
data_streaming_client.loop_stop()
|
|
99
|
+
print("processing done")
|
|
100
|
+
|
|
101
|
+
|
|
File without changes
|
|
@@ -0,0 +1,163 @@
|
|
|
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.data.common.category import Category
|
|
21
|
+
from webull.trade.trade_client import TradeClient
|
|
22
|
+
|
|
23
|
+
optional_api_endpoint = "<api_endpoint>"
|
|
24
|
+
your_app_key = "<your_app_key>"
|
|
25
|
+
your_app_secret = "<your_app_secret>"
|
|
26
|
+
region_id = "<region_id>"
|
|
27
|
+
account_id = "<your_account_id>"
|
|
28
|
+
api_client = ApiClient(your_app_key, your_app_secret, region_id)
|
|
29
|
+
api_client.add_endpoint(region_id, optional_api_endpoint)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if __name__ == '__main__':
|
|
33
|
+
trade_client = TradeClient(api_client)
|
|
34
|
+
|
|
35
|
+
res = trade_client.account.get_app_subscriptions()
|
|
36
|
+
if res.status_code == 200:
|
|
37
|
+
print('app subscriptions:', res.json())
|
|
38
|
+
|
|
39
|
+
res = trade_client.account.get_account_profile(account_id)
|
|
40
|
+
if res.status_code == 200:
|
|
41
|
+
print('account profile:', res.json())
|
|
42
|
+
|
|
43
|
+
res = trade_client.account.get_account_position(account_id)
|
|
44
|
+
if res.status_code == 200:
|
|
45
|
+
print('account position:', res.json())
|
|
46
|
+
|
|
47
|
+
res = trade_client.account.get_account_balance(account_id, 'HKD')
|
|
48
|
+
if res.status_code == 200:
|
|
49
|
+
print('account balance:', res.json())
|
|
50
|
+
|
|
51
|
+
client_order_id = uuid.uuid4().hex
|
|
52
|
+
print('client order id:', client_order_id)
|
|
53
|
+
stock_order = {
|
|
54
|
+
"account_id": account_id,
|
|
55
|
+
"stock_order": {
|
|
56
|
+
"client_order_id": client_order_id,
|
|
57
|
+
"instrument_id": "913256135",
|
|
58
|
+
"side": "BUY",
|
|
59
|
+
"tif": "DAY",
|
|
60
|
+
"order_type": "MARKET",
|
|
61
|
+
"qty": "1",
|
|
62
|
+
"extended_hours_trading": False
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# This is an optional feature; you can still make a request without setting it.
|
|
67
|
+
custom_headers_map = {"category": Category.US_STOCK.name}
|
|
68
|
+
trade_client.order.add_custom_headers(custom_headers_map)
|
|
69
|
+
res = trade_client.order.place_order_v2(stock_order['account_id'], stock_order['stock_order'])
|
|
70
|
+
trade_client.order.remove_custom_headers()
|
|
71
|
+
if res.status_code == 200:
|
|
72
|
+
print('place order v2 res:', res.json())
|
|
73
|
+
|
|
74
|
+
res = trade_client.order.replace_order_v2(stock_order['account_id'], stock_order['stock_order'])
|
|
75
|
+
if res.status_code == 200:
|
|
76
|
+
print('replace order v2 res:', res.json())
|
|
77
|
+
|
|
78
|
+
res = trade_client.order.list_open_orders(account_id, page_size=20)
|
|
79
|
+
if res.status_code == 200:
|
|
80
|
+
print('open orders:', res.json())
|
|
81
|
+
|
|
82
|
+
res = trade_client.order.list_today_orders(account_id, page_size=20)
|
|
83
|
+
if res.status_code == 200:
|
|
84
|
+
print('today orders', res.json())
|
|
85
|
+
|
|
86
|
+
res = trade_client.order.query_order_detail(account_id, client_order_id)
|
|
87
|
+
if res.status_code == 200:
|
|
88
|
+
print('order detail:', res.json())
|
|
89
|
+
|
|
90
|
+
res = trade_client.order.cancel_order(account_id, client_order_id)
|
|
91
|
+
if res.status_code == 200:
|
|
92
|
+
print('cancel order status:', res.json())
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# Options
|
|
97
|
+
# For option order inquiries, please use the V2 query interface: api.order_v2.get_order_detail(account_id, client_order_id).
|
|
98
|
+
client_order_id = uuid.uuid4().hex
|
|
99
|
+
option_new_orders = [
|
|
100
|
+
{
|
|
101
|
+
"client_order_id": client_order_id,
|
|
102
|
+
"combo_type": "NORMAL",
|
|
103
|
+
"order_type": "LIMIT",
|
|
104
|
+
"quantity": "1",
|
|
105
|
+
"limit_price": "11.25",
|
|
106
|
+
"option_strategy": "SINGLE",
|
|
107
|
+
"side": "BUY",
|
|
108
|
+
"time_in_force": "GTC",
|
|
109
|
+
"entrust_type": "QTY",
|
|
110
|
+
"orders": [
|
|
111
|
+
{
|
|
112
|
+
"side": "BUY",
|
|
113
|
+
"quantity": "1",
|
|
114
|
+
"symbol": "AAPL",
|
|
115
|
+
"strike_price": "250.0",
|
|
116
|
+
"init_exp_date": "2025-08-15",
|
|
117
|
+
"instrument_type": "OPTION",
|
|
118
|
+
"option_type": "CALL",
|
|
119
|
+
"market": "US"
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
# preview
|
|
126
|
+
res = trade_client.order.preview_option(account_id, option_new_orders)
|
|
127
|
+
if res.status_code == 200:
|
|
128
|
+
print("preview option=" + json.dumps(res.json(), indent=4))
|
|
129
|
+
sleep(5)
|
|
130
|
+
|
|
131
|
+
# place
|
|
132
|
+
# This is an optional feature; you can still make a request without setting it.
|
|
133
|
+
custom_headers_map = {"category": Category.US_OPTION.name}
|
|
134
|
+
trade_client.order.add_custom_headers(custom_headers_map)
|
|
135
|
+
res = trade_client.order.place_option(account_id, option_new_orders)
|
|
136
|
+
trade_client.order.remove_custom_headers()
|
|
137
|
+
if res.status_code == 200:
|
|
138
|
+
print("place option=" + json.dumps(res.json(), indent=4))
|
|
139
|
+
sleep(5)
|
|
140
|
+
|
|
141
|
+
# replace
|
|
142
|
+
option_modify_orders = [
|
|
143
|
+
{
|
|
144
|
+
"client_order_id": client_order_id,
|
|
145
|
+
"quantity": "2",
|
|
146
|
+
"limit_price": "11.3",
|
|
147
|
+
"orders": [
|
|
148
|
+
{
|
|
149
|
+
"client_order_id": client_order_id,
|
|
150
|
+
"quantity": "2"
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
res = trade_client.order.replace_option(account_id, option_modify_orders)
|
|
156
|
+
if res.status_code == 200:
|
|
157
|
+
print("replace option=" + json.dumps(res.json(), indent=4))
|
|
158
|
+
sleep(5)
|
|
159
|
+
|
|
160
|
+
# cancel
|
|
161
|
+
res = trade_client.order.cancel_option(account_id, client_order_id)
|
|
162
|
+
if res.status_code == 200:
|
|
163
|
+
print("cancel option=" + json.dumps(res.json(), indent=4))
|
|
@@ -0,0 +1,181 @@
|
|
|
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
|
+
import json
|
|
15
|
+
import unittest
|
|
16
|
+
import uuid
|
|
17
|
+
from time import sleep
|
|
18
|
+
|
|
19
|
+
from webull.core.client import ApiClient
|
|
20
|
+
from webull.data.common.category import Category
|
|
21
|
+
from webull.trade.trade_client import TradeClient
|
|
22
|
+
|
|
23
|
+
optional_api_endpoint = "<api_endpoint>"
|
|
24
|
+
your_app_key = "<your_app_key>"
|
|
25
|
+
your_app_secret = "<your_app_secret>"
|
|
26
|
+
region_id = "<region_id>"
|
|
27
|
+
account_id = "<your_account_id>"
|
|
28
|
+
api_client = ApiClient(your_app_key, your_app_secret, region_id)
|
|
29
|
+
api_client.add_endpoint(region_id, optional_api_endpoint)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if __name__ == '__main__':
|
|
33
|
+
trade_client = TradeClient(api_client)
|
|
34
|
+
|
|
35
|
+
res = trade_client.account_v2.get_account_list()
|
|
36
|
+
if res.status_code == 200:
|
|
37
|
+
print("account_list=" + json.dumps(res.json(), indent=4))
|
|
38
|
+
|
|
39
|
+
res = trade_client.account_v2.get_account_balance(account_id)
|
|
40
|
+
if res.status_code == 200:
|
|
41
|
+
print("account_balance=" + json.dumps(res.json(), indent=4))
|
|
42
|
+
|
|
43
|
+
res = trade_client.account_v2.get_account_position(account_id)
|
|
44
|
+
if res.status_code == 200:
|
|
45
|
+
print("account_position=" + json.dumps(res.json(), indent=4))
|
|
46
|
+
|
|
47
|
+
preview_orders = {
|
|
48
|
+
"symbol": "AAPL",
|
|
49
|
+
"instrument_type": "EQUITY",
|
|
50
|
+
"market": "US",
|
|
51
|
+
"order_type": "MARKET",
|
|
52
|
+
"quantity": "1",
|
|
53
|
+
"support_trading_session": "N",
|
|
54
|
+
"side": "BUY",
|
|
55
|
+
"time_in_force": "DAY",
|
|
56
|
+
"entrust_type": "QTY"
|
|
57
|
+
}
|
|
58
|
+
res = trade_client.order_v2.preview_order(account_id=account_id, preview_orders=preview_orders)
|
|
59
|
+
if res.status_code == 200:
|
|
60
|
+
print("preview_res=" + json.dumps(res.json(), indent=4))
|
|
61
|
+
|
|
62
|
+
client_order_id = uuid.uuid4().hex
|
|
63
|
+
new_orders = {
|
|
64
|
+
"client_order_id": client_order_id,
|
|
65
|
+
"symbol": "AAPL",
|
|
66
|
+
"instrument_type": "EQUITY",
|
|
67
|
+
"market": "US",
|
|
68
|
+
"order_type": "LIMIT",
|
|
69
|
+
"limit_price": "188",
|
|
70
|
+
"quantity": "1",
|
|
71
|
+
"support_trading_session": "N",
|
|
72
|
+
"side": "BUY",
|
|
73
|
+
"time_in_force": "DAY",
|
|
74
|
+
"entrust_type": "QTY",
|
|
75
|
+
# "account_tax_type": "GENERAL"
|
|
76
|
+
# "total_cash_amount": "100.20"
|
|
77
|
+
# "sender_sub_id": "123321-lzg",
|
|
78
|
+
# "no_party_ids":[
|
|
79
|
+
# {"party_id":"BNG144.666555","party_id_source":"D","party_role":"3"}
|
|
80
|
+
# ]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# This is an optional feature; you can still make a request without setting it.
|
|
84
|
+
custom_headers_map = {"category": Category.US_STOCK.name}
|
|
85
|
+
trade_client.order_v2.add_custom_headers(custom_headers_map)
|
|
86
|
+
res = trade_client.order_v2.place_order(account_id=account_id, new_orders=new_orders)
|
|
87
|
+
trade_client.order_v2.remove_custom_headers()
|
|
88
|
+
if res.status_code == 200:
|
|
89
|
+
print("place_order_res=" + json.dumps(res.json(), indent=4))
|
|
90
|
+
sleep(5)
|
|
91
|
+
|
|
92
|
+
modify_orders = {
|
|
93
|
+
"client_order_id": client_order_id,
|
|
94
|
+
"quantity": "100",
|
|
95
|
+
"limit_price": "200"
|
|
96
|
+
}
|
|
97
|
+
res = trade_client.order_v2.replace_order(account_id=account_id, modify_orders=modify_orders)
|
|
98
|
+
if res.status_code == 200:
|
|
99
|
+
print("replace_order_res=" + json.dumps(res.json(), indent=4))
|
|
100
|
+
sleep(5)
|
|
101
|
+
|
|
102
|
+
res = trade_client.order_v2.cancel_order_v2(account_id=account_id, client_order_id=client_order_id)
|
|
103
|
+
if res.status_code == 200:
|
|
104
|
+
print("cancel_order_res=" + json.dumps(res.json(), indent=4))
|
|
105
|
+
|
|
106
|
+
res = trade_client.order_v2.get_order_history_request(account_id=account_id)
|
|
107
|
+
if res.status_code == 200:
|
|
108
|
+
print("order_history_res=" + json.dumps(res.json(), indent=4))
|
|
109
|
+
|
|
110
|
+
# order detail
|
|
111
|
+
res = trade_client.order_v2.get_order_detail(account_id=account_id, client_order_id=client_order_id)
|
|
112
|
+
if res.status_code == 200:
|
|
113
|
+
print("order detail=" + json.dumps(res.json(), indent=4))
|
|
114
|
+
|
|
115
|
+
# Options
|
|
116
|
+
# For option order inquiries, please use the V2 query interface: api.order_v2.get_order_detail(account_id, client_order_id).
|
|
117
|
+
client_order_id = uuid.uuid4().hex
|
|
118
|
+
option_new_orders = [
|
|
119
|
+
{
|
|
120
|
+
"client_order_id": client_order_id,
|
|
121
|
+
"combo_type": "NORMAL",
|
|
122
|
+
"order_type": "LIMIT",
|
|
123
|
+
"quantity": "1",
|
|
124
|
+
"limit_price": "11.25",
|
|
125
|
+
"option_strategy": "SINGLE",
|
|
126
|
+
"side": "BUY",
|
|
127
|
+
"time_in_force": "GTC",
|
|
128
|
+
"entrust_type": "QTY",
|
|
129
|
+
"orders": [
|
|
130
|
+
{
|
|
131
|
+
"side": "BUY",
|
|
132
|
+
"quantity": "1",
|
|
133
|
+
"symbol": "AAPL",
|
|
134
|
+
"strike_price": "250.0",
|
|
135
|
+
"init_exp_date": "2025-08-15",
|
|
136
|
+
"instrument_type": "OPTION",
|
|
137
|
+
"option_type": "CALL",
|
|
138
|
+
"market": "US"
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
# preview
|
|
144
|
+
res = trade_client.order_v2.preview_option(account_id, option_new_orders)
|
|
145
|
+
if res.status_code == 200:
|
|
146
|
+
print("preview option=" + json.dumps(res.json(), indent=4))
|
|
147
|
+
sleep(5)
|
|
148
|
+
# place
|
|
149
|
+
|
|
150
|
+
# This is an optional feature; you can still make a request without setting it.
|
|
151
|
+
custom_headers_map = {"category": Category.US_OPTION.name}
|
|
152
|
+
trade_client.order_v2.add_custom_headers(custom_headers_map)
|
|
153
|
+
res = trade_client.order_v2.place_option(account_id, option_new_orders)
|
|
154
|
+
trade_client.order_v2.remove_custom_headers()
|
|
155
|
+
if res.status_code == 200:
|
|
156
|
+
print("place option=" + json.dumps(res.json(), indent=4))
|
|
157
|
+
sleep(5)
|
|
158
|
+
|
|
159
|
+
# replace
|
|
160
|
+
option_modify_orders = [
|
|
161
|
+
{
|
|
162
|
+
"client_order_id": client_order_id,
|
|
163
|
+
"quantity": "2",
|
|
164
|
+
"limit_price": "11.3",
|
|
165
|
+
"orders": [
|
|
166
|
+
{
|
|
167
|
+
"client_order_id": client_order_id,
|
|
168
|
+
"quantity": "2"
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
res = trade_client.order_v2.replace_option(account_id, option_modify_orders)
|
|
174
|
+
if res.status_code == 200:
|
|
175
|
+
print("replace option=" + json.dumps(res.json(), indent=4))
|
|
176
|
+
sleep(5)
|
|
177
|
+
|
|
178
|
+
# cancel
|
|
179
|
+
res = trade_client.order_v2.cancel_option(account_id, client_order_id)
|
|
180
|
+
if res.status_code == 200:
|
|
181
|
+
print("cancel option=" + json.dumps(res.json(), indent=4))
|
|
@@ -0,0 +1,47 @@
|
|
|
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 unittest
|
|
16
|
+
|
|
17
|
+
from webull.trade.trade_events_client import TradeEventsClient
|
|
18
|
+
from webull.trade.events.types import ORDER_STATUS_CHANGED, EVENT_TYPE_ORDER
|
|
19
|
+
|
|
20
|
+
your_app_key = "<your_app_key>"
|
|
21
|
+
your_app_secret = "<your_app_secret>"
|
|
22
|
+
account_id = "<your_account_id>"
|
|
23
|
+
region_id = "hk"
|
|
24
|
+
|
|
25
|
+
optional_api_endpoint = "<event_api_endpoint>"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == '__main__':
|
|
29
|
+
# Create EventsClient instance
|
|
30
|
+
trade_events_client = TradeEventsClient(your_app_key, your_app_secret, region_id)
|
|
31
|
+
trade_events_client.enable_logger()
|
|
32
|
+
# 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
|
|
33
|
+
# trade_events_client = TradeEventsClient(your_app_key, your_app_secret, region_id, host=optional_api_endpoint)
|
|
34
|
+
|
|
35
|
+
# Set the callback function when the event data is received.
|
|
36
|
+
# The data of order status change is printed here
|
|
37
|
+
|
|
38
|
+
def my_on_events_message(event_type, subscribe_type, payload, raw_message):
|
|
39
|
+
if EVENT_TYPE_ORDER == event_type and ORDER_STATUS_CHANGED == subscribe_type:
|
|
40
|
+
print('----request_id:%s----' % payload['request_id'])
|
|
41
|
+
print(payload['account_id'])
|
|
42
|
+
print(payload['client_order_id'])
|
|
43
|
+
print(payload['order_status'])
|
|
44
|
+
|
|
45
|
+
trade_events_client.on_events_message = my_on_events_message
|
|
46
|
+
# Set the account ID to be subscribed and initiate the subscription. This method is synchronous
|
|
47
|
+
trade_events_client.do_subscribe([account_id])
|
webull/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.0"
|
webull/core/__init__.py
ADDED
|
File without changes
|
|
File without changes
|