Skip to content

Commit cea1a92

Browse files
committed
Merge branch 'feat_option_timezone' into 'master'
Feat option timezone See merge request server/openapi/openapi-python-sdk!237
2 parents 1bfe986 + f1cfd4b commit cea1a92

File tree

4 files changed

+71
-38
lines changed

4 files changed

+71
-38
lines changed

CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
## 3.3.6 (2025-04-23)
1+
## 3.3.6 (2025-04-28)
22
### New
33
- `TradeClient.get_fund_details` 资金明细
4-
4+
- `QuoteClient` 期权相关接口支持时区参数
5+
### Mod
6+
= 废弃 sandbox_config 配置
57

68
## 3.3.5 (2025-04-11)
79
### New

tigeropen/common/util/contract_utils.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,7 @@ def get_option_identifier(underlying_symbol, expiry, put_call, strike):
9898
if isinstance(strike, str):
9999
strike = float(strike)
100100
return underlying_symbol.ljust(6, ' ') + expiry[2:] + direction + str(int(strike * 1000)).zfill(8)
101+
102+
103+
def is_hk_option_underlying_symbol(underlying_symbol):
104+
return underlying_symbol and underlying_symbol.endswith('.HK')

tigeropen/quote/quote_client.py

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from tigeropen.common.exceptions import ApiException
3131
from tigeropen.common.request import OpenApiRequest
3232
from tigeropen.common.util.common_utils import eastern, get_enum_value, date_str_to_timestamp
33-
from tigeropen.common.util.contract_utils import extract_option_info
33+
from tigeropen.common.util.contract_utils import extract_option_info, is_hk_option_underlying_symbol
3434
from tigeropen.fundamental.request.model import FinancialDailyParams, FinancialReportParams, CorporateActionParams, \
3535
IndustryParams, FinancialExchangeRateParams
3636
from tigeropen.fundamental.response.corporate_dividend_response import CorporateDividendResponse
@@ -667,13 +667,16 @@ def get_option_expirations(self, symbols, market=None):
667667

668668
return None
669669

670-
def get_option_chain(self, symbol, expiry, option_filter=None, return_greek_value=None, market=None, **kwargs):
670+
def get_option_chain(self, symbol, expiry, option_filter=None, return_greek_value=None, market=None, timezone=None,
671+
**kwargs):
671672
"""
672673
query option chain with filter
673674
:param symbol: underlying stock symbol
674675
:param expiry: expiration date ( like '2021-06-18' or 1560484800000 )
675676
:param option_filter: option filter conditions, tigeropen.quote.domain.filter.OptionFilter
676677
:param return_greek_value: return greek value or not, bool
678+
:param market:
679+
:param timezone: Default US/Eastern, when querying non-U.S. stock options, you need to specify the time zone
677680
:param kwargs: optional. specify option_filter parameters directly without option_filer,
678681
like: open_interest_min=100, delta_min=0.1
679682
:return: pandas.DataFrame,the columns are as follows:
@@ -695,8 +698,10 @@ def get_option_chain(self, symbol, expiry, option_filter=None, return_greek_valu
695698
params = OptionChainParams()
696699
param = SingleContractParams()
697700
param.symbol = symbol
701+
if market is None and is_hk_option_underlying_symbol(symbol):
702+
market = Market.HK
698703
if isinstance(expiry, str) and re.match('[0-9]{4}-[0-9]{2}-[0-9]{2}', expiry):
699-
param.expiry = date_str_to_timestamp(expiry, self._timezone)
704+
param.expiry = date_str_to_timestamp(expiry, self._parse_timezone(timezone, market))
700705
else:
701706
param.expiry = expiry
702707
params.contracts = [param]
@@ -721,7 +726,7 @@ def get_option_chain(self, symbol, expiry, option_filter=None, return_greek_valu
721726

722727
return None
723728

724-
def get_option_briefs(self, identifiers, market = None):
729+
def get_option_briefs(self, identifiers, market = None, timezone = None):
725730
"""
726731
获取期权最新行情
727732
:param identifiers: 期权代码列表
@@ -753,9 +758,11 @@ def get_option_briefs(self, identifiers, market = None):
753758
symbol, expiry, put_call, strike = extract_option_info(identifier)
754759
if symbol is None or expiry is None or put_call is None or strike is None:
755760
continue
761+
if market is None and is_hk_option_underlying_symbol(symbol):
762+
market = Market.HK
756763
param = SingleContractParams()
757764
param.symbol = symbol
758-
param.expiry = date_str_to_timestamp(expiry, self._timezone)
765+
param.expiry = date_str_to_timestamp(expiry, self._parse_timezone(timezone, market))
759766
param.put_call = put_call
760767
param.strike = strike
761768
contracts.append(param)
@@ -776,7 +783,7 @@ def get_option_briefs(self, identifiers, market = None):
776783
return None
777784

