neurostats-API 0.0.21b0__tar.gz → 0.0.23__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 (52) hide show
  1. neurostats_api-0.0.23/MANIFEST.in +9 -0
  2. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/PKG-INFO +2 -2
  3. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/README.md +1 -1
  4. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/__init__.py +1 -1
  5. neurostats_api-0.0.23/neurostats_API/fetchers/balance_sheet.py +201 -0
  6. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/fetchers/base.py +93 -74
  7. neurostats_api-0.0.23/neurostats_API/fetchers/cash_flow.py +221 -0
  8. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/fetchers/finance_overview.py +28 -28
  9. neurostats_api-0.0.23/neurostats_API/fetchers/institution.py +413 -0
  10. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/fetchers/margin_trading.py +121 -94
  11. neurostats_api-0.0.23/neurostats_API/fetchers/month_revenue.py +195 -0
  12. neurostats_api-0.0.23/neurostats_API/fetchers/profit_lose.py +253 -0
  13. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/fetchers/tech.py +117 -42
  14. neurostats_api-0.0.23/neurostats_API/fetchers/tej_finance_report.py +376 -0
  15. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/fetchers/value_invest.py +32 -12
  16. neurostats_api-0.0.23/neurostats_API/tools/company_list/tw.json +2175 -0
  17. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/tools/tej_db/tej_db_percent_index.yaml +0 -3
  18. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/tools/tej_db/tej_db_skip_index.yaml +14 -1
  19. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/tools/tej_db/tej_db_thousand_index.yaml +0 -5
  20. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/utils/__init__.py +0 -1
  21. neurostats_api-0.0.23/neurostats_API/utils/calculate_value.py +127 -0
  22. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/utils/data_process.py +53 -19
  23. neurostats_api-0.0.23/neurostats_API/utils/logger.py +21 -0
  24. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API.egg-info/PKG-INFO +2 -2
  25. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API.egg-info/SOURCES.txt +7 -6
  26. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/setup.py +2 -3
  27. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/test/test_fetchers.py +46 -23
  28. neurostats_api-0.0.21b0/MANIFEST.in +0 -2
  29. neurostats_api-0.0.21b0/neurostats_API/fetchers/balance_sheet.py +0 -151
  30. neurostats_api-0.0.21b0/neurostats_API/fetchers/cash_flow.py +0 -191
  31. neurostats_api-0.0.21b0/neurostats_API/fetchers/institution.py +0 -299
  32. neurostats_api-0.0.21b0/neurostats_API/fetchers/month_revenue.py +0 -161
  33. neurostats_api-0.0.21b0/neurostats_API/fetchers/profit_lose.py +0 -158
  34. neurostats_api-0.0.21b0/neurostats_API/fetchers/tej_finance_report.py +0 -466
  35. neurostats_api-0.0.21b0/neurostats_API/utils/calculate_value.py +0 -26
  36. neurostats_api-0.0.21b0/neurostats_API/utils/fetcher.py +0 -1056
  37. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/cli.py +0 -0
  38. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/fetchers/__init__.py +0 -0
  39. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/main.py +0 -0
  40. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/tools/tej_db/tej_db_index.yaml +0 -0
  41. {neurostats_api-0.0.21b0/neurostats_API/tools → neurostats_api-0.0.23/neurostats_API/tools/twse}/balance_sheet.yaml +0 -0
  42. {neurostats_api-0.0.21b0/neurostats_API/tools → neurostats_api-0.0.23/neurostats_API/tools/twse}/cash_flow_percentage.yaml +0 -0
  43. {neurostats_api-0.0.21b0/neurostats_API/tools → neurostats_api-0.0.23/neurostats_API/tools/twse}/finance_overview_dict.yaml +0 -0
  44. {neurostats_api-0.0.21b0/neurostats_API/tools → neurostats_api-0.0.23/neurostats_API/tools/twse}/profit_lose.yaml +0 -0
  45. {neurostats_api-0.0.21b0/neurostats_API/tools → neurostats_api-0.0.23/neurostats_API/tools/twse}/seasonal_data_field_dict.txt +0 -0
  46. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/utils/datetime.py +0 -0
  47. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API/utils/db_client.py +0 -0
  48. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API.egg-info/dependency_links.txt +0 -0
  49. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API.egg-info/requires.txt +0 -0
  50. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/neurostats_API.egg-info/top_level.txt +0 -0
  51. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/setup.cfg +0 -0
  52. {neurostats_api-0.0.21b0 → neurostats_api-0.0.23}/test/test_tej.py +0 -0
