Skip to content

Commit a485198

Browse files
author
方佳
committed
Merge branch 'main_merge_261010' into 'main'
feat: support community-related capabilities for Webull US See merge request webull/webull-openapi-python-sdk!47
2 parents abe5668 + 790e3c9 commit a485198

14 files changed

Lines changed: 373 additions & 5 deletions

‎samples/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '3.0.2'
1+
__version__ = '3.0.3'

‎samples/data/community.py‎

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Copyright 2022 Webull
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# coding=utf-8
16+
17+
from webull.core.client import ApiClient
18+
from webull.data.common.category import Category
19+
from webull.data.data_client import DataClient
20+
21+
optional_api_endpoint = "<api_endpoint>"
22+
your_app_key = "<your_app_key>"
23+
your_app_secret = "<your_app_secret>"
24+
region_id = "<region_id>"
25+
26+
api_client = ApiClient(your_app_key, your_app_secret, region_id)
27+
api_client.add_endpoint(region_id, optional_api_endpoint)
28+
29+
30+
if __name__ == '__main__':
31+
data_client = DataClient(api_client)
32+
33+
response = data_client.community.create_post(
34+
"Hello, this is a test post from OpenAPI!",
35+
symbol="NVDA",
36+
category=Category.US_STOCK.name,
37+
)
38+
if response.status_code == 200:
39+
print('create_post:', response.json())
40+
41+
response = data_client.community.create_comment(
42+
"995005758239301632",
43+
"Hello, this is a test comment from OpenAPI!",
44+
)
45+
if response.status_code == 200:
46+
print('create_comment:', response.json())
47+
48+
response = data_client.community.list_hot_stocks()
49+
if response.status_code == 200:
50+
print('list_hot_stocks:', response.json())
51+
52+
response = data_client.community.list_posts_by_symbol("NVDA", Category.US_STOCK.name)
53+
if response.status_code == 200:
54+
print('list_posts_by_symbol:', response.json())
55+
56+
response = data_client.community.get_post("995005758239301632")
57+
if response.status_code == 200:
58+
print('get_post:', response.json())
59+
60+
response = data_client.community.list_my_posts()
61+
if response.status_code == 200:
62+
print('list_my_posts:', response.json())

‎webull/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '3.0.2'
1+
__version__ = '3.0.3'

‎webull/core/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = '3.0.2'
1+
__version__ = '3.0.3'
22

33
import logging
44

‎webull/data/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# coding=utf-8
22

3-
__version__ = '3.0.2'
3+
__version__ = '3.0.3'

‎webull/data/data_client.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from webull.data.quotes.fundamentals import Fundamentals
2828
from webull.data.quotes.screener import Screener
2929
from webull.data.quotes.watchlist import Watchlist
30+
from webull.data.quotes.community import Community
3031

3132

3233
class DataClient:
@@ -42,6 +43,7 @@ def __init__(self, api_client):
4243
self.fundamentals = Fundamentals(api_client)
4344
self.screener = Screener(api_client)
4445
self.watchlist = Watchlist(api_client)
46+
self.community = Community(api_client)
4547

4648
def _init_logger(self, api_client):
4749
# No logger configured, using default console and local file logging.

