neurostats-API 0.0.13__tar.gz → 0.0.15__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/PKG-INFO +66 -2
  2. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/README.md +65 -1
  3. neurostats_API-0.0.15/neurostats_API/__init__.py +13 -0
  4. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/fetchers/__init__.py +2 -0
  5. neurostats_API-0.0.15/neurostats_API/fetchers/base.py +152 -0
  6. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/fetchers/institution.py +19 -13
  7. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/fetchers/profit_lose.py +7 -7
  8. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/fetchers/tech.py +34 -7
  9. neurostats_API-0.0.15/neurostats_API/fetchers/tej_finance_report.py +313 -0
  10. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/tools/balance_sheet.yaml +1 -0
  11. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/tools/profit_lose.yaml +25 -3
  12. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/utils/__init__.py +2 -1
  13. neurostats_API-0.0.15/neurostats_API/utils/calculate_value.py +26 -0
  14. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/utils/data_process.py +90 -8
  15. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API.egg-info/PKG-INFO +66 -2
  16. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API.egg-info/SOURCES.txt +5 -1
  17. neurostats_API-0.0.15/neurostats_API.egg-info/requires.txt +6 -0
  18. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/setup.py +7 -1
  19. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/test/test_fetchers.py +0 -1
  20. neurostats_API-0.0.15/test/test_tej.py +26 -0
  21. neurostats_API-0.0.13/neurostats_API/__init__.py +0 -1
  22. neurostats_API-0.0.13/neurostats_API/fetchers/base.py +0 -54
  23. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/MANIFEST.in +0 -0
  24. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/cli.py +0 -0
  25. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/fetchers/balance_sheet.py +0 -0
  26. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/fetchers/cash_flow.py +0 -0
  27. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/fetchers/finance_overview.py +0 -0
  28. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/fetchers/margin_trading.py +0 -0
  29. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/fetchers/month_revenue.py +0 -0
  30. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/fetchers/value_invest.py +0 -0
  31. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/main.py +0 -0
  32. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/tools/cash_flow_percentage.yaml +0 -0
  33. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/tools/finance_overview_dict.yaml +0 -0
  34. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/tools/seasonal_data_field_dict.txt +0 -0
  35. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/utils/datetime.py +0 -0
  36. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/utils/db_client.py +0 -0
  37. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API/utils/fetcher.py +0 -0
  38. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API.egg-info/dependency_links.txt +0 -0
  39. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/neurostats_API.egg-info/top_level.txt +0 -0
  40. {neurostats_API-0.0.13 → neurostats_API-0.0.15}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: neurostats_API
3
- Version: 0.0.13
3
+ Version: 0.0.15
4
4
  Summary: The service of NeuroStats website
5
5
  Home-page: https://github.com/NeurowattStats/NeuroStats_API.git
6
6
  Author: JasonWang@Neurowatt
@@ -83,7 +83,7 @@ pip install neurostats-API
83
83
  ```Python
84
84
  >>> import neurostats_API
85
85
  >>> print(neurostats_API.__version__)
86
- 0.0.13
86
+ 0.0.15
87
87
  ```
88
88
 
89
89
  ### 得到最新一期的評價資料與歷年評價
@@ -667,7 +667,71 @@ fetcher.query()
667
667
 
668
668
  請注意`range`, `last_range`, `52week_range`這三個項目型態為字串,其餘為float
669
669
 