@@ -0,0 +1,9 @@
1
+ recursive-include neurostats_api/tools/tej_db *.yaml
2
+ recursive-include neurostats_api/tools/tej_db *.txt
3
+ recursive-include neurostats_api/tools/tej_db *.json
4
+ recursive-include neurostats_api/tools/twse *.yaml
5
+ recursive-include neurostats_api/tools/twse *.txt
6
+ recursive-include neurostats_api/tools/twse *.json
7
+ recursive-include neurostats_api/tools/company_list *.yaml
8
+ recursive-include neurostats_api/tools/company_list *.txt
9
+ recursive-include neurostats_api/tools/company_list *.json
@@ -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
  ### 得到最新一期的評價資料與歷年評價
@@ -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.21b0
76
+ 0.0.23
77
77
  ```
78
78
 
79
79
  ### 得到最新一期的評價資料與歷年評價
@@ -1,4 +1,4 @@
1
- __version__='0.0.20'
1
+ __version__='0.0.23'
2
2
 
3
3
  from .fetchers import (
4
4
  BalanceSheetFetcher,
@@ -0,0 +1,201 @@
1
+ from .base import StatsFetcher, StatsDateTime
2
+ import json
3
+ import pandas as pd
4
+ from ..utils import StatsDateTime, StatsProcessor
5
+ import yaml
6
+
7
+
8
+ class BalanceSheetFetcher(StatsFetcher):
9
+ """
10
+ 對應iFa.ai -> 財務分析 -> 資產負債表
11
+ """
12
+
13
+ def __init__(self, ticker, db_client):
14
+ super().__init__(ticker, db_client)
15
+ self.table_settings = StatsProcessor.load_yaml("twse/balance_sheet.yaml")
16
+
17
+ self.process_function_map = {
18
+ "twse_stats": self.process_data_twse,
19
+ "us_stats": self.process_data_us
20
+ }
21
+
22
+ self.return_keys = [
23
+ 'balance_sheet', 'total_asset', 'current_asset', 'non_current_asset',
24
+ 'current_debt', 'non_current_debt', 'equity', 'balance_sheet_all', 'balance_sheet_YoY'
25
+ ]
26
+
27
+ def prepare_query(self):
28
+ pipeline = super().prepare_query()
29
+
30
+ name_map = {
31
+ "twse_stats": "balance_sheet",
32
+ "us_stats": "balance_sheet"
33
+ }
34
+
35
+
36
+ chart_name = name_map.get(self.collection_name, "balance_sheet")
37
+
38
+ append_pipeline = [
39
+ {
40
+ "$project": {
41
+ "_id": 0,
42
+ "ticker": 1,
43
+ "company_name": 1,
44
+ "seasonal_data": {
45
+ "$map": {
46
+ "input": {"$ifNull": ["$seasonal_data", []]},
47
+ "as": "season",
48
+ "in": {
49
+ "year": "$$season.year",
50
+ "season": "$$season.season",
51
+ "data": {"$ifNull": [f"$$season.{chart_name}", []]}
52
+ }
53
+ }
54
+ }
55
+ }
56
+ }
57
+ ]
58
+ pipeline = pipeline + append_pipeline
59
+
60
+ return pipeline
61
+
62
+ def collect_data(self):
63
+ return super().collect_data()
64
+
65
+ def query_data(self):
66
+ fetched_data = self.collect_data()
67
+ fetched_data = fetched_data[0]
68
+
69
+ process_fn = self.process_function_map[self.collection_name]
70
+ processed_data = process_fn(fetched_data)
71
+ return processed_data
72
+
73
+ def process_data_twse(self, fetched_data):
74
+ latest_time = StatsDateTime.get_latest_time(
75
+ self.ticker, self.collection
76
+ ).get('last_update_time', {})
77
+ # 取最新時間資料時間,沒取到就預設去年年底
78
+ target_year = latest_time.get('seasonal_data', {}).get(
79
+ 'latest_target_year',
80
+ StatsDateTime.get_today().year - 1
81
+ )
82
+ target_season = latest_time.get('seasonal_data',
83
+ {}).get('latest_season', 4)
84
+
85
+ return_dict = {
86
+ "ticker": self.ticker,
87
+ "company_name": fetched_data['company_name']
88
+ }
89
+ table_dict = {}
90
+
91
+ seasonal_data = fetched_data.get('seasonal_data')
92
+ if not seasonal_data:
93
+ return_dict.update(self._get_empty_structure())
94
+ return return_dict
95
+
96
+ # 將value與percentage跟著年分季度一筆筆取出
97
+ for data in seasonal_data:
98
+ year, season, balance_sheet = data['year'], data['season'], data[
99
+ 'data']
100
+ time_index = f"{year}Q{season}"
101
+
102
+ new_balance_sheet = dict()
103
+ # 蒐集整體的keys
104
+ index_names = list(balance_sheet.keys())
105
+
106
+ table_dict[time_index] = balance_sheet
107
+ # flatten dict:
108
+ # {<key>: {"value": <value>, "percentage": <value>}}
109
+ # -> {<key>_value: <value>, <key>_percentage:<value>}
110
+
111
+ old_balance_sheet = pd.DataFrame(table_dict)
112
+ target_season_col = old_balance_sheet.columns.str.endswith(f"Q{target_season}")
113
+ old_balance_sheet = old_balance_sheet.loc[:, target_season_col]
114
+ old_balance_sheet = StatsProcessor.expand_value_percentage(old_balance_sheet)
115
+
116
+ # 處理QoQ版BalanceSheet
117
+ for time_index, data_dict in table_dict.items():
118
+ new_balance_sheet = self.flatten_dict(
119
+ data_dict,
120
+ indexes = index_names,
121
+ target_keys=["value", "percentage"]
122
+ )
123
+
124
+ table_dict[time_index] = new_balance_sheet
125
+
126
+ total_table = pd.DataFrame.from_dict(table_dict).T
127
+ value_index = total_table.columns.str.endswith("_value")
128
+ value_cols = total_table.loc[:, value_index].columns
129
+ total_table[value_cols] = (
130
+ total_table[value_cols].map(
131
+ lambda x: StatsProcessor.cal_non_percentage(x, postfix="千元"),
132
+ )
133
+ )
134
+
135
+ percentage_index = total_table.columns.str.endswith(
136
+ "_percentage"
137
+ )
138
+ percentage_cols = total_table.loc[:, percentage_index].columns
139
+ total_table[percentage_cols] = (
140
+ total_table[percentage_cols].map(
141
+ lambda x: StatsProcessor.
142
+ cal_non_percentage(x, to_str=True, postfix="%"),
143
+ )
144
+ )
145
+
146
+ total_table = total_table.T
147
+ target_season_columns = total_table.columns.str.endswith(
148
+ f"Q{target_season}"
149
+ )
150
+ total_table_YoY = total_table.loc[:, target_season_columns]
151
+
152
+ for name, setting in self.table_settings.items():
153
+ target_indexes = setting.get('target_index', [None])
154
+ for target_index in target_indexes:
155
+ try:
156
+ return_dict[name] = StatsProcessor.slice_old_table(
157
+ total_table=old_balance_sheet,
158
+ target_index=target_index
159
+ )
160
+ break
161
+ except Exception as e:
162
+ continue
163
+
164
+ return_dict.update(
165
+ {
166
+ "balance_sheet": old_balance_sheet,
167
+ "balance_sheet_all": total_table.copy(),
168
+ "balance_sheet_YoY": total_table_YoY
169
+ }
170
+ )
171
+ return return_dict
172
+
173
+ def process_data_us(self, fetched_data):
174
+ return_dict = {
175
+ "ticker": self.ticker,
176
+ "company_name": fetched_data[-1]['company_name']
177
+ }
178
+
179
+ table_dict = dict()
180
+
181
+ for data in fetched_data:
182
+ year, season, balance_sheet = data['year'], data['season'], data[
183
+ 'balance_sheet']
184
+ table_dict[f"{year}Q{season}"] = balance_sheet
185
+
186
+ table_dict = pd.DataFrame.from_dict(table_dict)
187
+
188
+ return_dict["balance_sheet"] = table_dict
189
+
190
+ latest_season = fetched_data[0]['season']
191
+ target_season_columns = table_dict.columns.str.endswith(
192
+ f"Q{latest_season}"
193
+ )
194
+ table_dict_YoY = table_dict.loc[:, target_season_columns]
195
+ return_dict["balance_sheet_YoY"] = table_dict_YoY
196
+ return return_dict
197
+
198
+ def _get_empty_structure(self):
199
+ return {
200
+ key: pd.DataFrame(columns= pd.Index([], name = 'date')) for key in self.return_keys
201
+ }
@@ -1,22 +1,31 @@
1
1
  import abc
2
- from typing import Union
3
- from pymongo import MongoClient
4
- import pandas as pd
2
+ from datetime import datetime, timedelta, date
5
3
  import json
4
+ import pandas as pd
5
+ from pymongo import MongoClient
6
6
  import pytz
7
- from datetime import datetime, timedelta, date
7
+ from typing import Union
8
8
  from ..utils import StatsDateTime, StatsProcessor, YoY_Calculator
9
- import yaml
10
9
 
11
10
 
12
- class StatsFetcher:
11
+ class StatsFetcher(abc.ABC):
13
12
 
14
- def __init__(self, ticker, db_client):
13
+ def __init__(self, ticker: str, db_client: MongoClient):
15
14
  self.ticker = ticker
16
- self.db = db_client["company"] # Replace with your database name
17
- self.collection = self.db["twse_stats"]
18
-
19
15
  self.timezone = pytz.timezone("Asia/Taipei")
16
+ self.tw_company_list = StatsProcessor.load_json("company_list/tw.json")
17
+ db_mapping = {
18
+ "company": "twse_stats",
19
+ "company_us": "us_stats",
20
+ }
21
+
22
+ name_mapping = {"company": "台股", "company_us": "美股"}
23
+
24
+ db_name = "company" if self.ticker in self.tw_company_list else "company_us"
25
+ self.db = db_client[db_name]
26
+ self.collection_name = db_mapping.get(db_name, "unknown")
27
+ assert self.collection_name != "unknown", f"請確認 {ticker} 是否是 {','.join(list(name_mapping.values()))}"
28
+ self.collection = db_client[db_name][self.collection_name]
20
29
 
21
30
  self.target_metric_dict = {
22
31
  'value': ['value'],
@@ -37,40 +46,41 @@ class StatsFetcher:
37
46
  }
38
47
  },
39
48
  ]
49
+
50
+ def query_data(self):
51
+ return NotImplementedError()
40
52
 
41
- def collect_data(self, start_date, end_date):
53
+ def collect_data(self):
42
54
  pipeline = self.prepare_query()
43
-
44
55
  fetched_data = list(self.collection.aggregate(pipeline))
56
+ return fetched_data if fetched_data else None
45
57
 
46
- return fetched_data[0]
47
-
48
- def str_to_datetime(self, date_str):
49
- year, month, day = [int(num) for num in date_str.split("-")]
50
-
51
- date = datetime.strptime(date_str, "%Y-%m-%d")
52
- date = self.timezone.localize(date)
53
-
58
+ def str_to_datetime(self, date_str: str) -> StatsDateTime:
59
+ date = self.timezone.localize(datetime.strptime(date_str, "%Y-%m-%d"))
60
+ year, month, day = date.year, date.month, date.day
54
61
  season = (month - 1) // 3 + 1
55
-
56
62
  return StatsDateTime(date, year, month, day, season)
57
63
 
58
- def has_required_columns(self, df: pd.DataFrame, required_cols=None):
59
- """
60
- Check if the required columns are present in the DataFrame.
61
-
62
- Args:
63
- df (pd.DataFrame): The DataFrame to check.
64
- required_cols (list, optional): List of required column names.
65
- Defaults to ['date', 'open', 'high', 'low', 'close', 'volume'].
66
-
67
- Returns:
68
- bool: True if all required columns are present, False otherwise.
69
- """
64
+ def has_required_columns(
65
+ self, df: pd.DataFrame, required_cols=None
66
+ ) -> bool:
70
67
  if required_cols is None:
71
68
  required_cols = ['date', 'open', 'high', 'low', 'close', 'volume']
72
-
73
69
  return all(col in df.columns for col in required_cols)
70
+
71
+ @staticmethod
72
+ def flatten_dict(value_dict, indexes, target_keys):
73
+ indexes = value_dict.keys()
74
+ new_dict = {}
75
+
76
+ for key in indexes:
77
+ new_dict.update(
78
+ {
79
+ f"{key}_{sub_key}": value_dict[key].get(sub_key, None)
80
+ for sub_key in target_keys
81
+ }
82
+ )
83
+ return new_dict
74
84
 
75
85
 
76
86
  class BaseTEJFetcher(abc.ABC):
@@ -81,21 +91,18 @@ class BaseTEJFetcher(abc.ABC):
81
91
 
82
92
  def get_latest_data_time(self, ticker):
83
93
  latest_data = self.collection.find_one(
84
- {
85
- "ticker": ticker
86
- },
87
- {
94
+ {"ticker": ticker}, {
88
95
  "last_update": 1,
89
96
  "_id": 0
90
97
  }
91
98
  )
92
99
 
93
- try:
94
- latest_date = latest_data['last_update']["latest_data_date"]
95
- except Exception as e:
96
- latest_date = None
97
-
98
- return latest_date
100
+ if (latest_data):
101
+ # return 得到最新日期或None
102
+ return latest_data.get('last_update', {}).get("latest_data_date", None)
103
+
104
+ else:
105
+ return None
99
106
 
100
107
  def process_value(self, value):
101
108
  if isinstance(value, str) and "%" in value:
@@ -107,77 +114,89 @@ class BaseTEJFetcher(abc.ABC):
107
114
 
108
115
  def calculate_growth(self, this_value, last_value, delta):
109
116
  try:
110
- return YoY_Calculator.cal_growth(this_value, last_value, delta) * 100
117
+ return YoY_Calculator.cal_growth(
118
+ this_value, last_value, delta
119
+ ) * 100
111
120
  except Exception:
112
121
  return None
113
122
 
114
- def cal_YoY(self, data_dict: dict, start_year: int, end_year: int, season: int):
123
+ def cal_YoY(
124
+ self, data_dict: dict, start_year: int, end_year: int, season: int
125
+ ):
115
126
  year_shifts = [1, 3, 5, 10]
116
127
  return_dict = {}
117
-
128
+
118
129
  for year in range(start_year, end_year + 1):
119
130
  year_data = data_dict.get(f"{year}Q{season}", {}).copy()
120
131
  if not year_data:
121
132
  continue
122
-
123
- for key in list(year_data.keys()):
133
+
134
+ for key, value in list(year_data.items()):
124
135
  if key == "season":
125
136
  continue
126
-
127
- this_value = self.process_value(year_data[key])
137
+
138
+ this_value = self.process_value(value)
128
139
  if this_value is None:
129
140
  year_data.pop(key)
130
141
  continue
131
-
132
- temp_dict = {"value": year_data[key]}
142
+
143
+ temp_dict = {"value": value}
133
144
  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
145
+ past_value = self.process_value(
146
+ data_dict.get(f"{year - shift}Q{season}", {}).get(key)
147
+ )
148
+ growth = self.calculate_growth(this_value, past_value, shift) if past_value else None
149
+
150
+ temp_dict[
151
+ f"YoY_{shift}"
152
+ ] = f"{growth:.2f}%" if growth else None
138
153
 
139
- temp_dict[f"YoY_{shift}"] = (f"{growth:.2f}%" if growth else None)
140
154
  year_data[key] = temp_dict
141
-
142
155
  return_dict[f"{year}Q{season}"] = year_data
143
-
144
156
  return return_dict
145
157
 
146
158
  def cal_QoQ(self, data_dict):
147
159
  return_dict = {}
148
-
160
+
149
161
  for time_index, this_data in data_dict.items():
150
162
  year, season = map(int, time_index.split("Q"))
151
- last_year, last_season = (year - 1, 4) if season == 1 else (year, season - 1)
152
-
163
+ last_year, last_season = (
164
+ year - 1, 4
165
+ ) if season == 1 else (year, season - 1)
166
+
153
167
  for key in list(this_data.keys()):
154
168
  if key == "season":
155
169
  continue
156
-
170
+
157
171
  this_value = self.process_value(this_data[key])
158
172
  if this_value is None:
159
173
  this_data.pop(key)
160
174
  continue
161
-
175
+
162
176
  temp_dict = {"value": this_data[key]}
163
- last_value = data_dict.get(f"{last_year}Q{last_season}", {}).get(key, {}).get('value')
177
+ last_value = data_dict.get(
178
+ f"{last_year}Q{last_season}",{}
179
+ ).get(key, {}).get('value')
180
+
164
181
  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
182
+ growth = self.calculate_growth(
183
+ this_value, last_value, 1
184
+ ) if last_value is not None else None
166
185
  temp_dict['growth'] = (f"{growth:.2f}%" if growth else None)
167
-
186
+
168
187
  this_data[key] = temp_dict
169
-
188
+
170
189
  return_dict[time_index] = this_data
171
-
190
+
172
191
  return return_dict
173
192
 
174
193
  def get_dict_of_df(self, data_dict):
175
194
  """
176
195
  dict[dict] -> dict[df]
177
196
  """
178
- for key in data_dict.keys():
179
- data_dict[key] = pd.DataFrame.from_dict(data_dict[key])
180
- return data_dict
197
+ return {
198
+ key: pd.DataFrame.from_dict(data) for key, data in data_dict.items()
199
+ }
181
200
 
182
201
  def set_time_shift(self, date: Union[str, datetime], period: str):
183
202
  if isinstance(date, str):
@@ -197,4 +216,4 @@ class BaseTEJFetcher(abc.ABC):
197
216
  if period == "all":
198
217
  return datetime.strptime("1991-01-01", "%Y-%m-%d")
199
218
 
200
- return date - period_mapping.get(period, timedelta(days=0)) # 預設為不變"
219
+ return date - period_mapping.get(period, timedelta(days=0)) # 預設為不變"