neurostats-API 0.0.19__tar.gz → 0.0.21__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.
Files changed (42) hide show
  1. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/PKG-INFO +26 -15
  2. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/README.md +24 -13
  3. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/__init__.py +1 -1
  4. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/base.py +78 -88
  5. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/month_revenue.py +48 -1
  6. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/tech.py +1 -1
  7. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/tej_finance_report.py +36 -2
  8. neurostats_api-0.0.21/neurostats_API/tools/tej_db/tej_db_percent_index.yaml +44 -0
  9. neurostats_api-0.0.21/neurostats_API/tools/tej_db/tej_db_skip_index.yaml +20 -0
  10. neurostats_api-0.0.21/neurostats_API/tools/tej_db/tej_db_thousand_index.yaml +71 -0
  11. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/utils/data_process.py +8 -2
  12. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API.egg-info/PKG-INFO +26 -15
  13. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API.egg-info/SOURCES.txt +4 -5
  14. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API.egg-info/requires.txt +1 -1
  15. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/setup.py +3 -3
  16. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/test/test_tej.py +7 -7
  17. neurostats_api-0.0.19/neurostats_API/tools/balance_sheet.yaml +0 -35
  18. neurostats_api-0.0.19/neurostats_API/tools/cash_flow_percentage.yaml +0 -39
  19. neurostats_api-0.0.19/neurostats_API/tools/finance_overview_dict.yaml +0 -185
  20. neurostats_api-0.0.19/neurostats_API/tools/profit_lose.yaml +0 -143
  21. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/MANIFEST.in +0 -0
  22. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/cli.py +0 -0
  23. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/__init__.py +0 -0
  24. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/balance_sheet.py +0 -0
  25. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/cash_flow.py +0 -0
  26. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/finance_overview.py +0 -0
  27. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/institution.py +0 -0
  28. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/margin_trading.py +0 -0
  29. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/profit_lose.py +0 -0
  30. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/fetchers/value_invest.py +0 -0
  31. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/main.py +0 -0
  32. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/tools/seasonal_data_field_dict.txt +0 -0
  33. {neurostats_api-0.0.19/neurostats_API/tools → neurostats_api-0.0.21/neurostats_API/tools/tej_db}/tej_db_index.yaml +0 -0
  34. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/utils/__init__.py +0 -0
  35. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/utils/calculate_value.py +0 -0
  36. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/utils/datetime.py +0 -0
  37. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/utils/db_client.py +0 -0
  38. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API/utils/fetcher.py +0 -0
  39. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API.egg-info/dependency_links.txt +0 -0
  40. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/neurostats_API.egg-info/top_level.txt +0 -0
  41. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/setup.cfg +0 -0
  42. {neurostats_api-0.0.19 → neurostats_api-0.0.21}/test/test_fetchers.py +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: neurostats_API
3
- Version: 0.0.19
3
+ Version: 0.0.21
4
4
  Summary: The service of NeuroStats website
5
5
  Home-page: https://github.com/NeurowattStats/NeuroStats_API.git
6
6
  Author: JasonWang@Neurowatt
7
7
  Author-email: jason@neurowatt.ai
8
8
  Requires-Python: >=3.6
9
9
  Description-Content-Type: text/markdown
10
- Requires-Dist: numpy>=2.1.0
10
+ Requires-Dist: numpy
11
11
  Requires-Dist: pandas>=2.2.0
12
12
  Requires-Dist: pymongo
13
13
  Requires-Dist: pytz
@@ -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.16
92
+ 0.0.21
93
93
  ```
94
94
 
95
95
  ### 得到最新一期的評價資料與歷年評價
@@ -236,6 +236,15 @@ data = fetcher.query_data()
236
236
  grand_total_YoY_5 1.691300e+02 ... NaN
237
237
  grand_total_YoY_10 NaN ... NaN
238
238
 
239
+ "recent_month_revenue":
240
+ date 2024/11 2024/10 ... 2024/1 2023/12
241
+ revenue 51243946000 45451116000 ... 56451418000 55329015000
242
+ MoM 12.75% -14.77% ... 2.03% -0.52%
243
+ YoY -7.87% -30.00% ... -7.36% -11.13%
244
+ total_YoY -6.93% -6.84% ... -7.36% -15.97%
245
+ accum_YoY 85.84% 78.65% ... 7.92% 84.03%
246
+ # total_YoY為當月累計營收 / 上一年的當月累計營收
247
+ # accum_YoY為當月累計營收 / 上一年的總營收
239
248
 
240
249
  }
241
250
  ```
