neurostats-API 0.0.21b0__py3-none-any.whl → 0.0.23__py3-none-any.whl
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.
- neurostats_API/__init__.py +1 -1
- neurostats_API/fetchers/balance_sheet.py +152 -102
- neurostats_API/fetchers/base.py +93 -74
- neurostats_API/fetchers/cash_flow.py +143 -113
- neurostats_API/fetchers/finance_overview.py +28 -28
- neurostats_API/fetchers/institution.py +211 -97
- neurostats_API/fetchers/margin_trading.py +121 -94
- neurostats_API/fetchers/month_revenue.py +139 -105
- neurostats_API/fetchers/profit_lose.py +203 -108
- neurostats_API/fetchers/tech.py +117 -42
- neurostats_API/fetchers/tej_finance_report.py +248 -338
- neurostats_API/fetchers/value_invest.py +32 -12
- neurostats_API/tools/company_list/tw.json +2175 -0
- neurostats_API/tools/tej_db/tej_db_percent_index.yaml +0 -3
- neurostats_API/tools/tej_db/tej_db_skip_index.yaml +14 -1
- neurostats_API/tools/tej_db/tej_db_thousand_index.yaml +0 -5
- neurostats_API/utils/__init__.py +0 -1
- neurostats_API/utils/calculate_value.py +102 -1
- neurostats_API/utils/data_process.py +53 -19
- neurostats_API/utils/logger.py +21 -0
- {neurostats_API-0.0.21b0.dist-info → neurostats_API-0.0.23.dist-info}/METADATA +2 -2
- neurostats_API-0.0.23.dist-info/RECORD +35 -0
- neurostats_API/utils/fetcher.py +0 -1056
- neurostats_API-0.0.21b0.dist-info/RECORD +0 -34
- /neurostats_API/tools/{balance_sheet.yaml → twse/balance_sheet.yaml} +0 -0
- /neurostats_API/tools/{cash_flow_percentage.yaml → twse/cash_flow_percentage.yaml} +0 -0
- /neurostats_API/tools/{finance_overview_dict.yaml → twse/finance_overview_dict.yaml} +0 -0
- /neurostats_API/tools/{profit_lose.yaml → twse/profit_lose.yaml} +0 -0
- /neurostats_API/tools/{seasonal_data_field_dict.txt → twse/seasonal_data_field_dict.txt} +0 -0
- {neurostats_API-0.0.21b0.dist-info → neurostats_API-0.0.23.dist-info}/WHEEL +0 -0
- {neurostats_API-0.0.21b0.dist-info → neurostats_API-0.0.23.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,14 @@ TWN/AINVFQ1:
|
|
8
8
|
- curr
|
9
9
|
- annd
|
10
10
|
- fin_ind
|
11
|
+
- eps
|
12
|
+
- r307
|
13
|
+
- r305
|
14
|
+
- r306
|
15
|
+
- r316
|
16
|
+
- r609
|
17
|
+
- r614
|
18
|
+
- r611
|
11
19
|
TWN/AFESTM1:
|
12
20
|
- coid
|
13
21
|
- mdate
|
@@ -17,4 +25,9 @@ TWN/AFESTM1:
|
|
17
25
|
- merg
|
18
26
|
- curr
|
19
27
|
- annd
|
20
|
-
- fin_ind
|
28
|
+
- fin_ind
|
29
|
+
- eps
|
30
|
+
- r307
|
31
|
+
- r305
|
32
|
+
- r306
|
33
|
+
- r316
|
neurostats_API/utils/__init__.py
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
from .data_process import StatsProcessor
|
2
|
+
import numpy as np
|
1
3
|
class YoY_Calculator:
|
2
4
|
def __init__(self):
|
3
5
|
pass
|
@@ -22,5 +24,104 @@ class YoY_Calculator:
|
|
22
24
|
|
23
25
|
if (isinstance(YoY, complex)): # 年化成長率有複數問題
|
24
26
|
return None
|
27
|
+
|
28
|
+
if YoY != YoY: # 確認是否為nan (Python 中 nan不等於自己)
|
29
|
+
return None
|
30
|
+
|
31
|
+
return YoY
|
32
|
+
@classmethod
|
33
|
+
def calculate_growth(cls, this_value, last_value, delta):
|
34
|
+
try:
|
35
|
+
return YoY_Calculator.cal_growth(
|
36
|
+
this_value, last_value, delta
|
37
|
+
) * 100
|
38
|
+
except Exception:
|
39
|
+
return None
|
40
|
+
|
41
|
+
@classmethod
|
42
|
+
def cal_YoY(
|
43
|
+
cls, data_dict: dict
|
44
|
+
):
|
45
|
+
year_shifts = [1, 3, 5, 10]
|
46
|
+
return_dict = {}
|
47
|
+
|
48
|
+
for time_index in data_dict.keys():
|
49
|
+
year, season = map(int, time_index.split("Q"))
|
50
|
+
|
51
|
+
year_data = data_dict.get(f"{year}Q{season}", {}).copy()
|
52
|
+
if not year_data:
|
53
|
+
continue
|
54
|
+
|
55
|
+
for key, data in list(year_data.items()):
|
56
|
+
if key in ["year", "season"]:
|
57
|
+
continue
|
58
|
+
|
59
|
+
if (isinstance(data, dict)):
|
60
|
+
temp_dict = data
|
61
|
+
value = data.get("value", None)
|
62
|
+
else:
|
63
|
+
temp_dict = {"value": data}
|
64
|
+
value = data
|
65
|
+
|
66
|
+
this_value = StatsProcessor.process_str_to_float(value)
|
67
|
+
|
68
|
+
for shift in year_shifts:
|
69
|
+
past_value = data_dict.get(f"{year - shift}Q{season}", {}).get(key, {})
|
70
|
+
if (isinstance(past_value, dict)):
|
71
|
+
past_value = past_value.get('value', None)
|
72
|
+
past_value = StatsProcessor.process_str_to_float(
|
73
|
+
past_value
|
74
|
+
)
|
75
|
+
|
76
|
+
growth = cls.calculate_growth(this_value, past_value, shift) if past_value else None
|
77
|
+
|
78
|
+
temp_dict[
|
79
|
+
f"YoY_{shift}"
|
80
|
+
] = f"{growth:.2f}%" if growth else None
|
81
|
+
|
82
|
+
year_data[key] = temp_dict
|
83
|
+
return_dict[f"{year}Q{season}"] = year_data
|
84
|
+
return return_dict
|
85
|
+
@classmethod
|
86
|
+
def cal_QoQ(cls, data_dict):
|
87
|
+
return_dict = {}
|
88
|
+
|
89
|
+
for time_index, this_data in data_dict.items():
|
90
|
+
year, season = map(int, time_index.split("Q"))
|
91
|
+
last_year, last_season = (
|
92
|
+
year - 1, 4
|
93
|
+
) if season == 1 else (year, season - 1)
|
94
|
+
|
95
|
+
for key in list(this_data.keys()):
|
96
|
+
if key == "season":
|
97
|
+
continue
|
98
|
+
|
99
|
+
value = this_data.get(key, None)
|
100
|
+
|
101
|
+
if (isinstance(value, dict)):
|
102
|
+
temp_dict = value
|
103
|
+
this_value = value.get("value", None)
|
104
|
+
else:
|
105
|
+
temp_dict = {"value": value}
|
106
|
+
this_value = value
|
107
|
+
|
108
|
+
this_value = StatsProcessor.process_str_to_float(this_value)
|
109
|
+
|
110
|
+
last_value = data_dict.get(
|
111
|
+
f"{last_year}Q{last_season}",{}
|
112
|
+
).get(key, {})
|
113
|
+
|
114
|
+
if (isinstance(last_value, dict)):
|
115
|
+
last_value = last_value.get("value", None)
|
116
|
+
|
117
|
+
last_value = StatsProcessor.process_str_to_float(last_value)
|
118
|
+
growth = cls.calculate_growth(
|
119
|
+
this_value, last_value, 1
|
120
|
+
) if last_value is not None else None
|
121
|
+
temp_dict['growth'] = (f"{growth:.2f}%" if growth else None)
|
122
|
+
|
123
|
+
this_data[key] = temp_dict
|
124
|
+
|
125
|
+
return_dict[time_index] = this_data
|
25
126
|
|
26
|
-
return
|
127
|
+
return return_dict
|
@@ -36,6 +36,14 @@ class StatsProcessor:
|
|
36
36
|
data = yaml.safe_load(f)
|
37
37
|
|
38
38
|
return data
|
39
|
+
|
40
|
+
@classmethod
|
41
|
+
def load_json(cls, filename):
|
42
|
+
yaml_path = files('neurostats_API.tools').joinpath(filename)
|
43
|
+
with open(yaml_path, 'r', encoding='utf-8') as f:
|
44
|
+
data = json.load(f)
|
45
|
+
|
46
|
+
return data
|
39
47
|
|
40
48
|
@classmethod
|
41
49
|
def expand_value_percentage(cls, dataframe):
|
@@ -52,6 +60,23 @@ class StatsProcessor:
|
|
52
60
|
expanded_df = pd.concat(expanded_columns.values(), axis=1)
|
53
61
|
|
54
62
|
return expanded_df
|
63
|
+
|
64
|
+
@classmethod
|
65
|
+
def slice_old_table(
|
66
|
+
cls,
|
67
|
+
total_table,
|
68
|
+
target_index,
|
69
|
+
):
|
70
|
+
"""
|
71
|
+
對舊格式的轉換
|
72
|
+
對只有單層column的table,切出想要的index
|
73
|
+
"""
|
74
|
+
|
75
|
+
if (target_index):
|
76
|
+
target_index = target_index.split()
|
77
|
+
return total_table.loc[target_index, :]
|
78
|
+
else:
|
79
|
+
return total_table
|
55
80
|
|
56
81
|
@classmethod
|
57
82
|
def slice_table(
|
@@ -61,30 +86,24 @@ class StatsProcessor:
|
|
61
86
|
target_index=None, # None or Str, 要特別抓哪個index
|
62
87
|
):
|
63
88
|
"""
|
64
|
-
total_table: column應為 <時間>_
|
65
|
-
對只有單層column的table,切出想要的index
|
89
|
+
total_table: column應為 <時間>_<季>
|
66
90
|
"""
|
67
|
-
times = [
|
68
|
-
column.split("_")[0] for column in total_table.columns.unique()
|
69
|
-
] #取出timeIndex
|
70
91
|
try:
|
71
92
|
target_metrics = target_metric_dict[mode]
|
72
93
|
except KeyError as e:
|
73
|
-
|
74
|
-
|
75
|
-
desired_order = [
|
76
|
-
f"{time}_{value_name}" for time in times
|
77
|
-
for value_name in target_metrics
|
78
|
-
]
|
94
|
+
raise ValueError(f"mode Error: Get mode should be {list(target_metric_dict.keys())} but get {mode}")
|
79
95
|
|
80
96
|
if (target_index):
|
81
|
-
target_index = target_index.split()
|
82
|
-
|
97
|
+
target_index = [index_name.strip() for index_name in target_index.split()]
|
98
|
+
desired_order = []
|
99
|
+
for index_name in target_index:
|
100
|
+
desired_order += [f"{index_name}_{metric_name}" for metric_name in target_metrics]
|
101
|
+
sliced_table = total_table.loc[desired_order, :].T
|
83
102
|
|
84
103
|
return sliced_table.T
|
85
104
|
|
86
105
|
else:
|
87
|
-
return total_table
|
106
|
+
return total_table
|
88
107
|
|
89
108
|
@classmethod
|
90
109
|
def slice_multi_col_table(
|
@@ -172,7 +191,11 @@ class StatsProcessor:
|
|
172
191
|
@classmethod
|
173
192
|
def cal_percentage(cls, value, postfix="%"):
|
174
193
|
if (isinstance(value, (float, int))):
|
194
|
+
if (np.isnan(value)):
|
195
|
+
return None
|
175
196
|
value = np.round(value * 100, 2).item()
|
197
|
+
if (value != value): # nan值發生
|
198
|
+
return None
|
176
199
|
value = f"{value:.2f}{postfix}"
|
177
200
|
|
178
201
|
return value
|
@@ -183,10 +206,11 @@ class StatsProcessor:
|
|
183
206
|
@classmethod
|
184
207
|
def cal_non_percentage(cls, value, to_str=False, postfix="元"):
|
185
208
|
if (isinstance(value, (float, int))):
|
186
|
-
|
209
|
+
if (np.isnan(value)):
|
210
|
+
return None
|
187
211
|
value = np.round(value, 2).item()
|
188
212
|
if (postfix == "千元"):
|
189
|
-
value
|
213
|
+
value = value * 1000
|
190
214
|
try:
|
191
215
|
value = int(value)
|
192
216
|
except Exception as e:
|
@@ -264,7 +288,7 @@ class StatsProcessor:
|
|
264
288
|
if (key):
|
265
289
|
keys = [key]
|
266
290
|
for data in data_list:
|
267
|
-
data = data
|
291
|
+
data = data.get("data")
|
268
292
|
|
269
293
|
pop_keys = []
|
270
294
|
|
@@ -273,6 +297,16 @@ class StatsProcessor:
|
|
273
297
|
pop_keys.append(str(data.pop(key)))
|
274
298
|
|
275
299
|
pop_key = delimeter.join(pop_keys)
|
276
|
-
|
300
|
+
target_data = data.get(data_key)
|
301
|
+
return_dict[pop_key] = target_data
|
277
302
|
|
278
|
-
return return_dict
|
303
|
+
return return_dict
|
304
|
+
|
305
|
+
@classmethod
|
306
|
+
def process_str_to_float(cls, value):
|
307
|
+
if isinstance(value, str) and "%" in value:
|
308
|
+
value = value.replace("%", "")
|
309
|
+
try:
|
310
|
+
return float(value)
|
311
|
+
except (ValueError, TypeError) as e:
|
312
|
+
return None
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import logging
|
2
|
+
from functools import wraps
|
3
|
+
|
4
|
+
class StatsLogger:
|
5
|
+
|
6
|
+
@classmethod
|
7
|
+
def exception_log(cls, default_return=None, level='error'):
|
8
|
+
def decorator(func):
|
9
|
+
@wraps(func)
|
10
|
+
def wrapper(*args, **kwargs):
|
11
|
+
try:
|
12
|
+
return func(*args, **kwargs)
|
13
|
+
except Exception as e:
|
14
|
+
log_fn = getattr(logging, level, logging.error)
|
15
|
+
log_fn(
|
16
|
+
f"{func.__name__} failed | args={args}, kwargs={kwargs} | error={e}",
|
17
|
+
exc_info=True
|
18
|
+
)
|
19
|
+
return default_return
|
20
|
+
return wrapper
|
21
|
+
return decorator
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: neurostats_API
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.23
|
4
4
|
Summary: The service of NeuroStats website
|
5
5
|
Home-page: https://github.com/NeurowattStats/NeuroStats_API.git
|
6
6
|
Author: JasonWang@Neurowatt
|
@@ -89,7 +89,7 @@ pip install neurostats-API
|
|
89
89
|
```Python
|
90
90
|
>>> import neurostats_API
|
91
91
|
>>> print(neurostats_API.__version__)
|
92
|
-
0.0.
|
92
|
+
0.0.23
|
93
93
|
```
|
94
94
|
|
95
95
|
### 得到最新一期的評價資料與歷年評價
|
@@ -0,0 +1,35 @@
|
|
1
|
+
neurostats_API/__init__.py,sha256=0pjIrvtZhJd0auAFx4I4qYYyZ_HkE_94paLzWPLv7E8,288
|
2
|
+
neurostats_API/cli.py,sha256=UJSWLIw03P24p-gkBb6JSEI5dW5U12UvLf1L8HjQD-o,873
|
3
|
+
neurostats_API/main.py,sha256=QcsfmWivg2Dnqw3MTJWiI0QvEiRs0VuH-BjwQHFCv00,677
|
4
|
+
neurostats_API/fetchers/__init__.py,sha256=KCw-yRSDFa3fw83u73LJ9OVop7gRl_YQYlQq-cITxuo,511
|
5
|
+
neurostats_API/fetchers/balance_sheet.py,sha256=j2bDFk_IwdNhGRy32wfVGz8Y8-S-gtyIZmT-uRNzH80,6889
|
6
|
+
neurostats_API/fetchers/base.py,sha256=fHdZJtBZ6OD1IUbW6sUTXsPJVWrj41Ay4TOJChp2keI,7236
|
7
|
+
neurostats_API/fetchers/cash_flow.py,sha256=7VznJBKwGyc4EBL9uB7x19zg0JRgZcNrvBAviTNns6k,7978
|
8
|
+
neurostats_API/fetchers/finance_overview.py,sha256=xRn4UF2iMS13ztsFgBFj4UykyJsWMriuUevNeZHQR7E,27815
|
9
|
+
neurostats_API/fetchers/institution.py,sha256=f-Z_Kd6-gnOM8bE7tqWKFnvlMGiE-pGZbsc0JCIobcU,14786
|
10
|
+
neurostats_API/fetchers/margin_trading.py,sha256=0enMPpq0J55uts0nJFHOylXvLEMWZYSb-gt1BH5_gBM,11430
|
11
|
+
neurostats_API/fetchers/month_revenue.py,sha256=K1WZct6vLU3y_8uaXR3po5jzx2w3EYb2v3XkIX2_pBE,8313
|
12
|
+
neurostats_API/fetchers/profit_lose.py,sha256=M-Ngn1l6FbulRurrs2BzlrP0iAeeNF9n5TdIoDa4G_s,9164
|
13
|
+
neurostats_API/fetchers/tech.py,sha256=TsS8m25Otc3_2jTYITFe-wNHlDWcfWsHIxhOrqL8qMY,16016
|
14
|
+
neurostats_API/fetchers/tej_finance_report.py,sha256=NHBqs1xbJ_IuXcBluNJyoZO4BYqmFN76UW201ss3R14,11936
|
15
|
+
neurostats_API/fetchers/value_invest.py,sha256=QxQS2GcoLIU9ZBDEo8iRK2yHd8YLmBS70Bq42F3IsSw,8295
|
16
|
+
neurostats_API/tools/company_list/tw.json,sha256=VWaDFvd0ACCVSWItcHHpmVuM_RzP71jLZl9RBHztu-0,51332
|
17
|
+
neurostats_API/tools/tej_db/tej_db_index.yaml,sha256=lu-cmbB6dhx0eUlBSkyzXWqPKlwRtEvqlMTAh2y0oHs,969
|
18
|
+
neurostats_API/tools/tej_db/tej_db_percent_index.yaml,sha256=xSgmamEK0DUBKRllUb94p9TxhJln_BzFoFYK9OJ0fkM,302
|
19
|
+
neurostats_API/tools/tej_db/tej_db_skip_index.yaml,sha256=6UtMfPL7XvkKvEWTFXIIUZMJWZSagIduLYJb-r3HEg8,246
|
20
|
+
neurostats_API/tools/tej_db/tej_db_thousand_index.yaml,sha256=K2YFBSrxqX1V2upy0IUeQ4ung4aPrjtlqYSvCGaaO8I,479
|
21
|
+
neurostats_API/tools/twse/balance_sheet.yaml,sha256=6XygNG_Ybb1Xkk1e39LMLKr7ATvaCP3xxuwFbgNl6dA,673
|
22
|
+
neurostats_API/tools/twse/cash_flow_percentage.yaml,sha256=fk2Z4eb1JjGFvP134eJatHacB7BgTkBenhDJr83w8RE,1345
|
23
|
+
neurostats_API/tools/twse/finance_overview_dict.yaml,sha256=B9nV75StXkrF3yv2-eezzitlJ38eEK86RD_VY6588gQ,2884
|
24
|
+
neurostats_API/tools/twse/profit_lose.yaml,sha256=iyp9asYJ04vAxk_HBUDse_IBy5oVvYHpwsyACg5YEeg,3029
|
25
|
+
neurostats_API/tools/twse/seasonal_data_field_dict.txt,sha256=X8yc_el6p8BH_3FikTqBVFGsvWdXT6MHXLfKfi44334,8491
|
26
|
+
neurostats_API/utils/__init__.py,sha256=uZk08lGPvVIc7MKAvRdZ2FJzgfa8GzsWG_hWAhF6C5U,152
|
27
|
+
neurostats_API/utils/calculate_value.py,sha256=ioPV5VWitJ2NylBi5vwfs-payAUYxWhAiS7aaJjzQKQ,4305
|
28
|
+
neurostats_API/utils/data_process.py,sha256=UlDjKPQHO2JklBQ0402rL6dCPIExyY90gvcLJ1de7sQ,10228
|
29
|
+
neurostats_API/utils/datetime.py,sha256=XJya4G8b_-ZOaBbMXgQjWh2MC4wc-o6goQ7EQJQMWrQ,773
|
30
|
+
neurostats_API/utils/db_client.py,sha256=OYe6yazcR4Aa6jYmy47JrryUeh2NnKGqY2K_lSZe6i8,455
|
31
|
+
neurostats_API/utils/logger.py,sha256=egBiiPGTi5l1FoX_o6EvdGh81R0_k8hFPctSxq8RCoo,693
|
32
|
+
neurostats_API-0.0.23.dist-info/METADATA,sha256=cowuJT-lpruk2usQAIE1K1NoWqgYcRalikHQkb897-w,31618
|
33
|
+
neurostats_API-0.0.23.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
|
34
|
+
neurostats_API-0.0.23.dist-info/top_level.txt,sha256=nSlQPMG0VtXivJyedp4Bkf86EOy2TpW10VGxolXrqnU,15
|
35
|
+
neurostats_API-0.0.23.dist-info/RECORD,,
|