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.
Files changed (295) hide show
  1. samples/__init__.py +1 -0
  2. samples/data/__init__.py +1 -0
  3. samples/data/data_client.py +57 -0
  4. samples/data/data_streaming_client.py +86 -0
  5. samples/data/data_streaming_client_async.py +101 -0
  6. samples/trade/__init__.py +0 -0
  7. samples/trade/trade_client.py +163 -0
  8. samples/trade/trade_client_v2.py +181 -0
  9. samples/trade/trade_event_client.py +47 -0
  10. webull/__init__.py +1 -0
  11. webull/core/__init__.py +12 -0
  12. webull/core/auth/__init__.py +0 -0
  13. webull/core/auth/algorithm/__init__.py +0 -0
  14. webull/core/auth/algorithm/sha_hmac1.py +65 -0
  15. webull/core/auth/algorithm/sha_hmac256.py +75 -0
  16. webull/core/auth/composer/__init__.py +0 -0
  17. webull/core/auth/composer/default_signature_composer.py +125 -0
  18. webull/core/auth/credentials.py +46 -0
  19. webull/core/auth/signers/__init__.py +0 -0
  20. webull/core/auth/signers/app_key_signer.py +72 -0
  21. webull/core/auth/signers/signer.py +48 -0
  22. webull/core/auth/signers/signer_factory.py +58 -0
  23. webull/core/cache/__init__.py +225 -0
  24. webull/core/client.py +410 -0
  25. webull/core/common/__init__.py +0 -0
  26. webull/core/common/api_type.py +19 -0
  27. webull/core/common/easy_enum.py +35 -0
  28. webull/core/common/region.py +7 -0
  29. webull/core/compat.py +85 -0
  30. webull/core/context/__init__.py +0 -0
  31. webull/core/context/request_context_holder.py +33 -0
  32. webull/core/data/endpoints.json +22 -0
  33. webull/core/data/retry_config.json +15 -0
  34. webull/core/endpoint/__init__.py +8 -0
  35. webull/core/endpoint/chained_endpoint_resolver.py +57 -0
  36. webull/core/endpoint/default_endpoint_resolver.py +60 -0
  37. webull/core/endpoint/local_config_regional_endpoint_resolver.py +77 -0
  38. webull/core/endpoint/resolver_endpoint_request.py +46 -0
  39. webull/core/endpoint/user_customized_endpoint_resolver.py +55 -0
  40. webull/core/exception/__init__.py +0 -0
  41. webull/core/exception/error_code.py +23 -0
  42. webull/core/exception/error_msg.py +21 -0
  43. webull/core/exception/exceptions.py +53 -0
  44. webull/core/headers.py +57 -0
  45. webull/core/http/__init__.py +0 -0
  46. webull/core/http/initializer/__init__.py +0 -0
  47. webull/core/http/initializer/client_initializer.py +79 -0
  48. webull/core/http/initializer/token/__init__.py +0 -0
  49. webull/core/http/initializer/token/bean/__init__.py +0 -0
  50. webull/core/http/initializer/token/bean/access_token.py +40 -0
  51. webull/core/http/initializer/token/bean/check_token_request.py +44 -0
  52. webull/core/http/initializer/token/bean/create_token_request.py +45 -0
  53. webull/core/http/initializer/token/bean/refresh_token_request.py +44 -0
  54. webull/core/http/initializer/token/token_manager.py +208 -0
  55. webull/core/http/initializer/token/token_operation.py +72 -0
  56. webull/core/http/method_type.py +43 -0
  57. webull/core/http/protocol_type.py +43 -0
  58. webull/core/http/request.py +121 -0
  59. webull/core/http/response.py +166 -0
  60. webull/core/request.py +278 -0
  61. webull/core/retry/__init__.py +0 -0
  62. webull/core/retry/backoff_strategy.py +102 -0
  63. webull/core/retry/retry_condition.py +214 -0
  64. webull/core/retry/retry_policy.py +63 -0
  65. webull/core/retry/retry_policy_context.py +51 -0
  66. webull/core/utils/__init__.py +0 -0
  67. webull/core/utils/common.py +62 -0
  68. webull/core/utils/data.py +25 -0
  69. webull/core/utils/desensitize.py +33 -0
  70. webull/core/utils/validation.py +49 -0
  71. webull/core/vendored/__init__.py +0 -0
  72. webull/core/vendored/requests/__init__.py +94 -0
  73. webull/core/vendored/requests/__version__.py +28 -0
  74. webull/core/vendored/requests/_internal_utils.py +56 -0
  75. webull/core/vendored/requests/adapters.py +539 -0
  76. webull/core/vendored/requests/api.py +166 -0
  77. webull/core/vendored/requests/auth.py +307 -0
  78. webull/core/vendored/requests/certs.py +34 -0
  79. webull/core/vendored/requests/compat.py +85 -0
  80. webull/core/vendored/requests/cookies.py +555 -0
  81. webull/core/vendored/requests/exceptions.py +136 -0
  82. webull/core/vendored/requests/help.py +134 -0
  83. webull/core/vendored/requests/hooks.py +48 -0
  84. webull/core/vendored/requests/models.py +960 -0
  85. webull/core/vendored/requests/packages/__init__.py +17 -0
  86. webull/core/vendored/requests/packages/certifi/__init__.py +17 -0
  87. webull/core/vendored/requests/packages/certifi/__main__.py +16 -0
  88. webull/core/vendored/requests/packages/certifi/cacert.pem +4433 -0
  89. webull/core/vendored/requests/packages/certifi/core.py +51 -0
  90. webull/core/vendored/requests/packages/chardet/__init__.py +53 -0
  91. webull/core/vendored/requests/packages/chardet/big5freq.py +400 -0
  92. webull/core/vendored/requests/packages/chardet/big5prober.py +61 -0
  93. webull/core/vendored/requests/packages/chardet/chardistribution.py +247 -0
  94. webull/core/vendored/requests/packages/chardet/charsetgroupprober.py +120 -0
  95. webull/core/vendored/requests/packages/chardet/charsetprober.py +159 -0
  96. webull/core/vendored/requests/packages/chardet/cli/__init__.py +1 -0
  97. webull/core/vendored/requests/packages/chardet/cli/chardetect.py +99 -0
  98. webull/core/vendored/requests/packages/chardet/codingstatemachine.py +102 -0
  99. webull/core/vendored/requests/packages/chardet/compat.py +48 -0
  100. webull/core/vendored/requests/packages/chardet/cp949prober.py +63 -0
  101. webull/core/vendored/requests/packages/chardet/enums.py +90 -0
  102. webull/core/vendored/requests/packages/chardet/escprober.py +115 -0
  103. webull/core/vendored/requests/packages/chardet/escsm.py +260 -0
  104. webull/core/vendored/requests/packages/chardet/eucjpprober.py +106 -0
  105. webull/core/vendored/requests/packages/chardet/euckrfreq.py +209 -0
  106. webull/core/vendored/requests/packages/chardet/euckrprober.py +61 -0
  107. webull/core/vendored/requests/packages/chardet/euctwfreq.py +401 -0
  108. webull/core/vendored/requests/packages/chardet/euctwprober.py +60 -0
  109. webull/core/vendored/requests/packages/chardet/gb2312freq.py +297 -0
  110. webull/core/vendored/requests/packages/chardet/gb2312prober.py +60 -0
  111. webull/core/vendored/requests/packages/chardet/hebrewprober.py +306 -0
  112. webull/core/vendored/requests/packages/chardet/jisfreq.py +339 -0
  113. webull/core/vendored/requests/packages/chardet/jpcntx.py +247 -0
  114. webull/core/vendored/requests/packages/chardet/langbulgarianmodel.py +242 -0
  115. webull/core/vendored/requests/packages/chardet/langcyrillicmodel.py +347 -0
  116. webull/core/vendored/requests/packages/chardet/langgreekmodel.py +239 -0
  117. webull/core/vendored/requests/packages/chardet/langhebrewmodel.py +214 -0
  118. webull/core/vendored/requests/packages/chardet/langhungarianmodel.py +239 -0
  119. webull/core/vendored/requests/packages/chardet/langthaimodel.py +213 -0
  120. webull/core/vendored/requests/packages/chardet/langturkishmodel.py +207 -0
  121. webull/core/vendored/requests/packages/chardet/latin1prober.py +159 -0
  122. webull/core/vendored/requests/packages/chardet/mbcharsetprober.py +105 -0
  123. webull/core/vendored/requests/packages/chardet/mbcsgroupprober.py +68 -0
  124. webull/core/vendored/requests/packages/chardet/mbcssm.py +586 -0
  125. webull/core/vendored/requests/packages/chardet/sbcharsetprober.py +146 -0
  126. webull/core/vendored/requests/packages/chardet/sbcsgroupprober.py +87 -0
  127. webull/core/vendored/requests/packages/chardet/sjisprober.py +106 -0
  128. webull/core/vendored/requests/packages/chardet/universaldetector.py +300 -0
  129. webull/core/vendored/requests/packages/chardet/utf8prober.py +96 -0
  130. webull/core/vendored/requests/packages/chardet/version.py +23 -0
  131. webull/core/vendored/requests/packages/urllib3/__init__.py +114 -0
  132. webull/core/vendored/requests/packages/urllib3/_collections.py +346 -0
  133. webull/core/vendored/requests/packages/urllib3/connection.py +405 -0
  134. webull/core/vendored/requests/packages/urllib3/connectionpool.py +910 -0
  135. webull/core/vendored/requests/packages/urllib3/contrib/__init__.py +0 -0
  136. webull/core/vendored/requests/packages/urllib3/contrib/_appengine_environ.py +44 -0
  137. webull/core/vendored/requests/packages/urllib3/contrib/_securetransport/__init__.py +0 -0
  138. webull/core/vendored/requests/packages/urllib3/contrib/_securetransport/bindings.py +607 -0
  139. webull/core/vendored/requests/packages/urllib3/contrib/_securetransport/low_level.py +360 -0
  140. webull/core/vendored/requests/packages/urllib3/contrib/appengine.py +303 -0
  141. webull/core/vendored/requests/packages/urllib3/contrib/ntlmpool.py +125 -0
  142. webull/core/vendored/requests/packages/urllib3/contrib/pyopenssl.py +484 -0
  143. webull/core/vendored/requests/packages/urllib3/contrib/securetransport.py +818 -0
  144. webull/core/vendored/requests/packages/urllib3/contrib/socks.py +206 -0
  145. webull/core/vendored/requests/packages/urllib3/exceptions.py +260 -0
  146. webull/core/vendored/requests/packages/urllib3/fields.py +192 -0
  147. webull/core/vendored/requests/packages/urllib3/filepost.py +112 -0
  148. webull/core/vendored/requests/packages/urllib3/packages/__init__.py +19 -0
  149. webull/core/vendored/requests/packages/urllib3/packages/backports/__init__.py +0 -0
  150. webull/core/vendored/requests/packages/urllib3/packages/backports/makefile.py +67 -0
  151. webull/core/vendored/requests/packages/urllib3/packages/ordered_dict.py +273 -0
  152. webull/core/vendored/requests/packages/urllib3/packages/six.py +882 -0
  153. webull/core/vendored/requests/packages/urllib3/packages/socks.py +887 -0
  154. webull/core/vendored/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py +19 -0
  155. webull/core/vendored/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py +170 -0
  156. webull/core/vendored/requests/packages/urllib3/poolmanager.py +467 -0
  157. webull/core/vendored/requests/packages/urllib3/request.py +164 -0
  158. webull/core/vendored/requests/packages/urllib3/response.py +721 -0
  159. webull/core/vendored/requests/packages/urllib3/util/__init__.py +68 -0
  160. webull/core/vendored/requests/packages/urllib3/util/connection.py +148 -0
  161. webull/core/vendored/requests/packages/urllib3/util/queue.py +35 -0
  162. webull/core/vendored/requests/packages/urllib3/util/request.py +132 -0
  163. webull/core/vendored/requests/packages/urllib3/util/response.py +101 -0
  164. webull/core/vendored/requests/packages/urllib3/util/retry.py +426 -0
  165. webull/core/vendored/requests/packages/urllib3/util/selectors.py +601 -0
  166. webull/core/vendored/requests/packages/urllib3/util/ssl_.py +396 -0
  167. webull/core/vendored/requests/packages/urllib3/util/timeout.py +256 -0
  168. webull/core/vendored/requests/packages/urllib3/util/url.py +252 -0
  169. webull/core/vendored/requests/packages/urllib3/util/wait.py +164 -0
  170. webull/core/vendored/requests/packages.py +28 -0
  171. webull/core/vendored/requests/sessions.py +750 -0
  172. webull/core/vendored/requests/status_codes.py +105 -0
  173. webull/core/vendored/requests/structures.py +119 -0
  174. webull/core/vendored/requests/utils.py +916 -0
  175. webull/core/vendored/six.py +905 -0
  176. webull/data/__init__.py +3 -0
  177. webull/data/common/__init__.py +0 -0
  178. webull/data/common/category.py +26 -0
  179. webull/data/common/connect_ack.py +29 -0
  180. webull/data/common/direction.py +25 -0
  181. webull/data/common/exchange_code.py +33 -0
  182. webull/data/common/exercise_style.py +22 -0
  183. webull/data/common/expiration_cycle.py +26 -0
  184. webull/data/common/instrument_status.py +23 -0
  185. webull/data/common/option_type.py +20 -0
  186. webull/data/common/subscribe_type.py +22 -0
  187. webull/data/common/timespan.py +29 -0
  188. webull/data/data_client.py +35 -0
  189. webull/data/data_streaming_client.py +89 -0
  190. webull/data/internal/__init__.py +0 -0
  191. webull/data/internal/default_retry_policy.py +84 -0
  192. webull/data/internal/exceptions.py +60 -0
  193. webull/data/internal/quotes_client.py +314 -0
  194. webull/data/internal/quotes_decoder.py +40 -0
  195. webull/data/internal/quotes_payload_decoder.py +35 -0
  196. webull/data/internal/quotes_topic.py +36 -0
  197. webull/data/quotes/__init__.py +0 -0
  198. webull/data/quotes/instrument.py +33 -0
  199. webull/data/quotes/market_data.py +187 -0
  200. webull/data/quotes/market_streaming_data.py +66 -0
  201. webull/data/quotes/subscribe/__init__.py +0 -0
  202. webull/data/quotes/subscribe/ask_bid_result.py +49 -0
  203. webull/data/quotes/subscribe/basic_result.py +45 -0
  204. webull/data/quotes/subscribe/broker_result.py +33 -0
  205. webull/data/quotes/subscribe/message_pb2.py +37 -0
  206. webull/data/quotes/subscribe/order_result.py +30 -0
  207. webull/data/quotes/subscribe/payload_type.py +19 -0
  208. webull/data/quotes/subscribe/quote_decoder.py +28 -0
  209. webull/data/quotes/subscribe/quote_result.py +47 -0
  210. webull/data/quotes/subscribe/snapshot_decoder.py +30 -0
  211. webull/data/quotes/subscribe/snapshot_result.py +69 -0
  212. webull/data/quotes/subscribe/tick_decoder.py +29 -0
  213. webull/data/quotes/subscribe/tick_result.py +47 -0
  214. webull/data/request/__init__.py +0 -0
  215. webull/data/request/get_batch_historical_bars_request.py +43 -0
  216. webull/data/request/get_corp_action_request.py +47 -0
  217. webull/data/request/get_eod_bars_request.py +32 -0
  218. webull/data/request/get_historical_bars_request.py +43 -0
  219. webull/data/request/get_instruments_request.py +30 -0
  220. webull/data/request/get_quotes_request.py +35 -0
  221. webull/data/request/get_snapshot_request.py +38 -0
  222. webull/data/request/get_tick_request.py +37 -0
  223. webull/data/request/subscribe_request.py +43 -0
  224. webull/data/request/unsubscribe_request.py +42 -0
  225. webull/trade/__init__.py +2 -0
  226. webull/trade/common/__init__.py +0 -0
  227. webull/trade/common/account_type.py +22 -0
  228. webull/trade/common/category.py +29 -0
  229. webull/trade/common/combo_ticker_type.py +23 -0
  230. webull/trade/common/combo_type.py +31 -0
  231. webull/trade/common/currency.py +24 -0
  232. webull/trade/common/forbid_reason.py +27 -0
  233. webull/trade/common/instrument_type.py +27 -0
  234. webull/trade/common/markets.py +27 -0
  235. webull/trade/common/order_entrust_type.py +21 -0
  236. webull/trade/common/order_side.py +23 -0
  237. webull/trade/common/order_status.py +25 -0
  238. webull/trade/common/order_tif.py +24 -0
  239. webull/trade/common/order_type.py +30 -0
  240. webull/trade/common/trade_policy.py +22 -0
  241. webull/trade/common/trading_date_type.py +24 -0
  242. webull/trade/common/trailing_type.py +23 -0
  243. webull/trade/events/__init__.py +0 -0
  244. webull/trade/events/default_retry_policy.py +64 -0
  245. webull/trade/events/events_pb2.py +43 -0
  246. webull/trade/events/events_pb2_grpc.py +66 -0
  247. webull/trade/events/signature_composer.py +61 -0
  248. webull/trade/events/types.py +21 -0
  249. webull/trade/request/__init__.py +0 -0
  250. webull/trade/request/cancel_order_request.py +28 -0
  251. webull/trade/request/get_account_balance_request.py +28 -0
  252. webull/trade/request/get_account_positions_request.py +30 -0
  253. webull/trade/request/get_account_profile_request.py +26 -0
  254. webull/trade/request/get_app_subscriptions.py +28 -0
  255. webull/trade/request/get_open_orders_request.py +30 -0
  256. webull/trade/request/get_order_detail_request.py +27 -0
  257. webull/trade/request/get_today_orders_request.py +31 -0
  258. webull/trade/request/get_trade_calendar_request.py +30 -0
  259. webull/trade/request/get_trade_instrument_detail_request.py +24 -0
  260. webull/trade/request/get_trade_security_detail_request.py +42 -0
  261. webull/trade/request/get_tradeable_instruments_request.py +27 -0
  262. webull/trade/request/palce_order_request.py +91 -0
  263. webull/trade/request/place_order_request_v2.py +58 -0
  264. webull/trade/request/replace_order_request.py +73 -0
  265. webull/trade/request/replace_order_request_v2.py +38 -0
  266. webull/trade/request/v2/__init__.py +0 -0
  267. webull/trade/request/v2/cancel_option_request.py +28 -0
  268. webull/trade/request/v2/cancel_order_request.py +28 -0
  269. webull/trade/request/v2/get_account_balance_request.py +28 -0
  270. webull/trade/request/v2/get_account_list.py +23 -0
  271. webull/trade/request/v2/get_account_positions_request.py +24 -0
  272. webull/trade/request/v2/get_order_detail_request.py +26 -0
  273. webull/trade/request/v2/get_order_history_request.py +35 -0
  274. webull/trade/request/v2/palce_order_request.py +87 -0
  275. webull/trade/request/v2/place_option_request.py +64 -0
  276. webull/trade/request/v2/preview_option_request.py +28 -0
  277. webull/trade/request/v2/preview_order_request.py +59 -0
  278. webull/trade/request/v2/replace_option_request.py +28 -0
  279. webull/trade/request/v2/replace_order_request.py +57 -0
  280. webull/trade/trade/__init__.py +0 -0
  281. webull/trade/trade/account_info.py +83 -0
  282. webull/trade/trade/order_operation.py +246 -0
  283. webull/trade/trade/trade_calendar.py +37 -0
  284. webull/trade/trade/trade_instrument.py +72 -0
  285. webull/trade/trade/v2/__init__.py +0 -0
  286. webull/trade/trade/v2/account_info_v2.py +55 -0
  287. webull/trade/trade/v2/order_operation_v2.py +206 -0
  288. webull/trade/trade_client.py +43 -0
  289. webull/trade/trade_events_client.py +233 -0
  290. webull_openapi_python_sdk-1.0.0.dist-info/METADATA +28 -0
  291. webull_openapi_python_sdk-1.0.0.dist-info/RECORD +295 -0
  292. webull_openapi_python_sdk-1.0.0.dist-info/WHEEL +5 -0
  293. webull_openapi_python_sdk-1.0.0.dist-info/licenses/LICENSE +202 -0
  294. webull_openapi_python_sdk-1.0.0.dist-info/licenses/NOTICE +56 -0
  295. 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"
@@ -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"
@@ -0,0 +1,12 @@
1
+ __version__ = "1.0.0"
2
+
3
+ import logging
4
+
5
+ class NullHandler(logging.Handler):
6
+ def emit(self, record):
7
+ """
8
+ null handler
9
+ """
10
+ pass
11
+
12
+ logging.getLogger('webull.core').addHandler(NullHandler())
File without changes
File without changes