Skip to content

Commit c84ff92

Browse files
committed
Merge branch 'feature/us-quotes' into 'main'
feat:us stock market See merge request institution/openapi-python-sdk!33
2 parents 2f1ee08 + bd3d860 commit c84ff92

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1312
-419
lines changed

README.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,21 @@ Subscription to real-time information: Subscribe to order status changes, market
1919

2020
## Interface Protocol
2121

22-
The bottom layer of Webull OpenAPI provides three protocols, HTTP / GRPC / MQTT, to support functions and features like trading, subcriptions for changes of order status and real-time market quotes.
22+
The bottom layer of Webull OpenAPI provides three protocols, HTTP / GRPC / MQTT, to support functions and features like trading, subscriptions for changes of order status and real-time market quotes.
2323

24-
HTTP: It mainly provides interface services for data such as tradings, accounts, candlestick charts, snapshots, etc.
25-
26-
GRPC: Currently provides real-time messages for order status changes.
27-
28-
MQTT: Provides data services for real-time market conditions.
24+
| Protocol | Description |
25+
|-------|------------------------------------------|
26+
| HTTP | It mainly provides interface services for data such as tradings, accounts, candlestick charts, snapshots, etc. |
27+
| GRPC | 1. Provide real-time push messages for order status changes.<br/>2. Provide data query support for the market interface. |
28+
| MQTT | Provides data services for real-time market conditions. |
2929

3030
## Developer documentation
3131

3232
https://developer.webull.hk/api-doc/
3333

3434
## Documentation
3535

36-
- [Requirements](./docs/0-Requirement_CN.md)
36+
- [Requirements](./docs/0-Requirement.md)
3737
- [SDK installation](./docs/1-Installation.md)
3838
- [Timeout mechanism](./docs/2-Timeout.md)
3939
- [Proxy configuration](./docs/3-Proxy.md)

docs/1-Installation.md

-8
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,3 @@ Packages that need to be installed by default for the complete use of the tradin
2525
- `webull-python-sdk-core`
2626
- `webull-python-sdk-trade-events-core`
2727
- `webull-python-sdk-trade-hk`
28-
29-
## Source package installation script
30-
31-
### windows
32-
Under the source code package scripts directory`install_for_windows.bat`
33-
34-
### Linux / MacOS
35-
Under the source code package scripts directory`install.sh`

webull-python-sdk-core/webullsdkcore/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "0.1.1"
1+
__version__ = "0.1.2"
22

33
import logging
44

webull-python-sdk-demos/setup.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
LONG_DESCRIPTION = fp.read()
1616

1717
requires = [
18-
"webull-python-sdk-mdata==0.1.1",
19-
"webull-python-sdk-trade-hk==0.1.1"
18+
"webull-python-sdk-mdata==0.1.2",
19+
"webull-python-sdk-trade-hk==0.1.2"
2020
]
2121

2222
setup_args = {

webull-python-sdk-demos/tests/mdata/quote_mqtt/custom_client.py

+11-8
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
from webullsdkmdata.common.subscribe_type import SubscribeType
77
from webullsdkmdata.quotes.grpc.pb import quote_pb2
88
from webullsdkmdata.quotes.grpc.response import Response
9-
from webullsdkmdata.quotes.subscribe.basic_quote_decoder import BasicQuoteDecoder
10-
from webullsdkmdata.quotes.subscribe.payload_type import PAYLOAD_TYPE_SHAPSHOT, PAYLOAD_TYPE_BASIC_QUOTE
119
from webullsdkmdata.quotes.subscribe.snapshot_decoder import SnapshotDecoder
10+
from webullsdkmdata.quotes.subscribe.tick_decoder import TickDecoder
11+
from webullsdkmdata.quotes.subscribe.quote_decoder import QuoteDecoder
12+
from webullsdkmdata.quotes.subscribe.payload_type import (PAYLOAD_TYPE_QUOTE,
13+
PAYLOAD_TYPE_SHAPSHOT, PAYLOAD_TYPE_TICK)
1214
from webullsdkmdata.request.grpc.get_streaming_token_request import GetStreamingTokenRequest
1315
from webullsdkmdata.request.grpc.quotes_subscribe_request import SubscribeRequest
1416
from webullsdkmdata.request.grpc.quotes_unsubscribe_request import UnsubcribeRequest
@@ -26,8 +28,9 @@ def __init__(self, app_key, app_secret, host=None, region_id=None):
2628
self._host = host
2729
self.subscribe_client = QuotesClient(app_key, app_secret, region_id, host)
2830
self.subscribe_client.register_payload_decoder(
29-
PAYLOAD_TYPE_BASIC_QUOTE, BasicQuoteDecoder())
31+
PAYLOAD_TYPE_QUOTE, QuoteDecoder())
3032
self.subscribe_client.register_payload_decoder(PAYLOAD_TYPE_SHAPSHOT, SnapshotDecoder())
33+
self.subscribe_client.register_payload_decoder(PAYLOAD_TYPE_TICK, TickDecoder())
3134
self._grpc_client = self.subscribe_client.grpc_client
3235

