Skip to content

Commit 750cc1c

Browse files
committed
Merge branch 'dev' into 'master'
Dev-master See merge request server/openapi/openapi-python-sdk!64
2 parents fa35f41 + ed4f000 commit 750cc1c

File tree

14 files changed

+311
-19
lines changed

14 files changed

+311
-19
lines changed

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
six==1.13.0
22
simplejson==3.17.0
33
delorean==1.0.0
4-
pandas==0.24.2
4+
pandas==0.25.3
55
python-dateutil==2.8.1
66
pytz==2019.3
77
pyasn1==0.4.2
88
rsa==4.0
99
stomp.py==4.1.22
10-
enum34==1.1.6
10+
enum34==1.1.6

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

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

tigeropen/common/consts/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class Market(Enum):
3131
US = 'US' # 美股
3232
HK = 'HK' # 港股
3333
CN = 'CN' # A股
34+
SG = 'SG' # 新加坡
3435

3536

3637
@unique
@@ -62,6 +63,7 @@ class Currency(Enum):
6263
USD = 'USD' # 美元
6364
HKD = 'HKD' # 港币
6465
CNH = 'CNH' # 离岸人民币
66+
SGD = 'SGD' # 新加坡币
6567

6668

6769
@unique

tigeropen/common/util/order_utils.py

Lines changed: 31 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, OrderLeg
7+
from tigeropen.trade.domain.order import Order, OrderLeg, AlgoParams
88
from tigeropen.common.consts import OrderStatus
99

1010

