Skip to content

Commit 7aa234d

Browse files
committed
Merge branch 'feat_optiontimeline' into 'master'
option timeline;contract fractional See merge request server/openapi/openapi-python-sdk!244
2 parents e09ba05 + 6cac893 commit 7aa234d

File tree

11 files changed

+128
-13
lines changed

11 files changed

+128
-13
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 3.4.1 (2025-06-26)
2+
### New
3+
- `QuoteClient.get_option_timeline` 期权分时接口
4+
- Contract 添加属性 `support_fractional_share`
5+
16
## 3.4.0 (2025-06-17)
27
### New
38
- `QuoteClient.get_bars` 增加 `date` 参数,用于查询历史分钟K线

tigeropen/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
55
@author: gaoan
66
"""
7-
__VERSION__ = '3.4.0'
7+
__VERSION__ = '3.4.1'

tigeropen/common/consts/service_types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
OPTION_TRADE_TICK = "option_trade_tick"
8787
OPTION_DEPTH = "option_depth"
8888
ALL_HK_OPTION_SYMBOLS = "all_hk_option_symbols"
89+
OPTION_TIMELINE = "option_timeline"
8990

9091

9192
# 期货行情

tigeropen/common/util/common_utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import delorean
1010
import pytz
1111

12+
from tigeropen.common.consts import Market
13+
1214
eastern = pytz.timezone('US/Eastern')
1315
china = pytz.timezone('Asia/Shanghai')
1416
hongkong = pytz.timezone('Asia/Hong_Kong')
@@ -43,3 +45,9 @@ def date_str_to_timestamp(dt, timezone):
4345
pass
4446
return dt
4547

48+
def get_tz_by_market(market: Market):
49+
if Market.HK == market:
50+
return hongkong
51+
elif Market.CN == market:
52+
return china
53+
return eastern

tigeropen/quote/quote_client.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
FUTURE_CONTRACTS, MARKET_SCANNER, \
2020
STOCK_BROKER, CAPITAL_FLOW, CAPITAL_DISTRIBUTION, WARRANT_REAL_TIME_QUOTE, WARRANT_FILTER, MARKET_SCANNER_TAGS, \
2121
KLINE_QUOTA, FUND_ALL_SYMBOLS, FUND_CONTRACTS, FUND_QUOTE, FUND_HISTORY_QUOTE, FINANCIAL_CURRENCY, \
22-
FINANCIAL_EXCHANGE_RATE, ALL_HK_OPTION_SYMBOLS, OPTION_DEPTH, BROKER_HOLD
22+
FINANCIAL_EXCHANGE_RATE, ALL_HK_OPTION_SYMBOLS, OPTION_DEPTH, BROKER_HOLD, OPTION_TIMELINE
2323
from tigeropen.common.consts.service_types import MARKET_STATE, ALL_SYMBOLS, ALL_SYMBOL_NAMES, BRIEF, \
2424
TIMELINE, KLINE, TRADE_TICK, OPTION_EXPIRATION, OPTION_CHAIN, FUTURE_EXCHANGE, OPTION_BRIEF, \
2525
OPTION_KLINE, OPTION_TRADE_TICK, FUTURE_KLINE, FUTURE_TICK, FUTURE_CONTRACT_BY_EXCHANGE_CODE, \
@@ -68,6 +68,7 @@
6868
from tigeropen.quote.response.option_quote_bar_response import OptionQuoteBarResponse
6969
from tigeropen.quote.response.option_quote_ticks_response import OptionTradeTickResponse
7070
from tigeropen.quote.response.option_symbols_response import OptionSymbolsResponse
71+
from tigeropen.quote.response.option_timeline_response import OptionTimelineResponse
7172
from tigeropen.quote.response.quote_bar_response import QuoteBarResponse
7273
from tigeropen.quote.response.quote_brief_response import QuoteBriefResponse
7374
from tigeropen.quote.response.quote_delay_briefs_response import DelayBriefsResponse
@@ -937,6 +938,34 @@ def get_option_depth(self, identifiers, market: Market = Market.US, timezone=Non
937938
else:
938939
raise ApiException(response.code, response.message)
939940

941+
def get_option_timeline(self, identifiers, market: Market, begin_time=None, timezone=None):
942+
params = OptionContractsParams()
943+
contracts = []
944+
for identifier in identifiers:
945+
symbol, expiry, put_call, strike = extract_option_info(identifier)
946+
if symbol is None or expiry is None or put_call is None or strike is None:
947+
continue
948+
param = SingleOptionQuoteParams()
949+
param.symbol = symbol
950+
param.expiry = date_str_to_timestamp(expiry, self._parse_timezone(timezone, market))
951+
param.put_call = put_call
952+
param.strike = strike
953+
param.begin_time = date_str_to_timestamp(begin_time, self._parse_timezone(timezone, market))
954+
contracts.append(param)
955+
params.option_query = contracts
956+
if market:
957+
params.market = get_enum_value(market)
958+
request = OpenApiRequest(OPTION_TIMELINE, biz_model=params)
959+
response_content = self.__fetch_data(request)
960+
if response_content:
961+
response = OptionTimelineResponse()
962+
response.parse_response_content(response_content)
963+
if response.is_success():
964+
return response.result
965+
else:
966+
raise ApiException(response.code, response.message)
967+
968+
940969
def get_future_exchanges(self, sec_type=SecurityType.FUT, lang=None):
941970
"""
942971
获取期货交易所列表