@@ -728,6 +737,7 @@ data = fetcher.get(
728
737
  #### 回傳資料
729
738
  ##### `YOY_NOCAL` 與 `QOQ_NOCAL`
730
739
  為回傳`pd.DataFrame`,column名稱為<年份>Q<季>, row名稱為指定財報項目
740
+
731
741
  ```Python
732
742
  # fetch_mode = fetcher.FetchMode.QOQ_NOCAL
733
743
  2024Q3 2024Q2 2024Q1
@@ -742,17 +752,18 @@ bp51 3.111298e+09 3.173919e+09 2.453840e+09
742
752
 
743
753
  ##### `YOY` 與 `QOQ`
744
754
  回傳為`Dict[pd.DataFrame]`, key 為指定的index, DataFrame中則是該index歷年的數值與成長率
755
+ 成長率單位為`%`
745
756
  ```Python
746
757
  # fetch_mode = fetcher.FetchMode.QOQ
747
758
  {
748
- 'bp41':
759
+ 'bp41':
749
760
  2024Q3 2024Q2 2024Q1
750
761
  value 7.082005e+07 6.394707e+07 5.761001e+07
751
- growth 1.074791e-01 1.099994e-01 5.532101e-03,
752
- 'bp51':
762
+ growth 10.75% 11.00% 0.55%,
763
+ 'bp51':
753
764
  2024Q3 2024Q2 2024Q1
754
765
  value 3.111298e+09 3.145373e+09 3.091985e+09
755
- growth -1.083335e-02 1.726663e-02 -4.159542e-03
766
+ growth -1.08% 1.73% -0.42%
756
767
  }
757
768
 
758
769
  # fetch_mode = fetcher.FetchMode.YOY
@@ -760,17 +771,17 @@ growth -1.083335e-02 1.726663e-02 -4.159542e-03
760
771
  'bp41':
761
772
  2024Q3 2023Q3 2022Q3
762
773
  value 7.082005e+07 5.377231e+07 6.201822e+07
763
- YoY_1 NaN NaN 4.130744e-01
764
- YoY_3 1.729171e-01 9.556684e-02 1.883274e-01
765
- YoY_5 1.389090e-01 1.215242e-01 1.642914e-01
766
- YoY_10 1.255138e-01 1.356297e-01 1.559702e-01,
774
+ YoY_1 31.70% -13.30% 41.31%
775
+ YoY_3 17.29% 9.56% 18.83%
776
+ YoY_5 13.89% 12.15% 16.43%
777
+ YoY_10 12.55% 13.56% 15.60% ,
767
778
  'bp51':
768
779
  2024Q3 2023Q3 2022Q3
769
780
  value 3.111298e+09 3.173919e+09 2.453840e+09
770
- YoY_1 NaN NaN 3.179539e-01
771
- YoY_3 1.866752e-01 2.766851e-01 2.638677e-01
772
- YoY_5 2.068132e-01 2.479698e-01 1.815106e-01
773
- YoY_10 1.420500e-01 1.586797e-01 1.551364e-01
781
+ YoY_1 -1.97% 29.34% 31.80%
782
+ YoY_3 18.67% 27.67% 26.39%
783
+ YoY_5 20.68% 24.80% 18.15%
784
+ YoY_10 14.20% 15.87% 15.51%
774
785
  }
775
786
  ```
776
787
 
@@ -73,7 +73,7 @@ pip install neurostats-API
73
73
  ```Python
74
74
  >>> import neurostats_API
75
75
  >>> print(neurostats_API.__version__)
76
- 0.0.16
76
+ 0.0.21
77
77
  ```
78
78
 
79
79
  ### 得到最新一期的評價資料與歷年評價
@@ -220,6 +220,15 @@ data = fetcher.query_data()
220
220
  grand_total_YoY_5 1.691300e+02 ... NaN
221
221
  grand_total_YoY_10 NaN ... NaN
222
222
 
223
+ "recent_month_revenue":
224
+ date 2024/11 2024/10 ... 2024/1 2023/12
225
+ revenue 51243946000 45451116000 ... 56451418000 55329015000
226
+ MoM 12.75% -14.77% ... 2.03% -0.52%
227
+ YoY -7.87% -30.00% ... -7.36% -11.13%
228
+ total_YoY -6.93% -6.84% ... -7.36% -15.97%
229
+ accum_YoY 85.84% 78.65% ... 7.92% 84.03%
230
+ # total_YoY為當月累計營收 / 上一年的當月累計營收
231
+ # accum_YoY為當月累計營收 / 上一年的總營收
223
232
 
224
233
  }
225
234
  ```