3336
def _on_quotes_subscribe(self, client, api_client, token):
@@ -84,8 +87,8 @@ def unsubscribe(self, symbols, category, sub_types, unsubscribe_all=False):
8487

8588
try:
8689
# subscribe
87-
res = custom_client.subscribe(['00700'], Category.HK_STOCK.name,
88-
[SubscribeType.BASIC_QUOTE.name, SubscribeType.SNAPSHOT.name])
90+
res = custom_client.subscribe(['AAPL'], Category.US_STOCK.name,
91+
[SubscribeType.QUOTE.name, SubscribeType.SNAPSHOT.name, SubscribeType.TICK.name])
8992
print(res.path)
9093
print(res.request_id)
9194
print(res.status_code)
@@ -97,9 +100,9 @@ def unsubscribe(self, symbols, category, sub_types, unsubscribe_all=False):
97100
time.sleep(30)
98101

99102
print("unsubscribe")
100-
res = custom_client.unsubscribe(symbols=None, category=Category.HK_STOCK.name,
101-
sub_types=[SubscribeType.BASIC_QUOTE.name, SubscribeType.SNAPSHOT.name],
102-
unsubscribe_all=True)
103+
res = custom_client.unsubscribe(symbols=['AAPL'], category=Category.US_STOCK.name,
104+
sub_types=[SubscribeType.QUOTE.name],
105+
unsubscribe_all=False)
103106

104107
print(res.path)
105108
print(res.request_id)

webull-python-sdk-demos/tests/mdata/requset/test_get_quote_request.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# coding=utf-8
22
import unittest
3-
from webullsdkmdata.request.get_quote_request import GetQuoteRequest
3+
from webullsdkmdata.request.get_snapshot_request import GetSnapshotRequest
44
from webullsdkmdata.common.category import Category
55
from webullsdkcore.client import ApiClient
66

77
PRE_OPENAPI_ENDPOINT = "<api_endpoint>"
88
class TestGetQuoteRequest(unittest.TestCase):
99
def test_request(self):
10-
reuqest = GetQuoteRequest()
10+
reuqest = GetSnapshotRequest()
1111
reuqest.set_category(Category.US_STOCK.name)
1212
reuqest.set_symbols(["AAPL", "TSLA"])
1313
reuqest.set_endpoint(PRE_OPENAPI_ENDPOINT)

webull-python-sdk-demos/tests/tradehk/quote/grpc/grpc_test.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,30 @@
5353

5454
time.sleep(1)
5555
print('get_instrument request', '*' * 20)
56-
res = instrument.get_instrument('00700', 'HK_STOCK')
56+
res = instrument.get_instrument('F', 'US_STOCK')
5757
print(res.path)
5858
print(res.request_id)
5959
print(res.status_code)
6060
print(res.msg)
6161
print(res.json())
6262
print('get_instrument request end', '*' * 20)
63+
64+
time.sleep(1)
65+
print('get_tick request', '*' * 20)
66+
res = market_data.get_tick('00700', 'HK_STOCK')
67+
print(res.path)
68+
print(res.request_id)
69+
print(res.status_code)
70+
print(res.msg)
71+
print(res.json())
72+
print('get_tick request end', '*' * 20)
73+
74+
time.sleep(1)
75+
print('get_snapshot_quote request', '*' * 20)
76+
res = market_data.get_snapshot('00700', 'HK_STOCK')
77+
print(res.path)
78+
print(res.request_id)
79+
print(res.status_code)
80+
print(res.msg)
81+
print(res.json())
82+
print('get_snapshot_quote request end', '*' * 20)

webull-python-sdk-demos/tests/tradehk/quote/subcribe/subcribe.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@ def test_default_quotes_client(self):
1515
def pt_logs(client, userdata, level, buf):
1616
print("userdata:%s, level:%s, buf:%s" % (userdata, level, buf))
1717