‎webull/data/quotes/community.py‎

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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.request.create_comment_request import CreateCommentRequest
18+
from webull.data.request.create_post_request import CreatePostRequest
19+
from webull.data.request.get_post_request import GetPostRequest
20+
from webull.data.request.list_hot_stocks_request import ListHotStocksRequest
21+
from webull.data.request.list_my_posts_request import ListMyPostsRequest
22+
from webull.data.request.list_posts_by_symbol_request import ListPostsBySymbolRequest
23+
24+
25+
class Community:
26+
"""Community API operations."""
27+
28+
def __init__(self, api_client):
29+
self.client = api_client
30+
31+
def create_post(self, text, symbol=None, category=None):
32+
"""
33+
Create a plain-text community post.
34+
35+
:param text: Post content.
36+
:param symbol: Optional ticker symbol. Provide it with category.
37+
:param category: Optional ticker market category. Provide it with symbol.
38+
:return: Response containing the created post identifier.
39+
"""
40+
request = CreatePostRequest()
41+
request.set_text(text)
42+
request.set_symbol(symbol)
43+
request.set_category(category)
44+
return self.client.get_response(request)
45+
46+
def create_comment(self, post_id, text):
47+
"""
48+
Create a plain-text comment on an existing community post.
49+
50+
:param post_id: Parent post identifier.
51+
:param text: Comment content.
52+
:return: Response containing the created comment identifier.
53+
"""
54+
request = CreateCommentRequest()
55+
request.set_post_id(post_id)
56+
request.set_text(text)
57+
return self.client.get_response(request)
58+
59+
def list_hot_stocks(self):
60+
"""
61+
List stocks ranked by community activity.
62+
63+
:return: Response containing hot stock ranking entries.
64+
"""
65+
request = ListHotStocksRequest()
66+
return self.client.get_response(request)
67+
68+
def list_posts_by_symbol(self, symbol, category, keyword=None, pagination_key=None):
69+
"""
70+
List community posts associated with a symbol.
71+
72+
:param symbol: Stock symbol.
73+
:param category: Market category.
74+
:param keyword: Optional search keyword.
75+
:param pagination_key: Optional key from the previous response.
76+
:return: Paginated post list response.
77+
"""
78+
request = ListPostsBySymbolRequest()
79+
request.set_symbol(symbol)
80+
request.set_category(category)
81+
request.set_keyword(keyword)
82+
request.set_pagination_key(pagination_key)
83+
return self.client.get_response(request)
84+
85+
def get_post(self, post_id):
86+
"""
87+
Get detailed information for a community post.
88+
89+
:param post_id: Post identifier.
90+
:return: Post detail response.
91+
"""
92+
request = GetPostRequest()
93+
request.set_post_id(post_id)
94+
return self.client.get_response(request)
95+
96+
def list_my_posts(self, pagination_key=None):
97+
"""
98+
List posts created by the current user.
99+
100+
:param pagination_key: Optional key from the previous response.
101+
:return: Paginated post list response.
102+
"""
103+
request = ListMyPostsRequest()
104+
request.set_pagination_key(pagination_key)
105+
return self.client.get_response(request)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Copyright 2022 Webull
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# coding=utf-8
16+
17+
from webull.core.request import ApiRequest
18+
19+
20+
class CreateCommentRequest(ApiRequest):
21+
"""Request for creating a plain-text comment on a community post."""
22+
23+
def __init__(self):
24+
ApiRequest.__init__(self, "/market-data/communities/comments/create", version="v3", method="POST",
25+
body_params={})
26+
27+
def set_post_id(self, post_id):
28+
"""Set the parent post identifier."""
29+
self.add_body_params("post_id", post_id)
30+
31+
def set_text(self, text):
32+
"""Set the comment text."""
33+
self.add_body_params("text", text)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2022 Webull
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# coding=utf-8
16+
17+
from webull.core.request import ApiRequest
18+
19+
20+
class CreatePostRequest(ApiRequest):
21+
"""Request for creating a plain-text community post."""
22+
23+
def __init__(self):
24+
ApiRequest.__init__(self, "/market-data/communities/posts/create", version="v3", method="POST",
25+
body_params={})
26+
27+
def set_text(self, text):
28+
"""Set the post text."""
29+
self.add_body_params("text", text)
30+
31+
def set_symbol(self, symbol):
32+
"""Set the optional ticker symbol."""
33+
if symbol is not None:
34+
self.add_body_params("symbol", symbol)
35+
36+
def set_category(self, category):
37+
"""Set the optional ticker market category."""
38+
if category is not None:
39+
self.add_body_params("category", category)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright 2022 Webull
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# coding=utf-8
16+
17+
from webull.core.request import ApiRequest
18+
19+
20+
class GetPostRequest(ApiRequest):
21+
"""Request for retrieving a community post by identifier."""
22+
23+
def __init__(self):
24+
ApiRequest.__init__(self, "/market-data/communities/posts/get", version="v3", method="GET",
25+
query_params={})
26+
27+
def set_post_id(self, post_id):
28+
"""Set the post identifier."""
29+
self.add_query_param("post_id", post_id)

0 commit comments

Comments
 (0)