Skip to content

Commit c218b48

Browse files
committed
Merge branch 'dev' into 'master'
Dev->master See merge request !46
2 parents 80e14d4 + a8ac9c5 commit c218b48

File tree

15 files changed

+272
-33
lines changed

15 files changed

+272
-33
lines changed

requirements.txt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
six
2-
simplejson
3-
delorean
1+
six==1.13.0
2+
simplejson==3.17.0
3+
delorean==1.0.0
44
pandas==0.24.2
5-
python-dateutil
6-
pytz
5+
python-dateutil==2.8.1
6+
pytz==2019.3
77
pyasn1==0.4.2
88
rsa==4.0
9-
stomp.py
9+
stomp.py==4.1.22
10+
enum34==1.1.6

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
from os import path
88
from setuptools import find_packages, setup
99

10-
with open(path.join(path.abspath(path.dirname(__file__)), 'requirements.txt'), encoding='utf-8') as f:
10+
with open(path.join(path.abspath(path.dirname(__file__)), 'requirements.txt')) as f:
1111
install_requires = f.read()
1212

1313
setup(
1414
name='tigeropen',
15-
version='1.1.9',
15+
version='1.1.10',
1616
description='TigerBrokers Open API',
1717
packages=find_packages(exclude=[]),
1818
author='TigerBrokers',

tigeropen/common/consts/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,4 @@ class CorporateActionType(Enum):
132132
"""
133133
SPLIT = 'split' # 拆合股
134134
DIVIDEND = 'dividend' # 分红
135+
EARNINGS_CALENDAR = 'earning' # 财报日历

tigeropen/common/consts/push_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,5 @@ class ResponseType(Enum):
6060
GET_SUB_SYMBOLS_END = 111
6161
GET_SUBSCRIBE_END = 112
6262
GET_CANCEL_SUBSCRIBE_END = 113
63+
64+
ERROR_END = 200

tigeropen/common/util/order_utils.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
@author: gaoan
66
"""
7-
from tigeropen.trade.domain.order import Order
7+
from tigeropen.trade.domain.order import Order, OrderLeg
88
from tigeropen.common.consts import OrderStatus
99

1010

@@ -74,6 +74,33 @@ def trail_order(account, contract, action, quantity, trailing_percent=None, aux_
7474
return Order(account, contract, action, 'TRAIL', quantity, trailing_percent=trailing_percent, aux_price=aux_price)
7575

7676

77+
def order_leg(leg_type, price, time_in_force='DAY', outside_rth=None):
78+
"""
79+
附加订单
80+
:param leg_type: 附加订单类型. PROFIT 止盈单类型, LOSS 止损单类型
81+
:param price: 附加订单价格.
82+
:param time_in_force: 附加订单有效期. 'DAY'(当日有效)和'GTC'(取消前有效 Good-Til-Canceled).
83+
:param outside_rth: 附加订单是否允许盘前盘后交易(美股专属). True 允许, False 不允许.
84+
"""
85+
return OrderLeg(leg_type=leg_type, price=price, time_in_force=time_in_force, outside_rth=outside_rth)
86+
87+
88+
def limit_order_with_legs(account, contract, action, quantity, limit_price, order_legs=None):
89+
"""
90+
限价单 + 附加订单(仅环球账户支持)
91+
:param account:
92+
:param contract:
93+
:param action: BUY/SELL
94+
:param quantity:
95+
:param limit_price: 限价单价格
96+
:param order_legs: 附加订单列表
97+
:return:
98+
"""
99+
if order_legs and len(order_legs) > 2:
100+
raise Exception('2 order legs at most')
101+
return Order(account, contract, action, 'LMT', quantity, limit_price=limit_price, order_legs=order_legs)
102+
103+
77104
def get_order_status(value):
78105
"""
79106
Invalid(-2), Initial(-1), PendingCancel(3), Cancelled(4), Submitted(5), Filled(6), Inactive(7), PendingSubmit(8)

tigeropen/examples/push_client_demo.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,24 @@ def on_position_changed(account, items):
9090
print(account, items)
9191

9292

93+
def subscribe_callback(destination, content):
94+
"""
95+
订阅成功与否的回调
96+
:param destination: 订阅的类型. 有 quote, trade/asset, trade/position, trade/order
97+
:param content: 回调信息. 如成功 {'code': 0, 'message': 'success'}; 若失败则 code 不为0, message 为错误详情
98+
"""
99+
print('subscribe:{}, callback content:{}'.format(destination, content))
100+
101+
102+
def unsubscribe_callback(destination, content):
103+
"""
104+
退订成功与否的回调
105+
:param destination: 取消订阅的类型. 有 quote, trade/asset, trade/position, trade/order
106+
:param content: 回调信息.
107+
"""
108+
print('subscribe:{}, callback content:{}'.format(destination, content))
109+
110+
93111
# def connect_callback():
94112
# """连接建立回调"""
95113
# print('connected')
@@ -126,9 +144,14 @@ def on_position_changed(account, items):
126144
# 持仓变动回调
127145
# push_client.position_changed = on_position_changed
128146

147+
# 订阅成功与否的回调
148+
push_client.subscribe_callback = subscribe_callback
149+
# 退订成功与否的回调
150+
push_client.unsubscribe_callback = unsubscribe_callback
151+
129152
# 建立推送连接
130153
push_client.connect(client_config.tiger_id, client_config.private_key)
131-
# 断线重连
154+
# 断线重连回调
132155
# push_client.disconnect_callback = disconnect_callback
133156

134157
# 订阅行情

tigeropen/examples/quote_client_demo.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ def get_fundamental():
104104
end_date='2019-01-01')
105105
print(corporate_dividend)
106106

107+
# 财报日历
108+
earnings_calendar = openapi_client.get_corporate_earnings_calendar(Market.US, '2020-01-01', '2020-02-01')
109+
print(earnings_calendar)
110+
107111

108112
if __name__ == '__main__':
109113
with pd.option_context('display.max_rows', None, 'display.max_columns', None):

tigeropen/examples/trade_client_demo.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
from tigeropen.trade.trade_client import TradeClient
1515
from tigeropen.quote.request import OpenApiRequest
1616
from tigeropen.examples.client_config import get_client_config
17-
# from tigeropen.common.util.contract_utils import stock_contract, option_contract, future_contract
18-
# from tigeropen.common.util.order_utils import limit_order
17+
# from tigeropen.common.util.contract_utils import stock_contract, option_contract_by_symbol, future_contract, \
18+
# war_contract_by_symbol, iopt_contract_by_symbol
19+
from tigeropen.common.util.order_utils import limit_order, limit_order_with_legs, order_leg
1920

2021
logging.basicConfig(level=logging.INFO,
2122
format='%(asctime)s %(levelname)s %(message)s',
@@ -96,6 +97,22 @@ def trade_apis():
9697
result = openapi_client.preview_order(order)
9798
print(result)
9899

100+
# 限价单 + 附加订单 (仅主订单为限价单时支持附加订单)
101+
stop_loss_order_leg = order_leg('LOSS', 8.0, time_in_force='GTC') # 附加止损
102+
profit_taker_order_leg = order_leg('PROFIT', 12.0, time_in_force='GTC') # 附加止盈
103+
104+
main_order = openapi_client.create_order(account, contract, 'BUY', 'LMT', quantity=100, limit_price=10.0,
105+
order_legs=[stop_loss_order_leg, profit_taker_order_leg])
106+
# 本地构造限价单 + 附加订单
107+
# main_order = limit_order_with_legs(account, contract, 'BUY', 100, limit_price=10.0,
108+
# order_legs=[stop_loss_order_leg])
109+
110+
openapi_client.place_order(main_order)
111+
print(main_order)
112+
# 查询主订单所关联的附加订单
113+
order_legs = openapi_client.get_open_orders(account, parent_id=main_order.order_id)
114+
print(order_legs)
115+
99116

100117
if __name__ == '__main__':
101118
get_account_info()
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# -*- coding: utf-8 -*-
2+
from itertools import chain
3+
4+
import pandas as pd
5+
from tigeropen.common.response import TigerResponse
6+
7+
COLUMNS = ['symbol', 'reportDate', 'reportTime', 'executeDate', 'expectedEps', 'actualEps',
8+
'fiscalQuarterEnding', 'market', 'exchange', 'actionType']
9+
EARNINGS_CALENDAR_FIELD_MAPPINGS = {'actionType': 'action_type', 'actualEps': 'actual_eps',
10+
'expectedEps': 'expected_eps', 'executeDate': 'execute_date',
11+
'fiscalQuarterEnding': 'fiscal_quarter_ending', 'reportDate': 'report_date',
12+
'reportTime': 'report_time',
13+
}
14+
15+
16+
class EarningsCalendarResponse(TigerResponse):
17+
def __init__(self):
18+
super(EarningsCalendarResponse, self).__init__()
19+
self.earnings_calendar = None
20+
self._is_success = None
21+
22+
def parse_response_content(self, response_content):
23+
response = super(EarningsCalendarResponse, self).parse_response_content(response_content)
24+
if 'is_success' in response:
25+
self._is_success = response['is_success']
26+
27+
if self.data:
28+
self.earnings_calendar = pd.DataFrame(chain.from_iterable(self.data.values()), columns=COLUMNS).rename(
29+
columns=EARNINGS_CALENDAR_FIELD_MAPPINGS).sort_values(by=['report_date']).reset_index(drop=True)

tigeropen/push/push_client.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ def __init__(self, host, port, use_ssl=True, connection_timeout=120, auto_reconn
7777
self._asset_counter = 0
7878
self._position_counter = 0
7979
self._order_counter = 0
80-
# self.subscriptions = {} # subscription callbacks indexed by subscriber's ID
8180

8281
self.subscribed_symbols = None
8382
self.quote_changed = None
@@ -86,6 +85,8 @@ def __init__(self, host, port, use_ssl=True, connection_timeout=120, auto_reconn
8685
self.order_changed = None
8786
self.connect_callback = None
8887
self.disconnect_callback = None
88+
self.subscribe_callback = None
89+
self.unsubscribe_callback = None
8990
self.error_callback = None
9091
self._connection_timeout = connection_timeout
9192
self._auto_reconnect = auto_reconnect
@@ -226,11 +227,21 @@ def on_message(self, headers, body):
226227
items.append((ORDER_KEYS_MAPPINGS.get(key), value))
227228
if items:
228229
self.order_changed(account, items)
230+
elif response_type == str(ResponseType.GET_SUBSCRIBE_END.value):
231+
if self.subscribe_callback:
232+
self.subscribe_callback(headers.get('destination'), json.loads(body))
233+
elif response_type == str(ResponseType.GET_CANCEL_SUBSCRIBE_END.value):
234+
if self.unsubscribe_callback:
235+
self.unsubscribe_callback(headers.get('destination'), json.loads(body))
236+
elif response_type == str(ResponseType.ERROR_END.value):
237+
if self.error_callback:
238+
self.error_callback(body)
229239
except Exception as e:
230240
logging.error(e, exc_info=True)
231241

232242
def on_error(self, headers, body):
233-
pass
243+
if self.error_callback:
244+
self.error_callback(body)
234245

235246
@staticmethod
236247
def _get_subscribe_id(counter):

0 commit comments

Comments
 (0)