tigeropen/quote/response/option_briefs_response.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
"""
77
import pandas as pd
88

9+
from tigeropen.common.consts import Market
910
from tigeropen.common.response import TigerResponse
10-
from tigeropen.common.util.common_utils import eastern
11-
from tigeropen.common.util.contract_utils import get_option_identifier
11+
from tigeropen.common.util.common_utils import get_tz_by_market
12+
from tigeropen.common.util.contract_utils import get_option_identifier, is_hk_option_underlying_symbol
1213

1314
COLUMNS = ['identifier', 'symbol', 'expiry', 'strike', 'put_call', 'multiplier', 'ask_price', 'ask_size', 'bid_price',
1415
'bid_size', 'pre_close', 'latest_price', 'latest_time', 'volume', 'open_interest', 'open', 'high', 'low',
@@ -46,7 +47,11 @@ def parse_response_content(self, response_content):
4647
expiry = item_values.get('expiry')
4748
strike = float(item_values.get('strike'))
4849
put_call = item_values.get('right')
49-
expiry = pd.Timestamp(expiry, unit='ms', tzinfo=eastern).date().strftime("%Y%m%d")
50+
if is_hk_option_underlying_symbol(underlying_symbol):
51+
tz = get_tz_by_market(Market.HK)
52+
else:
53+
tz = get_tz_by_market(Market.US)
54+
expiry = pd.Timestamp(expiry, unit='ms', tzinfo=tz).date().strftime("%Y%m%d")
5055
item_values['identifier'] = get_option_identifier(underlying_symbol, expiry, put_call, strike)
5156

5257
brief_data.append([item_values.get(tag) for tag in COLUMNS])

tigeropen/quote/response/option_depth_response.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ def parse_data(self, item):
3030
strike = item.get('strike', '')
3131
right = item.get('right', '')
3232
identifier = get_option_identifier(symbol, expiry, right, strike)
33-
asks = [(v['price'], v.get('volume', 0), v['timestamp'], v['code']) for v in item.get('ask', [])]
34-
bids = [(v['price'], v.get('volume', 0), v['timestamp'], v['code']) for v in item.get('bid', [])]
33+
asks = [(v['price'], v.get('volume', 0), v.get('timestamp', 0), v.get('code')) for v in item.get('ask', [])]
34+
bids = [(v['price'], v.get('volume', 0), v.get('timestamp', 0), v.get('code')) for v in item.get('bid', [])]
3535
return {'identifier': identifier, 'asks': asks, 'bids': bids}
3636

3737

tigeropen/quote/response/option_quote_bar_response.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
"""
77
import pandas as pd
88

9+
from tigeropen.common.consts import Market
910
from tigeropen.common.response import TigerResponse
10-
from tigeropen.common.util.common_utils import eastern
11-
from tigeropen.common.util.contract_utils import get_option_identifier
11+
from tigeropen.common.util.common_utils import get_tz_by_market
12+
from tigeropen.common.util.contract_utils import get_option_identifier, is_hk_option_underlying_symbol
1213

1314
COLUMNS = ['identifier', 'symbol', 'expiry', 'put_call', 'strike', 'time', 'open', 'high', 'low', 'close', 'volume',
1415
'open_interest']
@@ -38,7 +39,11 @@ def parse_response_content(self, response_content):
3839
put_call = put_call.upper()
3940

