libfinance 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of libfinance might be problematic. Click here for more details.
- libfinance-0.0.1/PKG-INFO +16 -0
- libfinance-0.0.1/README.md +59 -0
- libfinance-0.0.1/libfinance/__init__.py +6 -0
- libfinance-0.0.1/libfinance/api/__init__.py +2 -0
- libfinance-0.0.1/libfinance/api/calendar.py +129 -0
- libfinance-0.0.1/libfinance/api/get_price.py +97 -0
- libfinance-0.0.1/libfinance/api/index_components.py +20 -0
- libfinance-0.0.1/libfinance/client.py +147 -0
- libfinance-0.0.1/libfinance/libfinance.thrift +16 -0
- libfinance-0.0.1/libfinance/utils/__init__.py +8 -0
- libfinance-0.0.1/libfinance/utils/datetime_func.py +26 -0
- libfinance-0.0.1/libfinance/utils/decorators.py +150 -0
- libfinance-0.0.1/libfinance/utils/loader.py +44 -0
- libfinance-0.0.1/libfinance/utils/serialize.py +38 -0
- libfinance-0.0.1/libfinance/version.py +3 -0
- libfinance-0.0.1/libfinance.egg-info/PKG-INFO +16 -0
- libfinance-0.0.1/libfinance.egg-info/SOURCES.txt +21 -0
- libfinance-0.0.1/libfinance.egg-info/dependency_links.txt +1 -0
- libfinance-0.0.1/libfinance.egg-info/not-zip-safe +1 -0
- libfinance-0.0.1/libfinance.egg-info/requires.txt +3 -0
- libfinance-0.0.1/libfinance.egg-info/top_level.txt +1 -0
- libfinance-0.0.1/setup.cfg +4 -0
- libfinance-0.0.1/setup.py +33 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: libfinance
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: libfinance
|
|
5
|
+
Home-page:
|
|
6
|
+
Author:
|
|
7
|
+
Author-email:
|
|
8
|
+
License: Apache License v2
|
|
9
|
+
Classifier: Programming Language :: Python
|
|
10
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
11
|
+
Classifier: Operating System :: Unix
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Requires-Dist: dill>=0.3.8
|
|
15
|
+
Requires-Dist: thriftpy2>=0.3.9
|
|
16
|
+
Requires-Dist: pandas>=0.16.2
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# libfinance
|
|
2
|
+
|
|
3
|
+
`libfinance` is python library for accessing financial data easily. The goal of `libfinance` is to provide HIGH quality financial data for scholars, researchers and developers in research and production environment.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# install
|
|
7
|
+
|
|
8
|
+
Install `libfinance` by `pip`
|
|
9
|
+
|
|
10
|
+
``` {.sourceCode .bash}
|
|
11
|
+
$ pip install libfinance
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Install with a develop mode
|
|
15
|
+
~~~
|
|
16
|
+
git clone https://github.com/StateOfTheArt-quant/libfinance.git
|
|
17
|
+
cd libfinance
|
|
18
|
+
python setup.py develop
|
|
19
|
+
~~~
|
|
20
|
+
|
|
21
|
+
# quick-start
|
|
22
|
+
|
|
23
|
+
~~~
|
|
24
|
+
from libfinance import get_trading_dates, history_bars
|
|
25
|
+
|
|
26
|
+
trading_dates = get_trading_dates(start_date="2023-12-25", end_date="2024-01-11")
|
|
27
|
+
print(trading_dates)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
DatetimeIndex(['2023-12-25', '2023-12-26', '2023-12-27', '2023-12-28',
|
|
31
|
+
'2023-12-29', '2024-01-02', '2024-01-03', '2024-01-04',
|
|
32
|
+
'2024-01-05', '2024-01-08', '2024-01-09', '2024-01-10',
|
|
33
|
+
'2024-01-11'],
|
|
34
|
+
dtype='datetime64[ns]', freq=None)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
trading_data = history_bars(order_book_ids=["000001.XSHE","600000.XSHG"], bar_count=6, frequency="1d", datetime="2024-01-11")
|
|
40
|
+
print(trading_data)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
open close ... volume total_turnover
|
|
44
|
+
order_book_id datetime ...
|
|
45
|
+
000001.XSHE 2024-01-04 9.19 9.11 ... 86419399.0 7.874701e+08
|
|
46
|
+
2024-01-05 9.10 9.27 ... 199162216.0 1.852660e+09
|
|
47
|
+
2024-01-08 9.23 9.15 ... 112115619.0 1.029007e+09
|
|
48
|
+
2024-01-09 9.16 9.18 ... 76619388.0 7.003757e+08
|
|
49
|
+
2024-01-10 9.16 9.09 ... 85862091.0 7.837712e+08
|
|
50
|
+
2024-01-11 9.08 9.17 ... 93468637.0 8.538902e+08
|
|
51
|
+
600000.XSHG 2024-01-04 6.64 6.62 ... 28885978.0 1.905806e+08
|
|
52
|
+
2024-01-05 6.60 6.68 ... 44421387.0 2.969769e+08
|
|
53
|
+
2024-01-08 6.68 6.59 ... 37520337.0 2.479778e+08
|
|
54
|
+
2024-01-09 6.60 6.61 ... 30741897.0 2.026476e+08
|
|
55
|
+
2024-01-10 6.61 6.57 ... 22240946.0 1.466959e+08
|
|
56
|
+
2024-01-11 6.56 6.53 ... 35914708.0 2.353121e+08
|
|
57
|
+
~~~
|
|
58
|
+
|
|
59
|
+
# Documentation
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
import bisect
|
|
4
|
+
import datetime
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
from libfinance.client import get_client
|
|
8
|
+
from libfinance.utils.decorators import export_as_api, ttl_cache, compatible_with_parm
|
|
9
|
+
|
|
10
|
+
def _to_timestamp(d):
|
|
11
|
+
return pd.Timestamp(d).replace(hour=0, minute=0, second=0, microsecond=0)
|
|
12
|
+
|
|
13
|
+
@ttl_cache(24 * 3600)
|
|
14
|
+
def _get_all_trading_dates():
|
|
15
|
+
return get_client().get_trading_calendar()
|
|
16
|
+
|
|
17
|
+
@export_as_api
|
|
18
|
+
def get_trading_dates(start_date, end_date):
|
|
19
|
+
r"""get the trading datata
|
|
20
|
+
|
|
21
|
+
获取A股某个区间的交易日期
|
|
22
|
+
|
|
23
|
+
:param start_date: 开始日期
|
|
24
|
+
:param end_date: 结束如期
|
|
25
|
+
|
|
26
|
+
Example::
|
|
27
|
+
|
|
28
|
+
获取2020-05-10至2020-05-20之间的交易日期
|
|
29
|
+
|
|
30
|
+
.. code-block:: python3
|
|
31
|
+
|
|
32
|
+
from libfinance.api import get_trading_dates
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
>>> trading_dates = get_trading_dates(start_date = "2020-05-11", end_date="2020-05-20")
|
|
36
|
+
>>> print(trading_dates)
|
|
37
|
+
DatetimeIndex(['2020-05-11', '2020-05-12', '2020-05-13', '2020-05-14',
|
|
38
|
+
'2020-05-15', '2020-05-18', '2020-05-19', '2020-05-20'],
|
|
39
|
+
dtype='datetime64[ns]', freq=None)
|
|
40
|
+
"""
|
|
41
|
+
trading_dates = _get_all_trading_dates()
|
|
42
|
+
|
|
43
|
+
start_date = _to_timestamp(start_date)
|
|
44
|
+
end_date = _to_timestamp(end_date)
|
|
45
|
+
left = trading_dates.searchsorted(start_date)
|
|
46
|
+
right = trading_dates.searchsorted(end_date, side='right')
|
|
47
|
+
return trading_dates[left:right]
|
|
48
|
+
|
|
49
|
+
@export_as_api
|
|
50
|
+
def get_previous_trading_date(date, n=1):
|
|
51
|
+
"""获取指定日期的之前的第 n 个交易日
|
|
52
|
+
|
|
53
|
+
:param date: 指定日期
|
|
54
|
+
:param n: 第 n 个交易日
|
|
55
|
+
|
|
56
|
+
Example::
|
|
57
|
+
|
|
58
|
+
2020-05-18之前3天的交易日
|
|
59
|
+
|
|
60
|
+
.. code-block:: python3
|
|
61
|
+
|
|
62
|
+
from libfinance.api import get_previous_trading_date
|
|
63
|
+
|
|
64
|
+
>>> get_previous_trading_date(date='2020-05-18', n=3)
|
|
65
|
+
Timestamp('2020-05-13 00:00:00')
|
|
66
|
+
"""
|
|
67
|
+
trading_dates = _get_all_trading_dates()
|
|
68
|
+
pos = trading_dates.searchsorted(_to_timestamp(date))
|
|
69
|
+
if pos >= n:
|
|
70
|
+
return trading_dates[pos - n]
|
|
71
|
+
else:
|
|
72
|
+
return trading_dates[0]
|
|
73
|
+
|
|
74
|
+
@export_as_api
|
|
75
|
+
def get_next_trading_date(date, n=1):
|
|
76
|
+
"""
|
|
77
|
+
获取指定日期之后的第 n 个交易日
|
|
78
|
+
|
|
79
|
+
:param date: 指定日期
|
|
80
|
+
:param n: 第 n 个交易日
|
|
81
|
+
|
|
82
|
+
:example:
|
|
83
|
+
|
|
84
|
+
.. code-block:: python3
|
|
85
|
+
|
|
86
|
+
from simonsc.api import get_next_trading_date
|
|
87
|
+
|
|
88
|
+
>>> get_next_trading_date(date='2020-05-13', n=3)
|
|
89
|
+
Timestamp('2020-05-18 00:00:00')
|
|
90
|
+
"""
|
|
91
|
+
trading_dates = _get_all_trading_dates()
|
|
92
|
+
pos = trading_dates.searchsorted(_to_timestamp(date), side='right')
|
|
93
|
+
if pos + n > len(trading_dates):
|
|
94
|
+
return trading_dates[-1]
|
|
95
|
+
else:
|
|
96
|
+
return trading_dates[pos + n - 1]
|
|
97
|
+
|
|
98
|
+
@export_as_api
|
|
99
|
+
def is_trading_date(date):
|
|
100
|
+
date = _to_timestamp(date)
|
|
101
|
+
trading_dates = _get_all_trading_dates()
|
|
102
|
+
pos = trading_dates.searchsorted(date)
|
|
103
|
+
return pos < len(trading_dates) and trading_dates[pos] == date
|
|
104
|
+
|
|
105
|
+
@export_as_api
|
|
106
|
+
def get_n_trading_dates_until(date, n):
|
|
107
|
+
trading_dates = _get_all_trading_dates()
|
|
108
|
+
pos = trading_dates.searchsorted(_to_timestamp(date), side='right')
|
|
109
|
+
if pos >= n:
|
|
110
|
+
return trading_dates[pos - n:pos]
|
|
111
|
+
return trading_dates[:pos]
|
|
112
|
+
|
|
113
|
+
@export_as_api
|
|
114
|
+
def count_trading_dates(start_date, end_date):
|
|
115
|
+
start_date = _to_timestamp(start_date)
|
|
116
|
+
end_date = _to_timestamp(end_date)
|
|
117
|
+
trading_dates = _get_all_trading_dates()
|
|
118
|
+
return trading_dates.searchsorted(end_date, side='right') - trading_dates.searchsorted(start_date)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
if __name__ == "__main__":
|
|
122
|
+
start_date = "2024-01-01"
|
|
123
|
+
end_date = "2024-02-27"
|
|
124
|
+
|
|
125
|
+
trading_dates = get_trading_dates(start_date, end_date)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
from typing import List, Union
|
|
5
|
+
import datetime
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
from libfinance.client import get_client
|
|
9
|
+
from libfinance.utils.decorators import export_as_api, ttl_cache, compatible_with_parm
|
|
10
|
+
from libfinance.utils.datetime_func import convert_dateteime_to_timestamp
|
|
11
|
+
|
|
12
|
+
@export_as_api
|
|
13
|
+
def history_bars(
|
|
14
|
+
order_book_ids: list,
|
|
15
|
+
bar_count: int,
|
|
16
|
+
frequency: str,
|
|
17
|
+
datetime: str,
|
|
18
|
+
fields: List[str]=None,
|
|
19
|
+
skip_suspended: bool=True,
|
|
20
|
+
include_now: bool=True,
|
|
21
|
+
adjust_type: str="none",
|
|
22
|
+
adjust_orig:datetime.datetime = None) -> pd.DataFrame:
|
|
23
|
+
"""获取指定合约的历史 k 线行情,支持任意日频率xd(1d,5d)和任意分钟频率xm(1m,3m,5m,15m)的历史数据。
|
|
24
|
+
|
|
25
|
+
:param order_book_ids: 多个标的合约代码
|
|
26
|
+
:param bar_count: 获取的历史数据数量,必填项
|
|
27
|
+
:param frequency: 获取数据什么样的频率进行。'1d'或'1m'分别表示每日和每分钟,必填项
|
|
28
|
+
:param fields: 返回数据字段。必填项。见下方列表。
|
|
29
|
+
:param skip_suspended: 是否跳过停牌数据
|
|
30
|
+
:param include_now: 是否包含当前数据
|
|
31
|
+
:param adjust_type: 复权类型,默认为前复权 pre;可选 pre, none, post
|
|
32
|
+
|
|
33
|
+
========================= ===================================================
|
|
34
|
+
fields 字段名
|
|
35
|
+
========================= ===================================================
|
|
36
|
+
datetime 时间戳
|
|
37
|
+
open 开盘价
|
|
38
|
+
high 最高价
|
|
39
|
+
low 最低价
|
|
40
|
+
close 收盘价
|
|
41
|
+
volume 成交量
|
|
42
|
+
total_turnover 成交额
|
|
43
|
+
open_interest 持仓量(期货专用)
|
|
44
|
+
basis_spread 期现差(股指期货专用)
|
|
45
|
+
settlement 结算价(期货日线专用)
|
|
46
|
+
prev_settlement 结算价(期货日线专用)
|
|
47
|
+
========================= ===================================================
|
|
48
|
+
|
|
49
|
+
Example1::
|
|
50
|
+
|
|
51
|
+
获取中国平安和万科 2020-04-20之前10天的交易数据
|
|
52
|
+
|
|
53
|
+
.. code-block:: python3
|
|
54
|
+
|
|
55
|
+
import pandas as pd
|
|
56
|
+
from simons.api import history_bars
|
|
57
|
+
|
|
58
|
+
#
|
|
59
|
+
>>> dt = pd.Timestamp("2020-04-20")
|
|
60
|
+
>>> fields=["datetime","open","high","low","close","volume"]
|
|
61
|
+
>>> data = history_bars(order_book_ids=["000001.XSHE", "000002.XSHE"], datatime=dt, bar_count=10, frequency="1d", fields=fields)
|
|
62
|
+
>>> print(data)
|
|
63
|
+
|
|
64
|
+
open high low close volume
|
|
65
|
+
order_book_id datetime
|
|
66
|
+
000001.XSHE 2020-04-07 12.89 12.94 12.81 12.88 87031371.0
|
|
67
|
+
2020-04-08 12.88 12.92 12.72 12.78 52871614.0
|
|
68
|
+
2020-04-09 12.88 12.89 12.72 12.74 40855377.0
|
|
69
|
+
2020-04-10 12.76 12.98 12.65 12.79 66667495.0
|
|
70
|
+
2020-04-13 12.67 12.71 12.47 12.59 44621440.0
|
|
71
|
+
2020-04-14 12.65 12.86 12.57 12.86 68608687.0
|
|
72
|
+
2020-04-15 12.86 12.93 12.78 12.87 65639640.0
|
|
73
|
+
2020-04-16 12.79 12.79 12.54 12.68 78915498.0
|
|
74
|
+
2020-04-17 12.77 13.04 12.65 12.89 133116477.0
|
|
75
|
+
2020-04-20 12.86 13.05 12.77 12.99 81845583.0
|
|
76
|
+
000002.XSHE 2020-04-07 27.34 27.42 26.80 27.07 67154006.0
|
|
77
|
+
2020-04-08 26.90 27.25 26.75 26.96 41251395.0
|
|
78
|
+
2020-04-09 27.10 27.16 26.60 26.69 38726254.0
|
|
79
|
+
2020-04-10 26.84 27.34 26.59 26.88 62460322.0
|
|
80
|
+
2020-04-13 26.74 27.13 26.61 27.04 43264902.0
|
|
81
|
+
2020-04-14 27.10 27.75 27.02 27.35 64241868.0
|
|
82
|
+
2020-04-15 27.20 27.23 26.55 26.70 70359257.0
|
|
83
|
+
2020-04-16 26.52 26.76 26.40 26.58 50238931.0
|
|
84
|
+
2020-04-17 26.78 27.03 26.55 26.72 83813322.0
|
|
85
|
+
2020-04-20 26.78 26.81 26.05 26.58 85012343.0
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
dt = convert_dateteime_to_timestamp(datetime)
|
|
89
|
+
return get_client().multi_history_bars(order_book_ids=order_book_ids,
|
|
90
|
+
bar_count=bar_count,
|
|
91
|
+
frequency=frequency,
|
|
92
|
+
fields=fields,
|
|
93
|
+
dt=dt,
|
|
94
|
+
skip_suspended=skip_suspended,
|
|
95
|
+
include_now=include_now,
|
|
96
|
+
adjust_type=adjust_type,
|
|
97
|
+
adjust_orig=adjust_orig)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import datetime
|
|
5
|
+
from typing import Any, Union, Optional, Iterable, Dict, List, Sequence, Iterable
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
from libfinance.client import get_client
|
|
9
|
+
from libfinance.utils.decorators import export_as_api, ttl_cache, compatible_with_parm
|
|
10
|
+
|
|
11
|
+
@export_as_api
|
|
12
|
+
def get_instrument_industry(order_book_ids: list, date: Union[str, datetime.datetime], source: str = "010303") -> pd.DataFrame():
|
|
13
|
+
|
|
14
|
+
return get_client().get_instrument_industry(order_book_ids=order_book_ids, date=date, source=source)
|
|
15
|
+
|
|
16
|
+
@export_as_api
|
|
17
|
+
def get_index_weights(index_id: str = "000300.XSHG", date: Union[str, datetime.datetime] = None) -> pd.DataFrame:
|
|
18
|
+
return get_client().get_index_weights(index_id=index_id, date = date)
|
|
19
|
+
|
|
20
|
+
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
import time
|
|
4
|
+
import socket
|
|
5
|
+
import threading
|
|
6
|
+
import warnings
|
|
7
|
+
|
|
8
|
+
import pdb
|
|
9
|
+
|
|
10
|
+
import thriftpy2 as thriftpy
|
|
11
|
+
from thriftpy2.rpc import make_client
|
|
12
|
+
from thriftpy2.transport import TTransportException
|
|
13
|
+
try:
|
|
14
|
+
from thriftpy2.protocol.cybin import ProtocolError
|
|
15
|
+
except ImportError:
|
|
16
|
+
ProtocolError = type('FakeProtocolError', (Exception,), {})
|
|
17
|
+
|
|
18
|
+
#from libfinance.thriftclient import libfinance_thrift
|
|
19
|
+
from libfinance.utils.serialize import serialize_object, deserialize_object
|
|
20
|
+
from libfinance.utils.loader import load_thrift_module
|
|
21
|
+
|
|
22
|
+
socket_error = (TTransportException, socket.error, ProtocolError)
|
|
23
|
+
|
|
24
|
+
libfinance_thrift = load_thrift_module(__file__, "libfinance.thrift")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ResponseError(Exception):
|
|
28
|
+
"""响应错误"""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class LibFinanceClient(object):
|
|
33
|
+
|
|
34
|
+
_threading_local = threading.local()
|
|
35
|
+
_auth_params = {}
|
|
36
|
+
|
|
37
|
+
_default_host = "127.0.0.1"
|
|
38
|
+
_default_port = 9090
|
|
39
|
+
|
|
40
|
+
request_timeout = 300
|
|
41
|
+
request_attempt_count = 3
|
|
42
|
+
|
|
43
|
+
def __init__(self, host=None, port=None, username="", password="", token=""):
|
|
44
|
+
self.host = host or self._default_host
|
|
45
|
+
self.port = int(port or self._default_port)
|
|
46
|
+
self.username = username
|
|
47
|
+
self.password = password
|
|
48
|
+
self.token = token
|
|
49
|
+
|
|
50
|
+
assert self.host, "host is required"
|
|
51
|
+
assert self.port, "port is required"
|
|
52
|
+
#assert self.username or self.token, "username is required"
|
|
53
|
+
#assert self.password or self.token, "password is required"
|
|
54
|
+
|
|
55
|
+
self.client = None
|
|
56
|
+
self.inited = False
|
|
57
|
+
self.not_auth = True
|
|
58
|
+
self.compress = True
|
|
59
|
+
self.data_api_url = ""
|
|
60
|
+
self._http_token = ""
|
|
61
|
+
|
|
62
|
+
self._create_client()
|
|
63
|
+
|
|
64
|
+
def _create_client(self):
|
|
65
|
+
self.client = make_client(
|
|
66
|
+
libfinance_thrift.LibfinanceService,
|
|
67
|
+
self.host,
|
|
68
|
+
self.port,
|
|
69
|
+
timeout=(self.request_timeout * 1000)
|
|
70
|
+
)
|
|
71
|
+
return self.client
|
|
72
|
+
|
|
73
|
+
def __getattr__(self, api_name):
|
|
74
|
+
return lambda **kwargs: self(api_name, **kwargs)
|
|
75
|
+
|
|
76
|
+
def __call__(self, api_name, **kwargs):
|
|
77
|
+
err, result = None, None
|
|
78
|
+
for attempt_index in range(self.request_attempt_count):
|
|
79
|
+
try:
|
|
80
|
+
result = self.query(api_name, kwargs)
|
|
81
|
+
break
|
|
82
|
+
except socket_error as ex:
|
|
83
|
+
if (
|
|
84
|
+
isinstance(ex, socket.timeout) or
|
|
85
|
+
"TSocket read 0 bytes" in str(ex) or
|
|
86
|
+
not self._ping_server()
|
|
87
|
+
):
|
|
88
|
+
self._reset()
|
|
89
|
+
err = ex
|
|
90
|
+
if attempt_index < self.request_attempt_count - 1:
|
|
91
|
+
time.sleep(0.6)
|
|
92
|
+
except ResponseError as ex:
|
|
93
|
+
err = ex
|
|
94
|
+
|
|
95
|
+
if result is None and isinstance(err, Exception):
|
|
96
|
+
if "TSocket read 0 bytes" in str(err):
|
|
97
|
+
raise Exception("连接被关闭,请减少数据查询量或检查网络后重试")
|
|
98
|
+
raise err
|
|
99
|
+
|
|
100
|
+
return result
|
|
101
|
+
|
|
102
|
+
def query(self, api_name, params):
|
|
103
|
+
|
|
104
|
+
request = libfinance_thrift.St_Query_Req()
|
|
105
|
+
request.api_name = api_name
|
|
106
|
+
request.params = serialize_object(params)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
result = None
|
|
110
|
+
try:
|
|
111
|
+
#pdb.set_trace()
|
|
112
|
+
#self.ensure_auth()
|
|
113
|
+
response = self.client.query(request)
|
|
114
|
+
#pdb.set_trace()
|
|
115
|
+
if response.status is False:
|
|
116
|
+
# error occur
|
|
117
|
+
# raise RuntimeError(response.msg)
|
|
118
|
+
warnings.warn(response.msg)
|
|
119
|
+
|
|
120
|
+
# get process result
|
|
121
|
+
result = deserialize_object(response.result)
|
|
122
|
+
except Exception as e:
|
|
123
|
+
print(e)
|
|
124
|
+
raise RuntimeError("error:{}".format(e))
|
|
125
|
+
|
|
126
|
+
return result
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
_CLIENT = LibFinanceClient()
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def get_client():
|
|
133
|
+
return _CLIENT
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__":
|
|
139
|
+
client = LibFinanceClient()
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
#output = client.get_trading_dates(start_date="2024-01-01",end_date="2024-02-22")
|
|
143
|
+
#print(output)
|
|
144
|
+
|
|
145
|
+
output = client.get_trading_dates("2024-01-01","2024-02-22")
|
|
146
|
+
print(output)
|
|
147
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
struct St_Query_Req {
|
|
2
|
+
1:required string api_name,
|
|
3
|
+
2:required binary params,
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
struct St_Query_Rsp {
|
|
7
|
+
1:required bool status,
|
|
8
|
+
2:optional string msg,
|
|
9
|
+
3:optional binary result
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
service LibfinanceService {
|
|
13
|
+
St_Query_Rsp query(1:St_Query_Req request),
|
|
14
|
+
St_Query_Rsp auth(1:string username, 2:string password)//, 5:bool compress, 8:string mac, 10:string version),
|
|
15
|
+
St_Query_Rsp auth_by_token(1: string token)
|
|
16
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
import six
|
|
4
|
+
import datetime
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
def convert_datetime_to_str(dt):
|
|
8
|
+
if dt is None:
|
|
9
|
+
return None
|
|
10
|
+
if isinstance(dt, pd.Timestamp):
|
|
11
|
+
dt = dt.to_pydatetime()
|
|
12
|
+
if isinstance(dt, six.string_types):
|
|
13
|
+
return dt
|
|
14
|
+
if isinstance(dt, datetime.datetime):
|
|
15
|
+
return dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
16
|
+
if isinstance(dt, datetime.date):
|
|
17
|
+
return dt.strftime("%Y-%m-%d")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def convert_dateteime_to_timestamp(dt):
|
|
21
|
+
if isinstance(dt, pd.Timestamp):
|
|
22
|
+
return dt
|
|
23
|
+
|
|
24
|
+
if isinstance(dt, ((str, datetime.date, datetime.datetime))):
|
|
25
|
+
return pd.Timestamp(dt)
|
|
26
|
+
return dt
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import time
|
|
5
|
+
import types
|
|
6
|
+
import warnings
|
|
7
|
+
from functools import wraps, partial, update_wrapper
|
|
8
|
+
|
|
9
|
+
import libfinance
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def deprecated(func=None, msg=None):
|
|
13
|
+
if func is None:
|
|
14
|
+
return partial(deprecated, msg=msg)
|
|
15
|
+
|
|
16
|
+
if msg is None:
|
|
17
|
+
msg = func.__name__ + " is deprecated, and will be removed in future."
|
|
18
|
+
|
|
19
|
+
@wraps(func)
|
|
20
|
+
def wrap(*args, **kwargs):
|
|
21
|
+
warnings.warn(msg, category=DeprecationWarning, stacklevel=0)
|
|
22
|
+
return func(*args, **kwargs)
|
|
23
|
+
|
|
24
|
+
return wrap
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def export_as_api(f=None, name=None, namespace=None, priority=0):
|
|
28
|
+
if f is None:
|
|
29
|
+
return partial(export_as_api, name=name, namespace=namespace)
|
|
30
|
+
name = name if name else f.__name__
|
|
31
|
+
if namespace:
|
|
32
|
+
if hasattr(libfinance, namespace):
|
|
33
|
+
namespace = getattr(libfinance, namespace)
|
|
34
|
+
else:
|
|
35
|
+
namespace_name = namespace
|
|
36
|
+
namespace = types.ModuleType(namespace_name)
|
|
37
|
+
namespace.__file__ = 'libfinance plugin'
|
|
38
|
+
namespace.__module__ = "libfinance"
|
|
39
|
+
setattr(libfinance, namespace_name, namespace)
|
|
40
|
+
libfinance.__all__.append(namespace_name)
|
|
41
|
+
else:
|
|
42
|
+
namespace = libfinance
|
|
43
|
+
libfinance.__all__.append(name)
|
|
44
|
+
|
|
45
|
+
old_f = getattr(namespace, name, None)
|
|
46
|
+
if old_f is not None:
|
|
47
|
+
if old_f.__priority > priority:
|
|
48
|
+
warnings.warn("!!!! CAN'T OVERWRITE API {} WITH {} BECAUSE OLD PRIPORITY {} > {} !!!!".format(name, f, old_f.__priority, priority))
|
|
49
|
+
return f
|
|
50
|
+
warnings.warn("!!!! OVERWRITE API {} WITH {} !!!!".format(name, f))
|
|
51
|
+
|
|
52
|
+
f.__priority = priority
|
|
53
|
+
setattr(namespace, name, f)
|
|
54
|
+
|
|
55
|
+
return f
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def retry(count, suppress_exceptions, delay=1.0):
|
|
59
|
+
def decorate(func):
|
|
60
|
+
@wraps(func)
|
|
61
|
+
def wrap(*args, **kwargs):
|
|
62
|
+
c = count
|
|
63
|
+
while c > 0:
|
|
64
|
+
try:
|
|
65
|
+
return func(*args, **kwargs)
|
|
66
|
+
except suppress_exceptions as e:
|
|
67
|
+
c -= 1
|
|
68
|
+
if c == 0:
|
|
69
|
+
raise e
|
|
70
|
+
if delay:
|
|
71
|
+
time.sleep(delay)
|
|
72
|
+
|
|
73
|
+
return wrap
|
|
74
|
+
|
|
75
|
+
return decorate
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def coroutine(func):
|
|
79
|
+
@wraps(func)
|
|
80
|
+
def primer(*args, **kwargs):
|
|
81
|
+
gen = func(*args, **kwargs)
|
|
82
|
+
next(gen)
|
|
83
|
+
return gen
|
|
84
|
+
|
|
85
|
+
return primer
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
_ttl_cached_functions = set()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def ttl_cache(ttl):
|
|
92
|
+
if not isinstance(ttl, int) or not ttl > 0:
|
|
93
|
+
raise TypeError("Expected ttl to be a positive integer")
|
|
94
|
+
|
|
95
|
+
def decorating_function(user_function):
|
|
96
|
+
wrapper = _ttl_cache_wrapper(user_function, ttl)
|
|
97
|
+
_ttl_cached_functions.add(wrapper)
|
|
98
|
+
return update_wrapper(wrapper, user_function)
|
|
99
|
+
|
|
100
|
+
return decorating_function
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def ttl_cache_clear():
|
|
104
|
+
for f in _ttl_cached_functions:
|
|
105
|
+
f.clear()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _ttl_cache_wrapper(user_function, ttl):
|
|
109
|
+
sentinel = object()
|
|
110
|
+
cache = {}
|
|
111
|
+
cache_get = cache.get # bound method to lookup a key or return None
|
|
112
|
+
cache_clear = cache.clear
|
|
113
|
+
|
|
114
|
+
def wrapper(*args, **kwargs):
|
|
115
|
+
if kwargs:
|
|
116
|
+
key = args + (repr(sorted(kwargs.items())),)
|
|
117
|
+
else:
|
|
118
|
+
key = args
|
|
119
|
+
|
|
120
|
+
# in cpython, dict.get is thread-safe
|
|
121
|
+
result = cache_get(key, sentinel)
|
|
122
|
+
if result is not sentinel:
|
|
123
|
+
expire_at, value = result
|
|
124
|
+
if expire_at > time.time():
|
|
125
|
+
return value
|
|
126
|
+
value = user_function(*args, **kwargs)
|
|
127
|
+
cache[key] = (time.time() + ttl, value)
|
|
128
|
+
return value
|
|
129
|
+
|
|
130
|
+
setattr(wrapper, 'clear', cache_clear)
|
|
131
|
+
return wrapper
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def compatible_with_parm(func=None, name=None, value=None, replace=None):
|
|
135
|
+
if func is None:
|
|
136
|
+
return partial(compatible_with_parm, name=name, value=value, replace=replace)
|
|
137
|
+
|
|
138
|
+
@wraps(func)
|
|
139
|
+
def wrap(*args, **kwargs):
|
|
140
|
+
if name:
|
|
141
|
+
if name in kwargs:
|
|
142
|
+
msg = "'{}' is no longer used, please use '{}' instead ".format(name, replace)
|
|
143
|
+
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
|
|
144
|
+
item = kwargs.pop(name)
|
|
145
|
+
if item != value:
|
|
146
|
+
raise ValueError("'{}': except '{}', got '{}'".format(name, value, item))
|
|
147
|
+
return func(*args, **kwargs)
|
|
148
|
+
|
|
149
|
+
return wrap
|
|
150
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import thriftpy2
|
|
5
|
+
|
|
6
|
+
from typing import Any
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def load_thrift_module(dir_or_file: str, thrift_file: str = "") -> Any:
|
|
11
|
+
"""加载thrift模块
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
dir_or_file (str): .thrift所在的文件或文件夹路径,若是文件则取当前文件所在目录为默认根目录
|
|
15
|
+
thrift_file (str, optional): thrift文件名全称,如果未提供,则默认按传入的文件名进行解析
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
Any: thrifty配置文件加载后的实例
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
>>> load_thrift_module(__file__, "pingpong.thrift")
|
|
22
|
+
<module 'pingpong_thrift'>
|
|
23
|
+
>>> load_thrift_module("/home/user/pingpong.thrift")
|
|
24
|
+
<module 'pingpong_thrift'>
|
|
25
|
+
"""
|
|
26
|
+
# current file absolute working directory
|
|
27
|
+
working_dir = Path(dir_or_file).absolute()
|
|
28
|
+
# if file get file directory
|
|
29
|
+
if working_dir.is_file():
|
|
30
|
+
working_dir = working_dir.parent
|
|
31
|
+
thrift_file = thrift_file or working_dir.name
|
|
32
|
+
# is file name valid
|
|
33
|
+
if len(thrift_file) == 0:
|
|
34
|
+
raise ValueError(
|
|
35
|
+
"thrift file name is empty, please check path '{}' contains ".format(dir_or_file) +
|
|
36
|
+
"file name or given 'thrift_file' parameter when called 'load_thrift_module' function."
|
|
37
|
+
)
|
|
38
|
+
# convert file name from 'demo.thrifty' to module name 'demo_thrifty'
|
|
39
|
+
thrift_module_name = thrift_file.replace(".", "_")
|
|
40
|
+
# thriftpy2 do not support pathlib
|
|
41
|
+
thrift_module = thriftpy2.load(path=str(working_dir.joinpath(thrift_file)),
|
|
42
|
+
module_name=thrift_module_name)
|
|
43
|
+
|
|
44
|
+
return thrift_module
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
import dill
|
|
4
|
+
import pickle
|
|
5
|
+
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def serialize_object(obj: Any, protocol: int = pickle.DEFAULT_PROTOCOL) -> bytes:
|
|
10
|
+
"""serialize obj to bytes
|
|
11
|
+
|
|
12
|
+
protocol v5 only available in python3.8,it`s a new feature that can accelerate memory process efficiency.
|
|
13
|
+
We highly recommend use v5,but to adapt more other python version choose protocol v4 as default,consider
|
|
14
|
+
adding a new api in 'Handle' class to sync client and server protocol.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
obj (object): almost support all python standard types,exclude frame, generator, traceback
|
|
18
|
+
protocol (int, optional): protocol can be 0-5,refer to https://docs.python.org/zh-cn/3/library/pickle.html#pickle-protocols
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
bytes: serialize value
|
|
22
|
+
"""
|
|
23
|
+
return dill.dumps(obj, protocol=protocol)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def deserialize_object(stream: bytes) -> Any:
|
|
27
|
+
"""deserialize bytes to object
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
stream (bytes): serialize bytes
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Any: deserialize object
|
|
34
|
+
"""
|
|
35
|
+
if stream is None:
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
return dill.loads(stream)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: libfinance
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: libfinance
|
|
5
|
+
Home-page:
|
|
6
|
+
Author:
|
|
7
|
+
Author-email:
|
|
8
|
+
License: Apache License v2
|
|
9
|
+
Classifier: Programming Language :: Python
|
|
10
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
11
|
+
Classifier: Operating System :: Unix
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Requires-Dist: dill>=0.3.8
|
|
15
|
+
Requires-Dist: thriftpy2>=0.3.9
|
|
16
|
+
Requires-Dist: pandas>=0.16.2
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
libfinance/__init__.py
|
|
4
|
+
libfinance/client.py
|
|
5
|
+
libfinance/libfinance.thrift
|
|
6
|
+
libfinance/version.py
|
|
7
|
+
libfinance.egg-info/PKG-INFO
|
|
8
|
+
libfinance.egg-info/SOURCES.txt
|
|
9
|
+
libfinance.egg-info/dependency_links.txt
|
|
10
|
+
libfinance.egg-info/not-zip-safe
|
|
11
|
+
libfinance.egg-info/requires.txt
|
|
12
|
+
libfinance.egg-info/top_level.txt
|
|
13
|
+
libfinance/api/__init__.py
|
|
14
|
+
libfinance/api/calendar.py
|
|
15
|
+
libfinance/api/get_price.py
|
|
16
|
+
libfinance/api/index_components.py
|
|
17
|
+
libfinance/utils/__init__.py
|
|
18
|
+
libfinance/utils/datetime_func.py
|
|
19
|
+
libfinance/utils/decorators.py
|
|
20
|
+
libfinance/utils/loader.py
|
|
21
|
+
libfinance/utils/serialize.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
libfinance
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
from os.path import dirname, join
|
|
4
|
+
|
|
5
|
+
from setuptools import find_packages, setup
|
|
6
|
+
|
|
7
|
+
from libfinance.version import __version__
|
|
8
|
+
|
|
9
|
+
def read_file(file):
|
|
10
|
+
with open(file, "rt") as f:
|
|
11
|
+
return f.read()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
setup(
|
|
15
|
+
name='libfinance',
|
|
16
|
+
version=__version__,
|
|
17
|
+
description='libfinance',
|
|
18
|
+
packages=find_packages(exclude=[]),
|
|
19
|
+
author='',
|
|
20
|
+
author_email='',
|
|
21
|
+
license='Apache License v2',
|
|
22
|
+
package_data={'': ['*.*']},
|
|
23
|
+
url='',
|
|
24
|
+
install_requires=["dill>=0.3.8", "thriftpy2>=0.3.9","pandas>=0.16.2"],
|
|
25
|
+
zip_safe=False,
|
|
26
|
+
classifiers=[
|
|
27
|
+
'Programming Language :: Python',
|
|
28
|
+
'Operating System :: Microsoft :: Windows',
|
|
29
|
+
'Operating System :: Unix',
|
|
30
|
+
'Programming Language :: Python :: 3.7',
|
|
31
|
+
'Programming Language :: Python :: 3.8',
|
|
32
|
+
],
|
|
33
|
+
)
|