@@ -101,6 +101,36 @@ def limit_order_with_legs(account, contract, action, quantity, limit_price, orde
101101
return Order(account, contract, action, 'LMT', quantity, limit_price=limit_price, order_legs=order_legs)
102102

103103

104+
def algo_order_params(start_time=None, end_time=None, no_take_liq=None, allow_past_end_time=None, participation_rate=None):
105+
"""
106+
算法订单参数
107+
:param start_time: 生效开始时间(时间戳 TWAP和VWAP专用)
108+
:param end_time: 生效结束时间(时间戳 TWAP和VWAP专用)
109+
:param no_take_liq: 是否尽可能减少交易次数(VWAP订单专用)
110+
:param allow_past_end_time: 是否允许生效时间结束后继续完成成交(TWAP和VWAP专用)
111+
:param participation_rate: 参与率(VWAP专用,0.01-0.5)
112+
:return:
113+
"""
114+
return AlgoParams(start_time=start_time, end_time=end_time, no_take_liq=no_take_liq,
115+
allow_past_end_time=allow_past_end_time, participation_rate=participation_rate)
116+
117+
118+
def algo_order(account, contract, action, quantity, strategy, algo_params=None, limit_price=None):
119+
"""
120+
算法订单
121+
:param account:
122+
:param contract:
123+
:param action:
124+
:param quantity:
125+
:param strategy: 交易量加权平均价格(VWAP)/时间加权平均价格(TWAP)
126+
:param algo_params: tigeropen.trade.domain.order.AlgoParams
127+
:param limit_price:
128+
:return:
129+
"""
130+
return Order(account, contract, action, order_type=strategy, quantity=quantity, algo_params=algo_params,
131+
limit_price=limit_price, outside_rth=False)
132+
133+
104134
def get_order_status(value):
105135
"""
106136
Invalid(-2), Initial(-1), PendingCancel(3), Cancelled(4), Submitted(5), Filled(6), Inactive(7), PendingSubmit(8)

tigeropen/common/util/web_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def do_post(url, query_string=None, headers=None, params=None, timeout=15, chars
6868
response = connection.getresponse()
6969
result = response.read()
7070

71-
if response.status is not 200:
71+
if response.status != 200:
7272
if PYTHON_VERSION_3 and charset:
7373
result = result.decode(charset)
7474
raise ResponseException('[' + THREAD_LOCAL.uuid + ']invalid http status ' + str(response.status) +

tigeropen/examples/quote_client_demo.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ def get_quote():
3939
print(ticks)
4040
short_interest = openapi_client.get_short_interest(['GOOG', 'AAPL', '00700'])
4141
print(short_interest)
42+
# 股票详情
43+
stock_details = openapi_client.get_stock_details(['AAPL', '03690'])
44+
print(stock_details)
4245

4346

4447
def get_option_quote():

tigeropen/examples/trade_client_demo.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
from tigeropen.quote.request import OpenApiRequest
1616
from tigeropen.examples.client_config import get_client_config
1717
# from tigeropen.common.consts import Currency, SecurityType
18-
# from tigeropen.common.util.contract_utils import stock_contract, option_contract_by_symbol, future_contract, \
19-
# war_contract_by_symbol, iopt_contract_by_symbol
20-
from tigeropen.common.util.order_utils import limit_order, limit_order_with_legs, order_leg
18+
from tigeropen.common.util.contract_utils import stock_contract, option_contract_by_symbol, future_contract, \
19+
war_contract_by_symbol, iopt_contract_by_symbol
20+
from tigeropen.common.util.order_utils import limit_order, limit_order_with_legs, order_leg, algo_order_params, \
21+
algo_order
2122

2223
logging.basicConfig(level=logging.INFO,
2324
format='%(asctime)s %(levelname)s %(message)s',
@@ -122,6 +123,17 @@ def trade_apis():
122123
print(order_legs)
123124

124125

126+
def algo_order_demo():
127+
account = client_config.account
128+
openapi_client = TradeClient(client_config, logger=logger)
129+
contract = stock_contract(symbol='AAPL', currency='USD')
130+
params = algo_order_params(start_time='2020-11-19 23:00:00', end_time='2020-11-19 23:50:00', no_take_liq=True,
131+
allow_past_end_time=True, participation_rate=0.1)
132+
order = algo_order(account, contract, 'BUY', 1000, 'VWAP', algo_params=params, limit_price=100.0)
133+
openapi_client.place_order(order)
134+
print(order)
135+
136+
125137
if __name__ == '__main__':
126138
get_account_info()
127139
get_account_apis()

tigeropen/push/push_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
'latestTime': 'trade_time', 'contractId': 'contract_id', 'trailStopPrice': 'trail_stop_price',
4848
'trailingPercent': 'trailing_percent', 'percentOffset': 'percent_offset', 'action': 'action',
4949
'status': 'status', 'currency': 'currency', 'remaining': 'remaining', 'id': 'id',
50-
'segment': 'segment', 'identifier': 'identifier'}
50+
'segment': 'segment', 'identifier': 'identifier', 'replaceStatus': 'replace_status'}
5151

5252
if sys.platform == 'linux' or sys.platform == 'linux2':
5353
KEEPALIVE = True

tigeropen/quote/quote_client.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from tigeropen.quote.response.quote_timeline_response import QuoteTimelineResponse
3636
from tigeropen.quote.response.quote_brief_response import QuoteBriefResponse
3737
from tigeropen.quote.response.stock_briefs_response import StockBriefsResponse
38+
from tigeropen.quote.response.stock_details_response import StockDetailsResponse
3839
from tigeropen.quote.response.stock_short_interest_response import ShortInterestResponse
3940
from tigeropen.quote.response.stock_trade_meta_response import TradeMetaResponse
4041
from tigeropen.quote.response.symbol_names_response import SymbolNamesResponse
@@ -51,7 +52,7 @@
5152
OPTION_KLINE, OPTION_TRADE_TICK, FUTURE_KLINE, FUTURE_TICK, FUTURE_CONTRACT_BY_EXCHANGE_CODE, \
5253
FUTURE_TRADING_DATE, QUOTE_SHORTABLE_STOCKS, FUTURE_REAL_TIME_QUOTE, \
5354
FUTURE_CURRENT_CONTRACT, QUOTE_REAL_TIME, QUOTE_STOCK_TRADE, FINANCIAL_DAILY, FINANCIAL_REPORT, CORPORATE_ACTION, \
54-
INDUSTRY_LIST, INDUSTRY_STOCKS, STOCK_INDUSTRY
55+
INDUSTRY_LIST, INDUSTRY_STOCKS, STOCK_INDUSTRY, STOCK_DETAIL
5556
from tigeropen.common.consts import Market, Language, QuoteRight, BarPeriod
5657
from tigeropen.common.util.contract_utils import extract_option_info
5758
from tigeropen.common.util.common_utils import eastern
@@ -204,7 +205,7 @@ def get_stock_briefs(self, symbols, lang=None):
204205
"""
205206
获取股票实时行情
206207
:param symbols: 股票代号列表
207-
:param lang: 语言支持: zh_CN,zh_TW,en_US
208+
:param lang: 语言支持: tigeropen.common.consts.Language: zh_CN,zh_TW,en_US
208209
:return: pandas.DataFrame. 各 column 含义如下:
209210
symbol: 证券代码
210211
ask_price: 卖一价
@@ -242,6 +243,58 @@ def get_stock_briefs(self, symbols, lang=None):
242243

243244
return None
244245

246+
def get_stock_details(self, symbols, lang=None):
247+
"""
248+
获取股票详情
249+
:param symbols: 股票代号列表
250+
:param lang: 语言支持: zh_CN,zh_TW,en_US
251+
:return: pandas.DataFrame. 各 column 含义如下:
252+
symbol: 代码
253+
market: 市场
254+
sec_type: 证券类型
255+
exchange: 交易所
256+
name: 名称
257+
shortable: 做空信息
258+
ask_price: 卖一价
259+
ask_size: 卖一量
260+
bid_price: 买一价
261+
bid_size: 买一量
262+
pre_close: 前收价
263+
latest_price: 最新价
264+
adj_pre_close: 复权后前收价
265+
latest_time: 最新成交时间
266+
volume: 成交量
267+
open: 开盘价
268+
high: 最高价
269+
low: 最低价
270+
change: 涨跌额
271+
amount: 成交额
272+
amplitude: 振幅
273+
market_status: 市场状态 (未开盘,交易中,休市等)
274+
trading_status: 0: 非交易状态 1: 盘前交易(盘前竞价) 2: 交易中 3: 盘后交易(收市竞价)
275+
float_shares: 流通股本
276+
shares: 总股本
277+
eps: 每股收益
278+
adr_rate: ADR的比例数据,非ADR的股票为None
279+
etf: 非0表示该股票是ETF,1表示不带杠杆的etf,2表示2倍杠杆etf,3表示3倍etf杠杆
280+
listing_date: 上市日期时间戳(该市场当地时间零点),该key可能不存在
281+
更多字段见 tigeropen.quote.response.stock_details_response.StockDetailsResponse
282+
"""
283+
params = MultipleQuoteParams()
284+
params.symbols = symbols
285+
params.lang = lang.value if lang else self._lang.value
286+
287+
request = OpenApiRequest(STOCK_DETAIL, biz_model=params)
288+
response_content = self.__fetch_data(request)
289+
if response_content:
290+
response = StockDetailsResponse()
291+
response.parse_response_content(response_content)
292+
if response.is_success():
293+
return response.details
294+
else:
295+
raise ApiException(response.code, response.message)
296+
return None
297+
245298
def get_timeline(self, symbols, include_hour_trading=False, begin_time=-1, lang=None):
246299
"""
247300
获取当日分时数据
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Created on 2018/10/31
4+
5+
@author: gaoan
6+
"""
7+
import json
8+
9+
import six
10+
import pandas as pd
11+
from tigeropen.common.util.string_utils import get_string
12+
from tigeropen.common.response import TigerResponse
13+
14+
# 盘前盘后
15+
HOUR_TRADING_COLUMNS = [
16+
'hour_trading_tag',
17+
'hour_trading_latest_price',
18+
'hour_trading_pre_close',
19+
'hour_trading_latest_time',
20+
'hour_trading_volume',
21+
'hour_trading_timestamp',
22+
]
23+
# 下一交易时段信息
24+
NEXT_MARKET_STATUS_COLUMNS = [
25+
# 市场状态(US:开盘、收盘、盘前交易、盘后交易||CN/HK:开盘、收盘、午间休市)
26+
'next_market_status_tag',
27+
# 开始时间
28+
'next_market_status_begin_time',
29+
]
30+
# 拆合股
31+
STOCK_SPLIT_COLUMNS = [
32+
# 执行日期 yyyy-MM-dd格式
33+
'stock_split_execute_date',
34+
# 公司行动后的因子
35+
'stock_split_to_factor',
36+
# 公司行动前的因子
37+
'stock_split_for_factor'
38+
]
39+
# 股权信息
40+
STOCK_RIGHT_COLUMNS = [
41+
# 原股权代码
42+
'stock_right_symbol',
43+
# 股权代码
44+
'stock_right_rights_symbol',
45+
# 开始交易日期, YYYY-MM-dd格式,可能为空字符串
46+
'stock_right_first_dealing_date',
47+
# 最后交易日期, YYYY-MM-dd格式,可能为空字符串
48+
'stock_right_last_dealing_date'
49+
]
50+
# 股票代码变更
51+
SYMBOL_CHANGE_COLUMNS = [
52+
# 新的股票代码
53+
'symbol_change_new_symbol',
54+
# 执行日期,yyyy-MM-dd格式
55+
'symbol_change_execute_date'
56+
]
57+
# 股票公告
58+
STOCK_NOTICE_COLUMNS = [
59+
# 公告标题
60+
'stock_notice_title',
61+
# 公告内容
62+
'stock_notice_content',
63+
# 公告类型
64+
'stock_notice_type'
65+
]
66+
67+
COLUMNS = ['symbol', 'market', 'exchange', 'sec_type', 'name', 'shortable', 'latest_price', 'pre_close',
68+
'adj_pre_close', 'trading_status', 'market_status', 'timestamp', 'latest_time',
69+
'open', 'high', 'low', 'volume', 'amount', 'ask_price', 'ask_size', 'bid_price', 'bid_size', 'change',
70+
'amplitude', 'halted', 'delay', 'float_shares', 'shares', 'eps', 'etf', 'listing_date', 'adr_rate'
71+
] + HOUR_TRADING_COLUMNS + NEXT_MARKET_STATUS_COLUMNS + STOCK_SPLIT_COLUMNS + STOCK_RIGHT_COLUMNS \
72+
+ SYMBOL_CHANGE_COLUMNS + STOCK_NOTICE_COLUMNS
73+
74+
DETAIL_FIELD_MAPPINGS = {'secType': 'sec_type', 'latestPrice': 'latest_price', 'preClose': 'pre_close',
75+
'floatShares': 'float_shares', 'marketStatus': 'market_status', 'latestTime': 'latest_time',
76+
'askPrice': 'ask_price', 'askSize': 'ask_size', 'bidPrice': 'bid_price', 'bidSize': 'bid_size',
77+
'tradingStatus': 'trading_status', 'adjPreClose': 'adj_pre_close', 'adrRate': 'adr_rate',
78+
'listingDate': 'listing_date', 'beginTime': 'begin_time',
79+
'nextMarketStatus': 'next_market_status', 'hourTrading': 'hour_trading',
80+
'stockSplit': 'stock_split', 'stockRight': 'stock_right', 'symbolChange': 'symbol_change',
81+
'executeDate': 'execute_date', 'newSymbol': 'new_symbol', 'forFactor': 'for_factor',
82+
'toFactor': 'to_factor', 'rightsSymbol': 'rights_symbol', 'stockNotice': 'stock_notice',
83+
'firstDealingDate': 'first_dealing_date', 'lastDealingDate': 'last_dealing_date'
84+
}
85+
86+
SUB_FIELDS = {
87+
# 下一交易时段信息
88+
'next_market_status',
89+
# 盘前盘后信息
90+
'hour_trading',
91+
# 拆合股
92+
'stock_split',
93+
# 股权信息
94+
'stock_right'
95+
# 股票代码变更
96+
'symbol_change',
97+
# 公告
98+
'stock_notice'
99+
}
100+
101+
102+
class StockDetailsResponse(TigerResponse):
103+
def __init__(self):
104+
super(StockDetailsResponse, self).__init__()
105+
self.details = None
106+
self._is_success = None
107+
108+
def parse_response_content(self, response_content):
109+
response = super(StockDetailsResponse, self).parse_response_content(response_content)
110+
if 'is_success' in response:
111+
self._is_success = response['is_success']
112+
if not self.data:
113+
return
114+
detail_data = []
115+
data_json = json.loads(self.data)
116+
for item in data_json.get('items', {}):
117+
item_values = dict()
118+
for key, value in item.items():
119+
if value is None:
120+
continue
121+
if isinstance(value, six.string_types):
122+
value = get_string(value)
123+
tag = self._key_to_tag(key)
124+
if tag in SUB_FIELDS:
125+
for sub_k, sub_v in value.items():
126+
sub_tag = self._key_to_tag(sub_k)
127+
item_values[self._join_tag(tag, sub_tag)] = sub_v
128+
else:
129+
item_values[tag] = value
130+
131+
detail_data.append([item_values.get(tag) for tag in COLUMNS])
132+
133+
self.details = pd.DataFrame(detail_data, columns=COLUMNS)
134+
135+
@classmethod
136+
def _key_to_tag(cls, k):
137+
return DETAIL_FIELD_MAPPINGS[k] if k in DETAIL_FIELD_MAPPINGS else k
138+
139+
@classmethod
140+
def _join_tag(cls, tag, sub_tag):
141+
return '_'.join((tag, sub_tag))

0 commit comments

Comments
 (0)