778785
def get_option_bars(self, identifiers, begin_time=-1, end_time=4070880000000, period=BarPeriod.DAY, limit=None,
779-
sort_dir=None, market=None):
786+
sort_dir=None, market=None, timezone=None):
780787
"""
781788
获取期权日K数据
782789
:param identifiers: 期权代码列表
@@ -807,12 +814,14 @@ def get_option_bars(self, identifiers, begin_time=-1, end_time=4070880000000, pe
807814
continue
808815
param = SingleOptionQuoteParams()
809816
param.symbol = symbol
810-
param.expiry = date_str_to_timestamp(expiry, self._timezone)
817+
if market is None and is_hk_option_underlying_symbol(symbol):
818+
market = Market.HK
819+
param.expiry = date_str_to_timestamp(expiry, self._parse_timezone(timezone, market))
811820
param.put_call = put_call
812821
param.strike = strike
813822
param.period = get_enum_value(period)
814-
param.begin_time = date_str_to_timestamp(begin_time, self._timezone)
815-
param.end_time = date_str_to_timestamp(end_time, self._timezone)
823+
param.begin_time = date_str_to_timestamp(begin_time, self._parse_timezone(timezone, market))
824+
param.end_time = date_str_to_timestamp(end_time, self._parse_timezone(timezone, market))
816825
param.limit = limit
817826
param.sort_dir = get_enum_value(sort_dir)
818827
contracts.append(param)
@@ -829,7 +838,7 @@ def get_option_bars(self, identifiers, begin_time=-1, end_time=4070880000000, pe
829838
else:
830839
raise ApiException(response.code, response.message)
831840

832-
def get_option_trade_ticks(self, identifiers):
841+
def get_option_trade_ticks(self, identifiers, timezone=None):
833842
"""
834843
获取期权逐笔成交
835844
:param identifiers: 期权代码列表
@@ -850,7 +859,11 @@ def get_option_trade_ticks(self, identifiers):
850859
continue
851860
param = SingleContractParams()
852861
param.symbol = symbol
853-
param.expiry = date_str_to_timestamp(expiry, timezone=self._timezone)
862+
if is_hk_option_underlying_symbol(symbol):
863+
market = Market.HK
864+
else:
865+
market = None
866+
param.expiry = date_str_to_timestamp(expiry, self._parse_timezone(timezone, market))
854867
param.put_call = put_call
855868
param.strike = strike
856869
contracts.append(param)
@@ -888,7 +901,7 @@ def get_option_symbols(self, market: Market = Market.HK, lang: Language = Langua
888901
else:
889902
raise ApiException(response.code, response.message)
890903

891-
def get_option_depth(self, identifiers, market: Market = Market.US):
904+
def get_option_depth(self, identifiers, market: Market = Market.US, timezone=None):
892905
"""
893906
获取期权深度
894907
:param market:
@@ -902,9 +915,11 @@ def get_option_depth(self, identifiers, market: Market = Market.US):
902915
symbol, expiry, put_call, strike = extract_option_info(identifier)
903916
if symbol is None or expiry is None or put_call is None or strike is None:
904917
continue
918+
if market is None and is_hk_option_underlying_symbol(symbol):
919+
market = Market.HK
905920
param = SingleContractParams()
906921
param.symbol = symbol
907-
param.expiry = date_str_to_timestamp(expiry, timezone=self._timezone)
922+
param.expiry = date_str_to_timestamp(expiry, self._parse_timezone(timezone, market))
908923
param.put_call = put_call
909924
param.strike = strike
910925
contracts.append(param)
@@ -1107,7 +1122,7 @@ def get_future_trading_times(self, identifier, trading_date=None):
11071122
return None
11081123

11091124
def get_future_bars(self, identifiers, period=BarPeriod.DAY, begin_time=-1, end_time=-1, limit=1000,
1110-
page_token=None):
1125+
page_token=None, timezone=None):
11111126
"""
11121127
获取期货K线数据
11131128
:param identifiers: 期货代码列表
@@ -1132,7 +1147,7 @@ def get_future_bars(self, identifiers, period=BarPeriod.DAY, begin_time=-1, end_
11321147
params = FutureQuoteParams()
11331148
params.contract_codes = identifiers if isinstance(identifiers, list) else [identifiers]
11341149
params.period = get_enum_value(period)
1135-
params.begin_time = date_str_to_timestamp(begin_time, self._timezone)
1150+
params.begin_time = date_str_to_timestamp(begin_time, self._parse_timezone(timezone))
11361151
params.end_time = end_time
11371152
params.limit = limit
11381153
params.page_token = page_token if len(params.contract_codes) == 1 else None
@@ -1253,7 +1268,7 @@ def get_future_brief(self, identifiers):
12531268
else:
12541269
raise ApiException(response.code, response.message)
12551270

1256-
def get_corporate_split(self, symbols, market, begin_date, end_date):
1271+
def get_corporate_split(self, symbols, market, begin_date, end_date, timezone=None):
12571272
"""
12581273
获取公司拆合股数据
12591274
:param symbols: 证券代码列表
@@ -1275,8 +1290,8 @@ def get_corporate_split(self, symbols, market, begin_date, end_date):
12751290
params.action_type = CorporateActionType.SPLIT.value
12761291
params.symbols = symbols
12771292
params.market = get_enum_value(market)
1278-
params.begin_date = date_str_to_timestamp(begin_date, self._timezone)
1279-
params.end_date = date_str_to_timestamp(end_date, self._timezone)
1293+
params.begin_date = date_str_to_timestamp(begin_date, self._parse_timezone(timezone))
1294+
params.end_date = date_str_to_timestamp(end_date, self._parse_timezone(timezone))
12801295
params.lang = get_enum_value(self._lang)
12811296
request = OpenApiRequest(CORPORATE_ACTION, biz_model=params)
12821297
response_content = self.__fetch_data(request)
@@ -1288,7 +1303,7 @@ def get_corporate_split(self, symbols, market, begin_date, end_date):
12881303
else:
12891304
raise ApiException(response.code, response.message)
12901305

1291-
def get_corporate_dividend(self, symbols, market, begin_date, end_date):
1306+
def get_corporate_dividend(self, symbols, market, begin_date, end_date, timezone=None):
12921307
"""
12931308
获取公司派息数据
12941309
:param symbols: 证券代码列表
@@ -1312,8 +1327,8 @@ def get_corporate_dividend(self, symbols, market, begin_date, end_date):
13121327
params.action_type = CorporateActionType.DIVIDEND.value
13131328
params.symbols = symbols
13141329
params.market = get_enum_value(market)
1315-
params.begin_date = date_str_to_timestamp(begin_date, self._timezone)
1316-
params.end_date = date_str_to_timestamp(end_date, self._timezone)
1330+
params.begin_date = date_str_to_timestamp(begin_date, self._parse_timezone(timezone))
1331+
params.end_date = date_str_to_timestamp(end_date, self._parse_timezone(timezone))
13171332
params.lang = get_enum_value(self._lang)
13181333
request = OpenApiRequest(CORPORATE_ACTION, biz_model=params)
13191334
response_content = self.__fetch_data(request)
@@ -1325,7 +1340,7 @@ def get_corporate_dividend(self, symbols, market, begin_date, end_date):
13251340
else:
13261341
raise ApiException(response.code, response.message)
13271342

1328-
def get_corporate_earnings_calendar(self, market, begin_date, end_date):
1343+
def get_corporate_earnings_calendar(self, market, begin_date, end_date, timezone=None):
13291344
"""
13301345
获取公司财报日历
13311346
:param market:
@@ -1336,8 +1351,8 @@ def get_corporate_earnings_calendar(self, market, begin_date, end_date):
13361351
params = CorporateActionParams()
13371352
params.action_type = CorporateActionType.EARNINGS_CALENDAR.value
13381353
params.market = get_enum_value(market)
1339-
params.begin_date = date_str_to_timestamp(begin_date, self._timezone)
1340-
params.end_date = date_str_to_timestamp(end_date, self._timezone)
1354+
params.begin_date = date_str_to_timestamp(begin_date, self._parse_timezone(timezone))
1355+
params.end_date = date_str_to_timestamp(end_date, self._parse_timezone(timezone))
13411356
params.lang = get_enum_value(self._lang)
13421357
request = OpenApiRequest(CORPORATE_ACTION, biz_model=params)
13431358
response_content = self.__fetch_data(request)
@@ -1349,7 +1364,7 @@ def get_corporate_earnings_calendar(self, market, begin_date, end_date):
13491364
else:
13501365
raise ApiException(response.code, response.message)
13511366

1352-
def get_financial_daily(self, symbols, market, fields, begin_date, end_date):
1367+
def get_financial_daily(self, symbols, market, fields, begin_date, end_date, timezone=None):
13531368
"""
13541369
获取日级的财务数据
13551370
:param symbols: 证券代码列表
@@ -1367,8 +1382,8 @@ def get_financial_daily(self, symbols, market, fields, begin_date, end_date):
13671382
params.symbols = symbols
13681383
params.market = get_enum_value(market)
13691384
params.fields = [get_enum_value(field) for field in fields]
1370-
params.begin_date = date_str_to_timestamp(begin_date, self._timezone)
1371-
params.end_date = date_str_to_timestamp(end_date, self._timezone)
1385+
params.begin_date = date_str_to_timestamp(begin_date, self._parse_timezone(timezone))
1386+
params.end_date = date_str_to_timestamp(end_date, self._parse_timezone(timezone))
13721387
params.lang = get_enum_value(self._lang)
13731388
request = OpenApiRequest(FINANCIAL_DAILY, biz_model=params)
13741389
response_content = self.__fetch_data(request)
@@ -1380,7 +1395,7 @@ def get_financial_daily(self, symbols, market, fields, begin_date, end_date):
13801395
else:
13811396
raise ApiException(response.code, response.message)
13821397

1383-
def get_financial_report(self, symbols, market, fields, period_type, begin_date=None, end_date=None):
1398+
def get_financial_report(self, symbols, market, fields, period_type, begin_date=None, end_date=None, timezone=None):
13841399
"""
13851400
获取财报数据
13861401
:param symbols:
@@ -1404,8 +1419,8 @@ def get_financial_report(self, symbols, market, fields, period_type, begin_date=
14041419
params.fields = [get_enum_value(field) for field in fields]
14051420
params.period_type = get_enum_value(period_type)
14061421
params.lang = get_enum_value(self._lang)
1407-
params.begin_date = date_str_to_timestamp(begin_date, self._timezone)
1408-
params.end_date = date_str_to_timestamp(end_date, self._timezone)
1422+
params.begin_date = date_str_to_timestamp(begin_date, self._parse_timezone(timezone))
1423+
params.end_date = date_str_to_timestamp(end_date, self._parse_timezone(timezone))
14091424
request = OpenApiRequest(FINANCIAL_REPORT, biz_model=params)
14101425
response_content = self.__fetch_data(request)
14111426
if response_content:
@@ -1452,7 +1467,7 @@ def get_financial_exchange_rate(self, currency_list, begin_date, end_date=None,
14521467
0 HKD 1691942400000 7.81728
14531468
1 USD 1691942400000 1.00000
14541469
"""
1455-
tz = timezone if timezone else self._timezone
1470+
tz = self._parse_timezone(timezone)
14561471
params = FinancialExchangeRateParams()
14571472
params.currency_list = currency_list
14581473
params.begin_date = date_str_to_timestamp(begin_date, tz)
@@ -1942,4 +1957,15 @@ def get_quote_overnight(self, symbols, lang=Language.en_US):
19421957
else:
19431958
raise ApiException(response.code, response.message)
19441959

1945-
1960+
1961+
def _parse_timezone(self, timezone=None, market=None):
1962+
if timezone:
1963+
return timezone
1964+
if market:
1965+
if Market.HK.name == get_enum_value(market):
1966+
return 'Asia/Hong_Kong'
1967+
if Market.US.name == get_enum_value(market):
1968+
return 'US/Eastern'
1969+
if Market.CN.name == get_enum_value(market):
1970+
return 'Asia/Shanghai'
1971+
return self._timezone

tigeropen/tiger_open_config.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,11 @@ def __init__(self, sandbox_debug=None, enable_dynamic_domain=True, props_path='.
118118
self.domain_conf = dict()
119119
self.enable_dynamic_domain = enable_dynamic_domain
120120
if self._sandbox_debug:
121-
self._tiger_public_key = SANDBOX_TIGER_PUBLIC_KEY
122-
self._server_url = SANDBOX_SERVER_URL
123-
self._quote_server_url = SANDBOX_SERVER_URL
124-
self._socket_host_port = SANDBOX_SOCKET_HOST_PORT
121+
raise NotImplementedError('Sandbox debug mode is deprecated, please set to False')
122+
# self._tiger_public_key = SANDBOX_TIGER_PUBLIC_KEY
123+
# self._server_url = SANDBOX_SERVER_URL
124+
# self._quote_server_url = SANDBOX_SERVER_URL
125+
# self._socket_host_port = SANDBOX_SOCKET_HOST_PORT
125126
if self.enable_dynamic_domain:
126127
self.domain_conf = self.query_domains()
127128
self.refresh_server_info()

0 commit comments

Comments
 (0)