18-
def on_message(client, userdata, message):
19-
print("Received message '" + str(message.payload) + "' on topic '"
20-
+ message.topic + "' with QoS " + str(message.qos))
18+
def on_quotes_message(client, userdata, message):
19+
print("Received message userdata: %s,%s'" % (userdata, message))
2120

2221
client = DefaultQuotesClient(your_app_key, your_app_secret, 'hk', optional_quotes_endpoint)
23-
client.init_default_settings('00700,09988', Category.HK_STOCK.name, SubscribeType.SNAPSHOT.name)
24-
client.on_log = pt_logs
25-
client.on_message = on_message
22+
client.init_default_settings('AAPL', Category.US_STOCK.name, SubscribeType.SNAPSHOT.name)
23+
# client.on_log = pt_logs
24+
client.on_quotes_message = on_quotes_message
2625
client.connect_and_loop_forever()

webull-python-sdk-demos/tests/tradehk/test_api.py

+9-13
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
from webullsdkmdata.common.category import Category
66
from webullsdktradehk.api import API
77

8-
98
optional_api_endpoint = "<api_endpoint>"
109
your_app_key = "<your_app_key>"
1110
your_app_secret = "<your_app_secret>"
1211
account_id = "<your_account_id>"
13-
api_client = ApiClient(your_app_key, your_app_secret,'hk')
14-
api_client.add_endpoint('us', optional_api_endpoint)
12+
api_client = ApiClient(your_app_key, your_app_secret, 'hk')
13+
api_client.add_endpoint('hk', optional_api_endpoint)
1514

1615