670
+
671
+ ## TEJ 相關
672
+ ### 會計師簽證財務資料
673
+ ```Python
674
+ from neurostats_API import FinanceReportFetcher
675
+
676
+ mongo_uri = <MongoDB 的 URI>
677
+ db_name = 'company' # 連接的DB名稱
678
+ collection_name = "TWN/AINVFQ1" # 連接的collection對象
679
+
680
+ fetcher = FinanceReportFetcher(
681
+ mongo_uri = mongo_uri,
682
+ db_name = db_name,
683
+ collection_name = collection_name
684
+ )
685
+
686
+ data = fetcher.get(
687
+ ticker = "2330" # 任意的股票代碼
688
+ fetch_mode = fetcher.YOY_NOCAL # 取得模式
689
+ start_date = "2005-01-01",
690
+ end_date = "2024-12-31",
691
+ report_type = "Q",
692
+ indexes = []
693
+ )
694
+ ```
695
+ - `ticker`: 股票代碼
696
+
697
+ - `fetch_mode` : 取得模式,為`fetcher.YOY_NOCAL` 或 `fetcher.QOQ_NOCAL`
698
+ - `YOY_NOCAL`: 以end_date為準,取得與end_date為準同季的歷年資料,時間範圍以start_date為準
699
+ > 例如`start_date = "2020-07-01"`, `end_date = "2024-01-01"`,會回傳2020~2024的第一季資料
700
+
701
+ - `QOQ_NOCAL`: 時間範圍內的每季資料
702
+
703
+ - `start_date`: 開始日期,不設定時預設為`2005-01-01`
704
+
705
+ - `end_date`: 結束日期,不設定時預設為資料庫最新資料的日期
706
+
707
+ - `report_type`: 選擇哪種報告,預設為`Q`
708
+ - `A`: 當年累計
709
+ - `Q`: 當季數值
710
+ - `TTM`: 移動四季 (包括當季在內,往前累計四個季度)
711
+
712
+ - `indexes`: 選擇的column,需要以TEJ提供的欄位名稱為準,不提供時或提供`[]`會回傳全部column
713
+ - 範例輸入: `['bp41', 'bp51']`
714
+
715
+ [TEJ資料集連結](https://tquant.tejwin.com/%E8%B3%87%E6%96%99%E9%9B%86/)
716
+ 請看 `會計師簽證財務資料`
717
+
718
+ #### 回傳資料
719
+ fetch_mode設定為`YOY_NOCAL`與`QOQ_NOCAL`下
720
+ 為回傳pd.DataFrame,column名稱為<年份>Q<季>, row名稱為指定財報項目
721
+
670
722
  ## 版本紀錄
723
+ ## 0.0.15
724
+ - TechFetcher中新增指數條件
725
+
726
+ - 新增tej_fetcher索取TEJ相關的資料
727
+
728
+ - package新增depensnecy,可以安裝需要的相關package
729
+
730
+ ## 0.0.14
731
+ - 修改部分財報資料錯誤的乘以1000的問題
732
+
733
+ - 新增例外處理: 若資料庫對於季資料一部分index缺失的情況下仍會盡可能去將資料蒐集並呈現
734
+
671
735
  ### 0.0.13
672
736
  - value_fetcher 新增獲得一序列評價的功能
673
737
 
@@ -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.13
76
+ 0.0.15
77
77
  ```
78
78
 
79
79
  ### 得到最新一期的評價資料與歷年評價
@@ -657,7 +657,71 @@ fetcher.query()
657
657
 
658
658
  請注意`range`, `last_range`, `52week_range`這三個項目型態為字串,其餘為float
659
659
 
660
+
661
+ ## TEJ 相關
662
+ ### 會計師簽證財務資料
663
+ ```Python
664
+ from neurostats_API import FinanceReportFetcher
665
+
666
+ mongo_uri = <MongoDB 的 URI>
667
+ db_name = 'company' # 連接的DB名稱
668
+ collection_name = "TWN/AINVFQ1" # 連接的collection對象
669
+
670
+ fetcher = FinanceReportFetcher(
671
+ mongo_uri = mongo_uri,
672
+ db_name = db_name,
673
+ collection_name = collection_name
674
+ )
675
+
676
+ data = fetcher.get(
677
+ ticker = "2330" # 任意的股票代碼
678
+ fetch_mode = fetcher.YOY_NOCAL # 取得模式
679
+ start_date = "2005-01-01",
680
+ end_date = "2024-12-31",
681
+ report_type = "Q",
682
+ indexes = []
683
+ )
684
+ ```
685
+ - `ticker`: 股票代碼
686
+
687
+ - `fetch_mode` : 取得模式,為`fetcher.YOY_NOCAL` 或 `fetcher.QOQ_NOCAL`
688
+ - `YOY_NOCAL`: 以end_date為準,取得與end_date為準同季的歷年資料,時間範圍以start_date為準
689
+ > 例如`start_date = "2020-07-01"`, `end_date = "2024-01-01"`,會回傳2020~2024的第一季資料
690
+
691
+ - `QOQ_NOCAL`: 時間範圍內的每季資料
692
+
693
+ - `start_date`: 開始日期,不設定時預設為`2005-01-01`
694
+
695
+ - `end_date`: 結束日期,不設定時預設為資料庫最新資料的日期
696
+
697
+ - `report_type`: 選擇哪種報告,預設為`Q`
698
+ - `A`: 當年累計
699
+ - `Q`: 當季數值
700
+ - `TTM`: 移動四季 (包括當季在內,往前累計四個季度)
701
+
702
+ - `indexes`: 選擇的column,需要以TEJ提供的欄位名稱為準,不提供時或提供`[]`會回傳全部column
703
+ - 範例輸入: `['bp41', 'bp51']`
704
+
705
+ [TEJ資料集連結](https://tquant.tejwin.com/%E8%B3%87%E6%96%99%E9%9B%86/)
706
+ 請看 `會計師簽證財務資料`
707
+
708
+ #### 回傳資料
709
+ fetch_mode設定為`YOY_NOCAL`與`QOQ_NOCAL`下
710
+ 為回傳pd.DataFrame,column名稱為<年份>Q<季>, row名稱為指定財報項目
711
+
660
712
  ## 版本紀錄
713
+ ## 0.0.15
714
+ - TechFetcher中新增指數條件
715
+
716
+ - 新增tej_fetcher索取TEJ相關的資料
717
+
718
+ - package新增depensnecy,可以安裝需要的相關package
719
+
720
+ ## 0.0.14
721
+ - 修改部分財報資料錯誤的乘以1000的問題
722
+
723
+ - 新增例外處理: 若資料庫對於季資料一部分index缺失的情況下仍會盡可能去將資料蒐集並呈現
724
+
661
725
  ### 0.0.13
662
726
  - value_fetcher 新增獲得一序列評價的功能
663
727
 
@@ -0,0 +1,13 @@
1
+ __version__='0.0.15'
2
+
3
+ from .fetchers import (
4
+ BalanceSheetFetcher,
5
+ CashFlowFetcher,
6
+ FinanceOverviewFetcher,
7
+ FinanceReportFetcher,
8
+ InstitutionFetcher,
9
+ MarginTradingFetcher,
10
+ MonthRevenueFetcher,
11
+ TechFetcher,
12
+ ProfitLoseFetcher
13
+ )
@@ -2,6 +2,8 @@ from .base import StatsDateTime, StatsFetcher
2
2
  from .balance_sheet import BalanceSheetFetcher
3
3
  from .cash_flow import CashFlowFetcher
4
4
  from .finance_overview import FinanceOverviewFetcher
5
+ from .tej_finance_report import FinanceReportFetcher
6
+ from .tech import TechFetcher
5
7
  from .institution import InstitutionFetcher
6
8
  from .margin_trading import MarginTradingFetcher
7
9
  from .month_revenue import MonthRevenueFetcher
@@ -0,0 +1,152 @@
1
+ import abc
2
+ from pymongo import MongoClient
3
+ import pandas as pd
4
+ import json
5
+ import pytz
6
+ from datetime import datetime, timedelta, date
7
+ from ..utils import StatsDateTime, StatsProcessor, YoY_Calculator
8
+ import yaml
9
+
10
+ class StatsFetcher:
11
+ def __init__(self, ticker, db_client):
12
+ self.ticker = ticker
13
+ self.db = db_client["company"] # Replace with your database name
14
+ self.collection = self.db["twse_stats"]
15
+
16
+ self.timezone = pytz.timezone("Asia/Taipei")
17
+
18
+ self.target_metric_dict = {
19
+ 'value': ['value'],
20
+ 'value_and_percentage': ['value', 'percentage'],
21
+ 'percentage': ['percentage'],
22
+ 'grand_total': ['grand_total'],
23
+ 'grand_total_values': ['grand_total', 'grand_total_percentage'],
24
+ 'grand_total_percentage': ['grand_total_percentage'],
25
+ 'growth': [f'YoY_{i}' for i in [1, 3, 5, 10]],
26
+ 'grand_total_growth': [f"YoY_{i}" for i in [1, 3, 5, 10]]
27
+ }
28
+
29
+
30
+ def prepare_query(self):
31
+ return [
32
+ {
33
+ "$match": {
34
+ "ticker": self.ticker,
35
+ }
36
+ },
37
+ ]
38
+
39
+ def collect_data(self, start_date, end_date):
40
+ pipeline = self.prepare_query()
41
+
42
+ fetched_data = list(self.collection.aggregate(pipeline))
43
+
44
+ return fetched_data[0]
45
+
46
+ def str_to_datetime(self, date_str):
47
+ year, month, day = [int(num) for num in date_str.split("-")]
48
+
49
+ date = datetime.strptime(date_str, "%Y-%m-%d")
50
+ date = self.timezone.localize(date)
51
+
52
+ season = (month - 1) // 3 + 1
53
+
54
+ return StatsDateTime(date, year, month, day, season)
55
+
56
+ class BaseTEJFetcher(abc.ABC):
57
+ def __init__(self):
58
+ self.client = None
59
+ self.db = None
60
+ self.collection = None
61
+
62
+ @abc.abstractmethod
63
+ def get(self):
64
+ pass
65
+
66
+ def get_latest_data_time(self, ticker):
67
+ latest_data = self.collection.find_one(
68
+ {"ticker": ticker},
69
+ {"last_update": 1, "_id" : 0}
70
+ )
71
+
72
+ try:
73
+ latest_date = latest_data['last_update']["latest_data_date"]
74
+ except Exception as e:
75
+ latest_date = None
76
+
77
+ return latest_date
78
+
79
+ def cal_YoY(self, data_dict: dict, start_year: int, end_year: int):
80
+ year_shifts = [1,3,5,10]
81
+ return_dict = {}
82
+ for year in range(start_year, end_year+1):
83
+ year_data = data_dict[str(year)]
84
+ year_keys = list(year_data.keys())
85
+ for key in year_keys:
86
+ if (key in 'season'):
87
+ continue
88
+
89
+ if (isinstance(year_data[key], (int, float))):
90
+ temp_dict = {"value": year_data[key]}
91
+
92
+ for shift in year_shifts:
93
+ this_value = year_data[key]
94
+ try:
95
+ past_year = str(year - shift)
96
+ last_value = data_dict[past_year][key]['value']
97
+ temp_dict[f"YoY_{shift}"] = YoY_Calculator.cal_growth(
98
+ this_value, last_value, delta = shift
99
+ )
100
+ except Exception as e:
101
+ temp_dict[f"YoY_{shift}"] = None
102
+
103
+ year_data[key] = temp_dict
104
+
105
+ else:
106
+ year_data.pop(key)
107
+
108
+ return_dict[year] = year_data
109
+
110
+
111
+ return return_dict
112
+
113
+ def cal_QoQ(self, data_dict):
114
+ return_dict = {}
115
+ for i, time_index in enumerate(data_dict.keys()):
116
+ year, season = time_index.split("Q")
117
+ year = int(year)
118
+ season = int(season)
119
+ if (season == 1):
120
+ last_year = year - 1
121
+ last_season = 4
122
+ else:
123
+ last_year = year
124
+ last_season = season - 1
125
+
126
+ this_data = data_dict[time_index]
127
+ this_keys = list(this_data.keys())
128
+ for key in this_keys:
129
+ if (key in 'season'):
130
+ continue
131
+
132
+ this_value = this_data[key]
133
+
134
+ if (isinstance(this_value, (int, float))):
135
+ temp_dict = {"value": this_value}
136
+
137
+ try:
138
+ last_value = data_dict[f"{last_year}Q{last_season}"][key]['value']
139
+
140
+ temp_dict['growth'] = YoY_Calculator.cal_growth(
141
+ this_value, last_value, delta=1
142
+ )
143
+ except Exception as e:
144
+ temp_dict['growth'] = None
145
+
146
+ this_data[key] = temp_dict
147
+
148
+ else:
149
+ this_data.pop(key)
150
+ return_dict[time_index] = this_data
151
+ return return_dict
152
+
@@ -164,25 +164,26 @@ class InstitutionFetcher(StatsFetcher):
164
164
  latest_daily_data['volume'])
165
165
  }
166
166
  # 一年內法人
167
- annual_dates = [data['date'].strftime("%Y-%m-%d") for data in daily_datas]
167
+ annual_dates = [
168
+ data['date'].strftime("%Y-%m-%d") for data in daily_datas
169
+ ]
168
170
  annual_closes = {
169
- data['date'].strftime("%Y-%m-%d") : data['close']
171
+ data['date'].strftime("%Y-%m-%d"): data['close']
170
172
  for data in daily_datas
171
173
  if (data['date'].strftime("%Y-%m-%d") in annual_dates)
172
174
  }
173
175
  annual_volumes = {
174
- data['date'].strftime("%Y-%m-%d") : data['volume']
176
+ data['date'].strftime("%Y-%m-%d"): data['volume']
175
177
  for data in daily_datas
176
178
  if (data['date'].strftime("%Y-%m-%d") in annual_dates)
177
179
  }
178
180
  annual_trading = {
179
- data['date'].strftime("%Y-%m-%d") : data
181
+ data['date'].strftime("%Y-%m-%d"): data
180
182
  for data in institution_tradings
181
- }
183
+ }
182
184
 
183
185
  annual_trading = {
184
186
  date: {
185
-
186
187
  "close": annual_closes[date],
187
188
  "volume": annual_volumes[date],
188
189
  **annual_trading[date]
@@ -217,13 +218,18 @@ class InstitutionFetcher(StatsFetcher):
217
218
  self.target_institution(latest_trading,
218
219
  latest_table['institutional_investor'],
219
220
  key, volume)
220
-
221
- for trade_type in ['buy', 'sell']:
222
- for unit in ['stock', 'percentage']:
223
- latest_table['institutional_investor'][trade_type][
224
- unit] = (latest_table['foreign'][trade_type][unit] +
225
- latest_table['prop'][trade_type][unit] +
226
- latest_table['mutual'][trade_type][unit])
221
+ # 計算合計
222
+ for unit in ['stock', 'percentage']:
223
+ # 買進總和
224
+ latest_table['institutional_investor']['buy'][unit] = (
225
+ latest_table['foreign']['buy'][unit] +
226
+ latest_table['prop']['buy'][unit] +
227
+ latest_table['mutual']['buy'][unit])
228
+ # 賣出總和
229
+ latest_table['institutional_investor']['sell'][unit] = (
230
+ latest_table['foreign']['sell'][unit] +
231
+ latest_table['prop']['sell'][unit] +
232
+ latest_table['mutual']['sell'][unit])
227
233
 
228
234
  frames = []
229
235
  for category, trades in latest_table.items():
@@ -21,12 +21,6 @@ class ProfitLoseFetcher(StatsFetcher):
21
21
  def prepare_query(self, target_season):
22
22
  pipeline = super().prepare_query()
23
23
 
24
- target_query = {
25
- "year": "$$target_season_data.year",
26
- "season": "$$target_season_data.season",
27
- "balance_sheet": "$$$$target_season_data.balance_sheet"
28
- }
29
-
30
24
  pipeline.append({
31
25
  "$project": {
32
26
  "_id": 0,
@@ -121,6 +115,9 @@ class ProfitLoseFetcher(StatsFetcher):
121
115
  elif ('YoY' in item_name):
122
116
  if (isinstance(item, (float, int))):
123
117
  item = StatsProcessor.cal_percentage(item)
118
+ elif ('每股盈餘' in index_name):
119
+ if (isinstance(item, (float, int))):
120
+ item = StatsProcessor.cal_non_percentage(item, postfix="元")
124
121
  else:
125
122
  if (isinstance(item, (float, int))):
126
123
  item = StatsProcessor.cal_non_percentage(item, postfix="千元")
@@ -153,6 +150,9 @@ class ProfitLoseFetcher(StatsFetcher):
153
150
  target_index=target_index)
154
151
  break
155
152
  except Exception as e:
156
- continue
153
+ return_dict[name] = StatsProcessor.slice_multi_col_table(
154
+ total_table=total_table,
155
+ mode=setting['mode'],
156
+ target_index=target_index)
157
157
 
158
158
  return return_dict
@@ -1,9 +1,16 @@
1
1
  from .base import StatsFetcher
2
2
  import pandas as pd
3
+ import yfinance as yf
3
4
 
4
5
  class TechFetcher(StatsFetcher):
5
6
 
6
7
  def __init__(self, ticker:str, db_client):
8
+
9
+ """
10
+ The Capitalization-Weighted Index includes the following tickers:
11
+ ['GSPC', 'IXIC', 'DJI', 'TWII']
12
+ """
13
+
7
14
  super().__init__(ticker, db_client)
8
15
  self.full_ohlcv = self._get_ohlcv()
9
16
  self.basic_indexes = ['SMA5', 'SMA20', 'SMA60', 'EMA5', 'EMA20',
@@ -40,16 +47,36 @@ class TechFetcher(StatsFetcher):
40
47
  )
41
48
 
42
49
  def _get_ohlcv(self):
43
- query = {'ticker': self.ticker}
44
- ticker_full = list(self.collection.find(query))
50
+
51
+ if self.ticker in ['GSPC', 'IXIC', 'DJI', 'TWII']:
52
+
53
+ full_tick = f'^{self.ticker}'
54
+ yf_ticker = yf.Ticker(full_tick)
55
+ origin_df = yf_ticker.history(period="10y")
56
+ origin_df = origin_df.reset_index()
57
+ origin_df["Date"] = pd.to_datetime(origin_df["Date"]).dt.date
58
+ df = origin_df.rename(
59
+ columns={
60
+ "Date": "date",
61
+ "Open": "open",
62
+ "High": "high",
63
+ "Low": "low",
64
+ "Close": "close",
65
+ "Volume": "volume"
66
+ }
67
+ )
68
+ else:
69
+
70
+ query = {'ticker': self.ticker}
71
+ ticker_full = list(self.collection.find(query))
45
72
 
46
- if not ticker_full:
47
- raise ValueError(f"No data found for ticker: {self.ticker}")
73
+ if not ticker_full:
74
+ raise ValueError(f"No data found for ticker: {self.ticker}")
48
75
 
49
- if 'daily_data' not in ticker_full[0] or ticker_full[0]['daily_data'] is None:
50
- raise KeyError("Missing 'daily_data' in the retrieved data")
76
+ if 'daily_data' not in ticker_full[0] or ticker_full[0]['daily_data'] is None:
77
+ raise KeyError("Missing 'daily_data' in the retrieved data")
51
78
 
52
- df = pd.DataFrame(ticker_full[0]['daily_data'])
79
+ df = pd.DataFrame(ticker_full[0]['daily_data'])
53
80
 
54
81
  selected_cols = ['date','open','high','low','close','volume']
55
82