@@ -712,6 +721,7 @@ data = fetcher.get(
712
721
  #### 回傳資料
713
722
  ##### `YOY_NOCAL` 與 `QOQ_NOCAL`
714
723
  為回傳`pd.DataFrame`,column名稱為<年份>Q<季>, row名稱為指定財報項目
724
+
715
725
  ```Python
716
726
  # fetch_mode = fetcher.FetchMode.QOQ_NOCAL
717
727
  2024Q3 2024Q2 2024Q1
@@ -726,17 +736,18 @@ bp51 3.111298e+09 3.173919e+09 2.453840e+09
726
736
 
727
737
  ##### `YOY` 與 `QOQ`
728
738
  回傳為`Dict[pd.DataFrame]`, key 為指定的index, DataFrame中則是該index歷年的數值與成長率
739
+ 成長率單位為`%`
729
740
  ```Python
730
741
  # fetch_mode = fetcher.FetchMode.QOQ
731
742
  {
732
- 'bp41':
743
+ 'bp41':
733
744
  2024Q3 2024Q2 2024Q1
734
745
  value 7.082005e+07 6.394707e+07 5.761001e+07
735
- growth 1.074791e-01 1.099994e-01 5.532101e-03,
736
- 'bp51':
746
+ growth 10.75% 11.00% 0.55%,
747
+ 'bp51':
737
748
  2024Q3 2024Q2 2024Q1
738
749
  value 3.111298e+09 3.145373e+09 3.091985e+09
739
- growth -1.083335e-02 1.726663e-02 -4.159542e-03
750
+ growth -1.08% 1.73% -0.42%
740
751
  }
741
752
 
742
753
  # fetch_mode = fetcher.FetchMode.YOY
@@ -744,17 +755,17 @@ growth -1.083335e-02 1.726663e-02 -4.159542e-03
744
755
  'bp41':
745
756
  2024Q3 2023Q3 2022Q3
746
757
  value 7.082005e+07 5.377231e+07 6.201822e+07
747
- YoY_1 NaN NaN 4.130744e-01
748
- YoY_3 1.729171e-01 9.556684e-02 1.883274e-01
749
- YoY_5 1.389090e-01 1.215242e-01 1.642914e-01
750
- YoY_10 1.255138e-01 1.356297e-01 1.559702e-01,
758
+ YoY_1 31.70% -13.30% 41.31%
759
+ YoY_3 17.29% 9.56% 18.83%
760
+ YoY_5 13.89% 12.15% 16.43%
761
+ YoY_10 12.55% 13.56% 15.60% ,
751
762
  'bp51':
752
763
  2024Q3 2023Q3 2022Q3
753
764
  value 3.111298e+09 3.173919e+09 2.453840e+09
754
- YoY_1 NaN NaN 3.179539e-01
755
- YoY_3 1.866752e-01 2.766851e-01 2.638677e-01
756
- YoY_5 2.068132e-01 2.479698e-01 1.815106e-01
757
- YoY_10 1.420500e-01 1.586797e-01 1.551364e-01
765
+ YoY_1 -1.97% 29.34% 31.80%
766
+ YoY_3 18.67% 27.67% 26.39%
767
+ YoY_5 20.68% 24.80% 18.15%
768
+ YoY_10 14.20% 15.87% 15.51%
758
769
  }
