Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Webull OpenAPI Python SDK
Note: This is the new version of the Webull SDK, currently applicable only to Webull Hong Kong or Webull US customers.

Webull OpenAPI aims to provide quantitative trading investors with convenient, fast and secure services. Webull aims to help every quant traders achieve flexible and changeable trading or market strategies.

Expand Down
2 changes: 1 addition & 1 deletion samples/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '2.0.1'
__version__ = '2.0.2'
2 changes: 1 addition & 1 deletion samples/data/data_streaming_client_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def my_connect_success_func(client, api_client, quotes_session_id):
print("connect success with session_id:%s" % quotes_session_id)
# subscribe
symbols = ['KXNHLGAME-26JAN21ANACOL-ANA', 'KXNBAGAME-26JAN20LACCHI-LAC']
sub_types = [SubscribeType.QUOTE.name, SubscribeType.SNAPSHOT.name]
sub_types = [SubscribeType.QUOTE.name, SubscribeType.SNAPSHOT.name, SubscribeType.TICK.name]
client.subscribe(symbols, Category.US_EVENT.name, sub_types)

def my_quotes_message_func(client, topic, quotes):
Expand Down
2 changes: 2 additions & 0 deletions samples/trade/trade_client_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@
# ============================================================

# normal option order
# position_intent: Currently, only the US market is supported, and only options orders are allowed.
normal_option_client_order_id = uuid.uuid4().hex
new_normal_option_orders = [
{
Expand All @@ -259,6 +260,7 @@
"side": "BUY",
"time_in_force": "GTC",
"entrust_type": "QTY",
"position_intent": "BUY_TO_OPEN",
"legs": [
{
"side": "BUY",
Expand Down
2 changes: 1 addition & 1 deletion webull/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '2.0.1'
__version__ = '2.0.2'
2 changes: 1 addition & 1 deletion webull/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '2.0.1'
__version__ = '2.0.2'

import logging

Expand Down
2 changes: 1 addition & 1 deletion webull/core/auth/composer/default_signature_composer.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def _build_sign_string(sign_params, uri, body_string):
if string_to_sign:
string_to_sign = string_to_sign + PARAMS_JOIN + PARAMS_JOIN.join(sorted_array)
else:
string_to_sign = PARAM_KV_JOIN.join(sorted_array)
string_to_sign = PARAMS_JOIN.join(sorted_array)
if body_string:
string_to_sign = string_to_sign + PARAMS_JOIN + body_string
# All characters except alphabetic characters, digits, -, ., _, ~ will be encoded as %XX.
Expand Down
2 changes: 1 addition & 1 deletion webull/data/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# coding=utf-8

__version__ = '2.0.1'
__version__ = '2.0.2'
4 changes: 3 additions & 1 deletion webull/data/data_streaming_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
from webull.data.quotes.market_streaming_data import MarketDataStreaming
from webull.data.quotes.subscribe.event_depth_decoder import EventDepthDecoder
from webull.data.quotes.subscribe.event_snapshot_decoder import EventSnapshotDecoder
from webull.data.quotes.subscribe.event_tick_decoder import EventTickDecoder
from webull.data.quotes.subscribe.payload_type import PAYLOAD_TYPE_QUOTE, PAYLOAD_TYPE_SHAPSHOT, PAYLOAD_TYPE_TICK, \
PAYLOAD_TYPE_EVENT_SHAPSHOT, PAYLOAD_TYPE_EVENT_DEPTH
PAYLOAD_TYPE_EVENT_SHAPSHOT, PAYLOAD_TYPE_EVENT_DEPTH, PAYLOAD_TYPE_EVENT_TICK
from webull.data.quotes.subscribe.quote_decoder import QuoteDecoder
from webull.data.quotes.subscribe.snapshot_decoder import SnapshotDecoder
from webull.data.quotes.subscribe.tick_decoder import TickDecoder
Expand All @@ -44,6 +45,7 @@ def __init__(self, app_key, app_secret, region_id, session_id, http_host=None,
self.register_payload_decoder(PAYLOAD_TYPE_TICK, TickDecoder())
self.register_payload_decoder(PAYLOAD_TYPE_EVENT_DEPTH, EventDepthDecoder())
self.register_payload_decoder(PAYLOAD_TYPE_EVENT_SHAPSHOT, EventSnapshotDecoder())
self.register_payload_decoder(PAYLOAD_TYPE_EVENT_TICK, EventTickDecoder())

@property
def on_connect_success(self):
Expand Down
30 changes: 30 additions & 0 deletions webull/data/quotes/subscribe/event_tick_decoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright 2022 Webull
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# coding=utf-8

from webull.data.quotes.subscribe.message_pb2 import EventTick
from webull.data.quotes.subscribe.event_tick_result import EventTickResult

from webull.data.internal.quotes_payload_decoder import BaseQuotesPayloadDecoder



class EventTickDecoder(BaseQuotesPayloadDecoder):
def __init__(self):
super().__init__()

def parse(self, payload):
eventTick = EventTick()
eventTick.ParseFromString(payload)
return EventTickResult(eventTick)
56 changes: 56 additions & 0 deletions webull/data/quotes/subscribe/event_tick_result.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright 2022 Webull
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# coding=utf-8

from decimal import Decimal
from webull.data.quotes.subscribe.basic_result import BasicResult


class EventTickResult:
def __init__(self, pb_event_tick):
self.basic = BasicResult(pb_event_tick.basic)
self.time = pb_event_tick.time
self.yes_price = Decimal(pb_event_tick.yes_price) if pb_event_tick.yes_price else None
self.no_price = Decimal(pb_event_tick.no_price) if pb_event_tick.no_price else None
self.volume = pb_event_tick.volume
self.side = pb_event_tick.side
self.trade_id = pb_event_tick.trade_id

def get_basic(self):
return self.basic

def get_time(self):
return self.time

def get_yes_price(self):
return self.yes_price

def get_no_price(self):
return self.no_price

def get_volume(self):
return self.volume

def get_side(self):
return self.side

def get_trade_id(self):
return self.trade_id

def __repr__(self):
return "basic: %s,time: %s,yes_price: %s,no_price:%s,volume:%s,side:%s,trade_id:%s" % (self.basic, self.time, self.yes_price, self.no_price, self.volume, self.side, self.trade_id)

def __str__(self):
return self.__repr__()
10 changes: 10 additions & 0 deletions webull/data/quotes/subscribe/message.proto
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,14 @@ message EventQuote {
message EventAskBid {
string price = 1;
string size = 2;
}

message EventTick {
Basic basic = 1;
string yes_price = 2;
string no_price = 3;
string volume = 4;
string side = 5;
string trade_id = 6;
string time = 7;
}
4 changes: 3 additions & 1 deletion webull/data/quotes/subscribe/message_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion webull/data/quotes/subscribe/payload_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@
PAYLOAD_TYPE_SHAPSHOT = 'snapshot'
PAYLOAD_TYPE_TICK = 'tick'
PAYLOAD_TYPE_EVENT_DEPTH = 'event-quote'
PAYLOAD_TYPE_EVENT_SHAPSHOT = 'event-snapshot'
PAYLOAD_TYPE_EVENT_SHAPSHOT = 'event-snapshot'
PAYLOAD_TYPE_EVENT_TICK = 'event-tick'
2 changes: 1 addition & 1 deletion webull/trade/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.1.0'
__version__ = '2.0.2'
24 changes: 24 additions & 0 deletions webull/trade/common/position_intent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2022 Webull
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# coding=utf-8

from webull.core.common.easy_enum import EasyEnum


class OrderStatus(EasyEnum):
BUY_TO_OPEN = (1, "BUY_TO_OPEN")
BUY_TO_CLOSE = (2, "BUY_TO_CLOSE")
SELL_TO_OPEN = (3, "SELL_TO_OPEN")
SELL_TO_CLOSE = (4, "SELL_TO_CLOSE")
6 changes: 5 additions & 1 deletion webull/trade/trade_events_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,12 @@ def __init__(self, app_key, app_secret, region_id=DEFAULT_REGION_ID, host=None,
self._on_log = None

def _build_request(self, app_key, app_secret, accounts):
if self._region_id == 'us':
subscribeType = 3
else:
subscribeType = 1
request = pb.SubscribeRequest(
subscribeType= 3, # only 1、2 allowed now
subscribeType= subscribeType, # 1、2、3 allowed now
timestamp=int(time.time() * 1000), # millis
accounts=accounts,
)
Expand Down