4041
if not identifier:
41-
expiration = pd.Timestamp(expiry, unit='ms', tzinfo=eastern).date().strftime("%Y%m%d")
42+
if is_hk_option_underlying_symbol(underlying_symbol):
43+
tz = get_tz_by_market(Market.HK)
44+
else:
45+
tz = get_tz_by_market(Market.US)
46+
expiration = pd.Timestamp(expiry, unit='ms', tzinfo=tz).date().strftime("%Y%m%d")
4247
identifier = get_option_identifier(underlying_symbol, expiration, put_call, strike)
4348

4449
if 'items' in symbol_item:

tigeropen/quote/response/option_quote_ticks_response.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
"""
77
import pandas as pd
88

9+
from tigeropen.common.consts import Market
910
from tigeropen.common.response import TigerResponse
10-
from tigeropen.common.util.common_utils import eastern
11-
from tigeropen.common.util.contract_utils import get_option_identifier
11+
from tigeropen.common.util.common_utils import get_tz_by_market
12+
from tigeropen.common.util.contract_utils import get_option_identifier, is_hk_option_underlying_symbol
1213

1314
COLUMNS = ['identifier', 'symbol', 'expiry', 'put_call', 'strike', 'time', 'price', 'volume']
1415

@@ -34,7 +35,11 @@ def parse_response_content(self, response_content):
3435
strike = float(symbol_item.get('strike'))
3536
identifier = symbol_item.get('identifier')
3637
if not identifier:
37-
expiration = pd.Timestamp(expiry, unit='ms', tzinfo=eastern).date().strftime("%Y%m%d")
38+
if is_hk_option_underlying_symbol(underlying_symbol):
39+
tz = get_tz_by_market(Market.HK)
40+
else:
41+
tz = get_tz_by_market(Market.US)
42+
expiration = pd.Timestamp(expiry, unit='ms', tzinfo=tz).date().strftime("%Y%m%d")
3843
identifier = get_option_identifier(underlying_symbol, expiration, put_call, strike)
3944

4045
for item in symbol_item['items']:
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# -*- coding: utf-8 -*-
2+
3+
4+
import pandas as pd
5+
6+
from tigeropen.common.consts import Market
7+
from tigeropen.common.response import TigerResponse
8+
from tigeropen.common.util.common_utils import get_tz_by_market
9+
from tigeropen.common.util.contract_utils import get_option_identifier, is_hk_option_underlying_symbol
10+
from tigeropen.common.util.string_utils import camel_to_underline_obj
11+
12+
13+
class OptionTimelineResponse(TigerResponse):
14+
def __init__(self):
15+
super(OptionTimelineResponse, self).__init__()
16+
self.result = None
17+
self._is_success = None
18+
19+
def parse_response_content(self, response_content):
20+
response = super(OptionTimelineResponse, self).parse_response_content(response_content)
21+
if 'is_success' in response:
22+
self._is_success = response['is_success']
23+
24+
timeline_items = []
25+
for symbol_item in self.data:
26+
identifier = symbol_item.get('identifier')
27+
underlying_symbol = symbol_item.get('symbol')
28+
expiry = symbol_item.get('expiry')
29+
strike = symbol_item.get('strike')
30+
put_call = symbol_item.get('right').upper()
31+
pre_close = symbol_item.get('preClose')
32+
if not identifier:
33+
if is_hk_option_underlying_symbol(underlying_symbol):
34+
tz = get_tz_by_market(Market.HK)
35+
else:
36+
tz = get_tz_by_market(Market.US)
37+
expiration = pd.Timestamp(expiry, unit='ms', tzinfo=tz).date().strftime("%Y%m%d")
38+
identifier = get_option_identifier(underlying_symbol, expiration, put_call, strike)
39+
option_info = {
40+
'identifier': identifier,
41+
'symbol': underlying_symbol,
42+
'expiry': expiry,
43+
'put_call': put_call,
44+
'strike': strike,
45+
'pre_close': pre_close,
46+
}
47+
minutes = symbol_item.get('minutes')
48+
if minutes:
49+
for item in minutes:
50+
item_values = dict(option_info)
51+
item_values.update(camel_to_underline_obj(item))
52+
timeline_items.append(item_values)
53+
54+
self.result = pd.DataFrame(timeline_items)
55+
56+

0 commit comments

Comments
 (0)