1716
class TestApi(unittest.TestCase):
@@ -35,13 +34,13 @@ def test_api(self):
3534
res = api.instrument.get_trade_instrument_detail("913244615")
3635
if res.status_code == 200:
3736
print(res.json())
38-
res = api.market_data.get_quote('AAPL','US_STOCK')
37+
res = api.market_data.get_snapshot('AAPL', 'US_STOCK')
3938
if res.status_code == 200:
4039
print('us stock quote:', res.json())
41-
res = api.market_data.get_quote('00700', 'HK_STOCK')
40+
res = api.market_data.get_snapshot('00700', 'HK_STOCK')
4241
if res.status_code == 200:
4342
print('hk stock quote:', res.json())
44-
res = api.market_data.get_quote('600000', 'CN_STOCK')
43+
res = api.market_data.get_snapshot('600000', 'CN_STOCK')
4544
if res.status_code == 200:
4645
print('cn stock quote:', res.json())
4746
res = api.market_data.get_history_bar('AAPL', 'US_STOCK', 'M1')
@@ -62,11 +61,11 @@ def test_api(self):
6261
res = api.account.get_account_position(account_id)
6362
if res.status_code == 200:
6463
print('account position:', res.json())
65-
res = api.account.get_account_balance(account_id,'HKD')
64+
res = api.account.get_account_balance(account_id, 'HKD')
6665
if res.status_code == 200:
6766
print('account balance:', res.json())
6867
client_order_id = uuid.uuid4().hex
69-
print('client order id:',client_order_id)
68+
print('client order id:', client_order_id)
7069
stock_order = {
7170
"account_id": account_id,
7271
"stock_order": {
@@ -155,15 +154,12 @@ def test_api(self):
155154
res = api.order.list_open_orders(account_id, page_size=20)
156155
if res.status_code == 200:
157156
print('open orders:', res.json())
158-
res = api.order.list_today_orders(account_id,page_size=20)
157+
res = api.order.list_today_orders(account_id, page_size=20)
159158
if res.status_code == 200:
160159
print('today orders', res.json())
161160
res = api.order.query_order_detail(account_id, client_order_id)
162161
if res.status_code == 200:
163-
print('order detail:',res.json())
162+
print('order detail:', res.json())
164163
res = api.order.cancel_order(account_id, client_order_id)
165164
if res.status_code == 200:
166165
print('cancel order status:', res.json())
167-
168-
169-

webull-python-sdk-demos/webullsdkdemos/mdata/get_quote_request.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@
1818
# coding=utf-8
1919
from webullsdkcore.client import ApiClient
2020
from webullsdkmdata.common.category import Category
21-
from webullsdkmdata.request.get_quote_request import GetQuoteRequest
21+
from webullsdkmdata.request.get_snapshot_request import GetSnapshotRequest
2222

2323
if __name__ == '__main__':
2424
your_app_key = "<your_app_key>"
2525
your_app_secret = "<your_app_secret>"
2626
region_id = "hk"
2727
optional_api_endpoint = "<api_endpoint>"
2828
api_client = ApiClient(your_app_key, your_app_secret, region_id)
29-
request = GetQuoteRequest()
29+
request = GetSnapshotRequest()
3030
request.set_endpoint(optional_api_endpoint)
3131
request.set_category(Category.US_STOCK.name)
3232
request.set_symbols("AAPL")

webull-python-sdk-mdata/__init__.py

Whitespace-only changes.

webull-python-sdk-mdata/setup.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
LONG_DESCRIPTION = fp.read()
1616

1717
requires = [
18-
"webull-python-sdk-core==0.1.1",
19-
"webull-python-sdk-quotes-core==0.1.1"
18+
"webull-python-sdk-core==0.1.2",
19+
"webull-python-sdk-quotes-core==0.1.2"
2020
]
2121

2222
setup_args = {
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# coding=utf-8
22

3-
__version__ = '0.1.1'
3+
__version__ = '0.1.2'

webull-python-sdk-mdata/webullsdkmdata/common/subscribe_type.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
# coding=utf-8
1919
from webullsdkcore.common.easy_enum import EasyEnum
20+
21+
2022
class SubscribeType(EasyEnum):
21-
BASIC_QUOTE = (1, "BASIC QUOTE")
22-
SNAPSHOT = (2, "SNAPSHOT")
23+
QUOTE = (0, "QUOTE")
24+
SNAPSHOT = (1, "SNAPSHOT")
25+
TICK = (2, "TICK")

webull-python-sdk-mdata/webullsdkmdata/quotes/grpc/instrument.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@
1414
# KIND, either express or implied. See the License for the
1515
# specific language governing permissions and limitations
1616
# under the License.
17-
import logging
1817

1918
from webullsdkmdata.quotes.grpc.pb import quote_pb2
2019
from webullsdkmdata.quotes.grpc.response import Response
2120
from webullsdkmdata.request.grpc.get_instruments_request import GetInstrumentsRequest
2221

22+
2323
class Instrument:
2424
def __init__(self, grpc_client):
2525
self.client = grpc_client
2626

2727
def get_instrument(self, symbols, category):
2828
request = GetInstrumentsRequest(symbols, category)
2929
result = self.client.get_response(request.get_path(), request.serialize())
30-
return Response(result, quote_pb2.TickerResponse())
30+
return Response(result, quote_pb2.InstrumentResponse())

webull-python-sdk-mdata/webullsdkmdata/quotes/grpc/market_data.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@
1414
# KIND, either express or implied. See the License for the
1515
# specific language governing permissions and limitations
1616
# under the License.
17-
import logging
1817

1918
from webullsdkmdata.quotes.grpc.pb import quote_pb2
2019
from webullsdkmdata.quotes.grpc.response import Response
2120
from webullsdkmdata.request.grpc.get_historical_bars_request import GetHistoricalBarsRequest
2221
from webullsdkmdata.request.grpc.get_quote_request import GetQuoteRequest
22+
from webullsdkmdata.request.grpc.get_snapshot_request import GetSnapshotRequest
2323
from webullsdkmdata.request.grpc.get_streaming_token_request import GetStreamingTokenRequest
2424
from webullsdkmdata.request.grpc.quotes_subscribe_request import SubscribeRequest
2525
from webullsdkmdata.request.grpc.quotes_unsubscribe_request import UnsubcribeRequest
26+
from webullsdkmdata.request.grpc.get_tick_request import GetTickRequest
2627

2728

2829
class MarketData:
@@ -49,7 +50,17 @@ def get_history_bar(self, symbol, category, timespan, count='200'):
4950
result = self.client.get_response(request.get_path(), request.serialize())
5051
return Response(result, quote_pb2.BarsResponse())
5152

52-
def get_quote(self, symbols, category):
53-
request = GetQuoteRequest(symbols, category)
53+
def get_quote(self, symbol, category):
54+
request = GetQuoteRequest(symbol, category)
5455
result = self.client.get_response(request.get_path(), request.serialize())
55-
return Response(result, quote_pb2.QuotesResponse())
56+
return Response(result, quote_pb2.QuoteResponse())
57+
58+
def get_snapshot(self, symbols, category):
59+
request = GetSnapshotRequest(symbols, category)
60+
result = self.client.get_response(request.get_path(), request.serialize())
61+
return Response(result, quote_pb2.SnapshotResponse())
62+
63+
def get_tick(self, symbol, category, count='30'):
64+
request = GetTickRequest(symbol, category, count)
65+
result = self.client.get_response(request.get_path(), request.serialize())
66+
return Response(result, quote_pb2.TickResponse())

0 commit comments

Comments
 (0)