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.
Files changed (31) hide show
  1. neurostats_API/__init__.py +1 -1
  2. neurostats_API/fetchers/balance_sheet.py +152 -102
  3. neurostats_API/fetchers/base.py +93 -74
  4. neurostats_API/fetchers/cash_flow.py +143 -113
  5. neurostats_API/fetchers/finance_overview.py +28 -28
  6. neurostats_API/fetchers/institution.py +211 -97
  7. neurostats_API/fetchers/margin_trading.py +121 -94
  8. neurostats_API/fetchers/month_revenue.py +139 -105
  9. neurostats_API/fetchers/profit_lose.py +203 -108
  10. neurostats_API/fetchers/tech.py +117 -42
  11. neurostats_API/fetchers/tej_finance_report.py +248 -338
  12. neurostats_API/fetchers/value_invest.py +32 -12
  13. neurostats_API/tools/company_list/tw.json +2175 -0
  14. neurostats_API/tools/tej_db/tej_db_percent_index.yaml +0 -3
  15. neurostats_API/tools/tej_db/tej_db_skip_index.yaml +14 -1
  16. neurostats_API/tools/tej_db/tej_db_thousand_index.yaml +0 -5
  17. neurostats_API/utils/__init__.py +0 -1
  18. neurostats_API/utils/calculate_value.py +102 -1
  19. neurostats_API/utils/data_process.py +53 -19
  20. neurostats_API/utils/logger.py +21 -0
  21. {neurostats_API-0.0.21b0.dist-info → neurostats_API-0.0.23.dist-info}/METADATA +2 -2
  22. neurostats_API-0.0.23.dist-info/RECORD +35 -0
  23. neurostats_API/utils/fetcher.py +0 -1056
  24. neurostats_API-0.0.21b0.dist-info/RECORD +0 -34
  25. /neurostats_API/tools/{balance_sheet.yaml → twse/balance_sheet.yaml} +0 -0
  26. /neurostats_API/tools/{cash_flow_percentage.yaml → twse/cash_flow_percentage.yaml} +0 -0
  27. /neurostats_API/tools/{finance_overview_dict.yaml → twse/finance_overview_dict.yaml} +0 -0
  28. /neurostats_API/tools/{profit_lose.yaml → twse/profit_lose.yaml} +0 -0
  29. /neurostats_API/tools/{seasonal_data_field_dict.txt → twse/seasonal_data_field_dict.txt} +0 -0
  30. {neurostats_API-0.0.21b0.dist-info → neurostats_API-0.0.23.dist-info}/WHEEL +0 -0
  31. {neurostats_API-0.0.21b0.dist-info → neurostats_API-0.0.23.dist-info}/top_level.txt +0 -0
@@ -29,9 +29,6 @@ TWN/AINVFQ1:
29
29
  - r607
30
30
  - r613
31
31
  - r612
32
- - r609
33
- - r614
34
- - r611
35
32
  TWN/AFESTM1:
36
33
  - r105
37
34
  - r106
@@ -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
@@ -42,7 +42,6 @@ TWN/AINVFQ1:
42
42
  - isibt
43
43
  - isni
44
44
  - isnip
45
- - eps
46
45
  - ispsd
47
46
  - gm
48
47
  - opi
@@ -57,10 +56,6 @@ TWN/AINVFQ1:
57
56
  - person
58
57
  - shares
59
58
  - wavg
60
- - r304
61
- - r305
62
- - r306
63
- - r316
64
59
  - r834
65
60
  TWN/AFESTM1:
66
61
  - ip12
@@ -1,5 +1,4 @@
1
1
  from .datetime import StatsDateTime
2
2
  from .db_client import DBClient
3
3
  from .data_process import StatsProcessor
4
- from .fetcher import StatsFetcher
5
4
  from .calculate_value import YoY_Calculator
@@ -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 YoY
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
- return f"mode Error: Get mode should be {list(target_metric_dict.keys())} but get {mode}"
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
- sliced_table = total_table.loc[target_index, desired_order].T
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.loc[:, desired_order]
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 *= 1000
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['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
- return_dict[pop_key] = data[data_key]
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.21b0
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.21b0
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,,