759
770
  ```
760
771
 
@@ -1,4 +1,4 @@
1
- __version__='0.0.19'
1
+ __version__='0.0.20'
2
2
 
3
3
  from .fetchers import (
4
4
  BalanceSheetFetcher,
@@ -81,10 +81,14 @@ class BaseTEJFetcher(abc.ABC):
81
81
 
82
82
  def get_latest_data_time(self, ticker):
83
83
  latest_data = self.collection.find_one(
84
- {"ticker": ticker}, {
84
+ {
85
+ "ticker": ticker
86
+ },
87
+ {
85
88
  "last_update": 1,
86
89
  "_id": 0
87
- })
90
+ }
91
+ )
88
92
 
89
93
  try:
90
94
  latest_date = latest_data['last_update']["latest_data_date"]
@@ -93,82 +97,78 @@ class BaseTEJFetcher(abc.ABC):
93
97
 
94
98
  return latest_date
95
99
 
96
- def cal_YoY(
97
- self, data_dict: dict, start_year: int, end_year: int, season: int):
100
+ def process_value(self, value):
101
+ if isinstance(value, str) and "%" in value:
102
+ value = value.replace("%", "")
103
+ try:
104
+ return float(value)
105
+ except (ValueError, TypeError):
106
+ return None
107
+
108
+ def calculate_growth(self, this_value, last_value, delta):
109
+ try:
110
+ return YoY_Calculator.cal_growth(this_value, last_value, delta) * 100
111
+ except Exception:
112
+ return None
113
+
114
+ def cal_YoY(self, data_dict: dict, start_year: int, end_year: int, season: int):
98
115
  year_shifts = [1, 3, 5, 10]
99
116
  return_dict = {}
117
+
100
118
  for year in range(start_year, end_year + 1):
101
- try:
102
- year_data = data_dict[f"{year}Q{season}"].copy()
103
- except KeyError as e:
119
+ year_data = data_dict.get(f"{year}Q{season}", {}).copy()
120
+ if not year_data:
104
121
  continue
105
-
106
- year_keys = list(year_data.keys())
107
- for key in year_keys:
108
- if (key in 'season'):
122
+
123
+ for key in list(year_data.keys()):
124
+ if key == "season":
109
125
  continue
110
-
111
- if (isinstance(year_data[key], (int, float))):
112
- temp_dict = {"value": year_data[key]}
113
-
114
- for shift in year_shifts:
115
- this_value = year_data[key]
116
- try:
117
- past_year = year - shift
118
- last_value = data_dict[f"{past_year}Q{season}"][key]
119
- temp_dict[
120
- f"YoY_{shift}"] = YoY_Calculator.cal_growth(
121
- this_value, last_value, delta=shift)
122
- except Exception as e:
123
- temp_dict[f"YoY_{shift}"] = None
124
-
125
- year_data[key] = temp_dict
126
-
127
- else:
126
+
127
+ this_value = self.process_value(year_data[key])
128
+ if this_value is None:
128
129
  year_data.pop(key)
129
-
130
+ continue
131
+
132
+ temp_dict = {"value": year_data[key]}
133
+ for shift in year_shifts:
134
+ past_year = year - shift
135
+ last_value = data_dict.get(f"{past_year}Q{season}", {}).get(key)
136
+ last_value = self.process_value(last_value)
137
+ growth = self.calculate_growth(this_value, last_value, shift) if last_value is not None else None
138
+
139
+ temp_dict[f"YoY_{shift}"] = (f"{growth:.2f}%" if growth else None)
140
+ year_data[key] = temp_dict
141
+
130
142
  return_dict[f"{year}Q{season}"] = year_data
131
-
143
+
132
144
  return return_dict
133
145
 
134
146
  def cal_QoQ(self, data_dict):
135
147
  return_dict = {}
136
- for i, time_index in enumerate(data_dict.keys()):
137
- year, season = time_index.split("Q")
138
- year = int(year)
139
- season = int(season)
140
- if (season == 1):
141
- last_year = year - 1
142
- last_season = 4
143
- else:
144
- last_year = year
145
- last_season = season - 1
146
-
147
- this_data = data_dict[time_index]
148
- this_keys = list(this_data.keys())
149
- for key in this_keys:
150
- if (key in 'season'):
148
+
149
+ for time_index, this_data in data_dict.items():
150
+ year, season = map(int, time_index.split("Q"))
151
+ last_year, last_season = (year - 1, 4) if season == 1 else (year, season - 1)
152
+
153
+ for key in list(this_data.keys()):
154
+ if key == "season":
151
155
  continue
152
-
153
- this_value = this_data[key]
154
-
155
- if (isinstance(this_value, (int, float))):
156
- temp_dict = {"value": this_value}
157
-
158
- try:
159
- last_value = data_dict[f"{last_year}Q{last_season}"][
160
- key]['value']
161
-
162
- temp_dict['growth'] = YoY_Calculator.cal_growth(
163
- this_value, last_value, delta=1)
164
- except Exception as e:
165
- temp_dict['growth'] = None
166
-
167
- this_data[key] = temp_dict
168
-
169
- else:
156
+
157
+ this_value = self.process_value(this_data[key])
158
+ if this_value is None:
170
159
  this_data.pop(key)
160
+ continue
161
+
162
+ temp_dict = {"value": this_data[key]}
163
+ last_value = data_dict.get(f"{last_year}Q{last_season}", {}).get(key, {}).get('value')
164
+ last_value = self.process_value(last_value)
165
+ growth = self.calculate_growth(this_value, last_value, 1) if last_value is not None else None
166
+ temp_dict['growth'] = (f"{growth:.2f}%" if growth else None)
167
+
168
+ this_data[key] = temp_dict
169
+
171
170
  return_dict[time_index] = this_data
171
+
172
172
  return return_dict
173
173
 
174
174
  def get_dict_of_df(self, data_dict):
@@ -180,31 +180,21 @@ class BaseTEJFetcher(abc.ABC):
180
180
  return data_dict
181
181
 
182
182
  def set_time_shift(self, date: Union[str, datetime], period: str):
183
- if (isinstance(date, str)):
183
+ if isinstance(date, str):
184
184
  date = datetime.strptime(date, "%Y-%m-%d")
185
- if (period == '1d'):
186
- return date - timedelta(days=1)
187
-
188
- elif (period == '7d'):
189
- return date - timedelta(days=7)
190
185
 
191
- elif (period == '1m'):
192
- return date - timedelta(days=30)
193
-
194
- elif (period == '3m'):
195
- return date - timedelta(days=90)
196
-
197
- elif (period == '1y'):
198
- return date - timedelta(days=365)
199
-
200
- elif (period == '3y'):
201
- return date - timedelta(days=365 * 3)
202
-
203
- elif (period == '5y'):
204
- return date - timedelta(days=365 * 5)
205
-
206
- elif (period == '10y'):
207
- return date - timedelta(days=365 * 10)
186
+ period_mapping = {
187
+ "1d": timedelta(days=1),
188
+ "7d": timedelta(days=7),
189
+ "1m": timedelta(days=30),
190
+ "3m": timedelta(days=90),
191
+ "1y": timedelta(days=365),
192
+ "3y": timedelta(days=365 * 3),
193
+ "5y": timedelta(days=365 * 5),
194
+ "10y": timedelta(days=365 * 10),
195
+ }
208
196
 
209
- elif (period == 'all'):
197
+ if period == "all":
210
198
  return datetime.strptime("1991-01-01", "%Y-%m-%d")
199
+
200
+ return date - period_mapping.get(period, timedelta(days=0)) # 預設為不變"
@@ -1,7 +1,7 @@
1
1
  from .base import StatsFetcher, StatsDateTime
2
2
  import json
3
3
  import pandas as pd
4
- from ..utils import StatsDateTime, StatsProcessor
4
+ from ..utils import StatsDateTime, StatsProcessor, YoY_Calculator
5
5
  import importlib.resources as pkg_resources
6
6
  import yaml
7
7
 
@@ -77,7 +77,9 @@ class MonthRevenueFetcher(StatsFetcher):
77
77
  postfix="千元")
78
78
  target_month = monthly_data[0]['month']
79
79
  monthly_df = pd.DataFrame(monthly_data)
80
+
80
81
  target_month_df = monthly_df[monthly_df['month'] == target_month]
82
+ annual_month_df = monthly_df[monthly_df['month'] == 12]
81
83
  month_revenue_df = monthly_df.pivot(index='month',
82
84
  columns='year',
83
85
  values='revenue')
@@ -86,6 +88,10 @@ class MonthRevenueFetcher(StatsFetcher):
86
88
  columns='year',
87
89
  values='grand_total')
88
90
 
91
+ annual_total_df = annual_month_df.pivot(index='month',
92
+ columns='year',
93
+ values='grand_total')
94
+
89
95
  grand_total_df.rename(index={target_month: f"grand_total"},
90
96
  inplace=True)
91
97
  month_revenue_df = month_revenue_df.sort_index(ascending=False)
@@ -111,4 +117,45 @@ class MonthRevenueFetcher(StatsFetcher):
111
117
 
112
118
  fetched_data.pop("monthly_data")
113
119
 
120
+ fetched_data['recent_month_revenue'] = self.get_recent_revenue_grwoth(
121
+ monthly_data, grand_total_dict=annual_total_df.to_dict(), interval = 12
122
+ )
123
+
114
124
  return fetched_data
125
+
126
+ def get_recent_revenue_grwoth(self, monthly_data, grand_total_dict, interval: int = 12):
127
+ recent_month_data = monthly_data[:interval + 1]
128
+
129
+ MoMs = [
130
+ YoY_Calculator.cal_growth(this_value['revenue'], last_value['revenue'], delta = 1)
131
+ for this_value, last_value in zip(
132
+ recent_month_data[:12], recent_month_data[1:13]
133
+ )
134
+ ]
135
+
136
+ recent_month_data = {
137
+ "date" : [f"{data['year']}/{data['month']}" for data in recent_month_data[:interval]],
138
+ "revenue" : [data['revenue'] for data in recent_month_data[:interval]],
139
+ "MoM" : [f"{(data * 100):.2f}%" for data in MoMs],
140
+ "YoY" : [f"{data['revenue_increment_ratio']}" for data in recent_month_data[:interval]],
141
+ "total_YoY": [f"{data['grand_total_increment_ratio']}" for data in recent_month_data[:interval]],
142
+ }
143
+
144
+ # accum_YoY
145
+ # accum_YoY 為 Davis提出的定義
146
+ # 2024/6的累計YoY(accum_YoY) 為 2024累計到6月為止的總營收/2023年度總營收
147
+ accum_YoYs = []
148
+ for data in monthly_data[:interval]:
149
+ try:
150
+ year = data['year'] - 1
151
+ total = grand_total_dict[year][12]
152
+ accum_YoY = round((data['grand_total'] / total) * 100, 2)
153
+ accum_YoYs.append(f"{accum_YoY}%")
154
+ except Exception as e:
155
+ accum_YoYs.append(None)
156
+
157
+ recent_month_data['accum_YoY'] = accum_YoYs
158
+
159
+ recent_month_df = pd.DataFrame(recent_month_data).set_index('date').T
160
+
161
+ return recent_month_df
@@ -85,7 +85,7 @@ class TechFetcher(StatsFetcher):
85
85
  ticker_full = self.collection.find_one(query)
86
86
 
87
87
  if not ticker_full:
88
- raise
88
+ raise ValueError("No ticker found in database")
89
89
 
90
90
  daily_data = ticker_full.get("data", [])
91
91
  if not isinstance(daily_data, list):
@@ -20,15 +20,23 @@ class FinanceReportFetcher(BaseTEJFetcher):
20
20
  def __init__(
21
21
  self,
22
22
  mongo_uri,
23
- db_name=".company",
23
+ db_name="company",
24
24
  collection_name="TWN/AINVFQ1"
25
25
  ):
26
26
  self.client = MongoClient(mongo_uri)
27
27
  self.db = self.client[db_name]
28
28
  self.collection = self.db[collection_name]
29
29
 
30
- index_dict = StatsProcessor.load_yaml("tej_db_index.yaml")
30
+ index_dict = StatsProcessor.load_yaml("tej_db/tej_db_index.yaml")
31
+ thousand_dict = StatsProcessor.load_yaml("tej_db/tej_db_thousand_index.yaml")
32
+ percent_dict = StatsProcessor.load_yaml("tej_db/tej_db_percent_index.yaml")
33
+ skip_dict = StatsProcessor.load_yaml("tej_db/tej_db_percent_index.yaml")
31
34
  self.check_index = set(index_dict[collection_name])
35
+ self.skip_index = set(skip_dict[collection_name])
36
+
37
+ self.thousand_index_list = list(thousand_dict[collection_name])
38
+ self.percent_index_list = list(percent_dict[collection_name])
39
+
32
40
 
33
41
  def get(
34
42
  self,
@@ -234,6 +242,8 @@ class FinanceReportFetcher(BaseTEJFetcher):
234
242
  keys=["year", "season"],
235
243
  delimeter="Q",
236
244
  data_key=report_type)
245
+
246
+ data_dict = self.transform_value(data_dict)
237
247
 
238
248
  if (use_cal):
239
249
  data_with_QoQ = self.cal_QoQ(data_dict)
@@ -347,6 +357,8 @@ class FinanceReportFetcher(BaseTEJFetcher):
347
357
  keys=['year', 'season'],
348
358
  data_key=report_type,
349
359
  delimeter='Q')
360
+
361
+ data_dict = self.transform_value(data_dict)
350
362
 
351
363
  if (use_cal):
352
364
  data_with_YoY = self.cal_YoY(
@@ -360,7 +372,29 @@ class FinanceReportFetcher(BaseTEJFetcher):
360
372
  data_df = pd.DataFrame.from_dict(data_dict)
361
373
  data_df = data_df.iloc[:, ::-1]
362
374
  return data_df
375
+
376
+ def transform_value(self, data_dict):
377
+ """
378
+ 處理千元, %等單位
379
+ """
363
380
 
381
+ data_df = pd.DataFrame.from_dict(data_dict)
382
+
383
+ process_set = set(data_df.index).intersection(set(self.thousand_index_list))
384
+ process_list = list(process_set)
385
+ data_df.loc[process_list] = data_df.loc[process_list].map(
386
+ lambda x : StatsProcessor.cal_non_percentage(x, postfix="千元")
387
+ )
388
+
389
+ process_set = set(data_df.index).intersection(set(self.percent_index_list))
390
+ process_list = list(process_set)
391
+ data_df.loc[process_list] = data_df.loc[process_list].map(
392
+ lambda x : f"{x}%"
393
+ )
394
+
395
+ data_dict = data_df.to_dict()
396
+
397
+ return data_dict
364
398
 
365
399
  class TEJStockPriceFetcher(BaseTEJFetcher):
366
400
 
@@ -0,0 +1,44 @@
1
+ TWN/AINVFQ1:
2
+ - taxrate
3
+ - r104
4
+ - r115
5
+ - r105
6
+ - r106
7
+ - r107
8
+ - r108
9
+ - r201
10
+ - r112
11
+ - r401
12
+ - r402
13
+ - r403
14
+ - r404
15
+ - r405
16
+ - r408
17
+ - r409
18
+ - r410
19
+ - r502
20
+ - r501
21
+ - r205
22
+ - r505
23
+ - r517
24
+ - r512
25
+ - r509
26
+ - r608
27
+ - r616
28
+ - r610
29
+ - r607
30
+ - r613
31
+ - r612
32
+ - r609
33
+ - r614
34
+ - r611
35
+ TWN/AFESTM1:
36
+ - r105
37
+ - r106
38
+ - r107
39
+ - r108
40
+ - r401
41
+ - r402
42
+ - r403
43
+ - r404
44
+ - r405
@@ -0,0 +1,20 @@
1
+ TWN/AINVFQ1:
2
+ - coid
3
+ - mdate
4
+ - key3
5
+ - 'no'
6
+ - sem
7
+ - merg
8
+ - curr
9
+ - annd
10
+ - fin_ind
11
+ TWN/AFESTM1:
12
+ - coid
13
+ - mdate
14
+ - key3
15
+ - 'no'
16
+ - sem
17
+ - merg
18
+ - curr
19
+ - annd
20
+ - fin_ind
@@ -0,0 +1,71 @@
1
+ TWN/AINVFQ1:
2
+ - bp11
3
+ - bp21
4
+ - bp22
5
+ - bp31
6
+ - bp41
7
+ - bp51
8
+ - bp53
9
+ - bp61
10
+ - bp62
11
+ - bp63
12
+ - bp64
13
+ - bp65
14
+ - bf11
15
+ - bf12
16
+ - bf21
17
+ - bf22
18
+ - bf41
19
+ - bf42
20
+ - bf43
21
+ - bf44
22
+ - bf45
23
+ - bf99
24
+ - bsca
25
+ - bsnca
26
+ - bsta
27
+ - bscl
28
+ - bsncl
29
+ - bstl
30
+ - bsse
31
+ - bslse
32
+ - debt
33
+ - quick
34
+ - ppe
35
+ - ar
36
+ - ip12
37
+ - ip22
38
+ - ip31
39
+ - ip51
40
+ - iv41
41
+ - if11
42
+ - isibt
43
+ - isni
44
+ - isnip
45
+ - eps
46
+ - ispsd
47
+ - gm
48
+ - opi
49
+ - nri
50
+ - ri
51
+ - nopi
52
+ - ebit
53
+ - cip31
54
+ - cscfo
55
+ - cscfi
56
+ - cscff
57
+ - person
58
+ - shares
59
+ - wavg
60
+ - r304
61
+ - r305
62
+ - r306
63
+ - r316
64
+ - r834
65
+ TWN/AFESTM1:
66
+ - ip12
67
+ - gm
68
+ - opi
69
+ - isibt
70
+ - isni
71
+ - isnip