neurostats-API 0.0.25rc1__py3-none-any.whl → 1.0.0rc2__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 (105) hide show
  1. neurostats_API/__init__.py +1 -1
  2. neurostats_API/async_mode/__init__.py +13 -0
  3. neurostats_API/async_mode/db/__init__.py +3 -0
  4. neurostats_API/async_mode/db/base.py +24 -0
  5. neurostats_API/async_mode/db/tej.py +10 -0
  6. neurostats_API/async_mode/db/twse.py +8 -0
  7. neurostats_API/async_mode/db/us.py +9 -0
  8. neurostats_API/async_mode/db_extractors/__init__.py +20 -0
  9. neurostats_API/async_mode/db_extractors/base.py +66 -0
  10. neurostats_API/async_mode/db_extractors/daily/__init__.py +7 -0
  11. neurostats_API/async_mode/db_extractors/daily/base.py +89 -0
  12. neurostats_API/async_mode/db_extractors/daily/tej_chip.py +14 -0
  13. neurostats_API/async_mode/db_extractors/daily/tej_tech.py +12 -0
  14. neurostats_API/async_mode/db_extractors/daily/twse_chip.py +49 -0
  15. neurostats_API/async_mode/db_extractors/daily/value.py +93 -0
  16. neurostats_API/async_mode/db_extractors/daily/yf.py +12 -0
  17. neurostats_API/async_mode/db_extractors/month_revenue/__init__.py +1 -0
  18. neurostats_API/async_mode/db_extractors/month_revenue/base.py +140 -0
  19. neurostats_API/async_mode/db_extractors/month_revenue/twse.py +5 -0
  20. neurostats_API/async_mode/db_extractors/seasonal/__init__.py +4 -0
  21. neurostats_API/async_mode/db_extractors/seasonal/balance_sheet.py +19 -0
  22. neurostats_API/async_mode/db_extractors/seasonal/base.py +152 -0
  23. neurostats_API/async_mode/db_extractors/seasonal/cashflow.py +10 -0
  24. neurostats_API/async_mode/db_extractors/seasonal/profit_lose.py +17 -0
  25. neurostats_API/async_mode/db_extractors/seasonal/tej.py +87 -0
  26. neurostats_API/async_mode/factory/__init__.py +1 -0
  27. neurostats_API/async_mode/factory/extractor_factory.py +168 -0
  28. neurostats_API/async_mode/factory/transformer_factory.py +164 -0
  29. neurostats_API/async_mode/fetchers/__init__.py +10 -0
  30. neurostats_API/async_mode/fetchers/balance_sheet.py +31 -0
  31. neurostats_API/async_mode/fetchers/base.py +48 -0
  32. neurostats_API/async_mode/fetchers/cash_flow.py +56 -0
  33. neurostats_API/async_mode/fetchers/finance_overview.py +134 -0
  34. neurostats_API/async_mode/fetchers/month_revenue.py +35 -0
  35. neurostats_API/async_mode/fetchers/profit_lose.py +46 -0
  36. neurostats_API/async_mode/fetchers/tech.py +205 -0
  37. neurostats_API/async_mode/fetchers/tej.py +88 -0
  38. neurostats_API/async_mode/fetchers/twse_institution.py +62 -0
  39. neurostats_API/async_mode/fetchers/twse_margin.py +100 -0
  40. neurostats_API/async_mode/fetchers/value.py +76 -0
  41. neurostats_API/config/company_list/ticker_index_industry_map.json +7946 -0
  42. neurostats_API/config/company_list/us.json +9986 -0
  43. neurostats_API/{tools → config}/tej_db/tej_db_skip_index.yaml +0 -2
  44. neurostats_API/{tools → config}/twse/profit_lose.yaml +0 -6
  45. neurostats_API/fetchers/finance_overview.py +27 -5
  46. neurostats_API/transformers/__init__.py +40 -0
  47. neurostats_API/transformers/balance_sheet/__init__.py +2 -0
  48. neurostats_API/transformers/balance_sheet/base.py +51 -0
  49. neurostats_API/transformers/balance_sheet/twse.py +76 -0
  50. neurostats_API/transformers/balance_sheet/us.py +30 -0
  51. neurostats_API/transformers/base.py +110 -0
  52. neurostats_API/transformers/cash_flow/__init__.py +2 -0
  53. neurostats_API/transformers/cash_flow/base.py +114 -0
  54. neurostats_API/transformers/cash_flow/twse.py +68 -0
  55. neurostats_API/transformers/cash_flow/us.py +38 -0
  56. neurostats_API/transformers/daily_chip/__init__.py +1 -0
  57. neurostats_API/transformers/daily_chip/base.py +5 -0
  58. neurostats_API/transformers/daily_chip/tej.py +0 -0
  59. neurostats_API/transformers/daily_chip/twse_chip.py +415 -0
  60. neurostats_API/transformers/daily_chip/utils/__init__.py +0 -0
  61. neurostats_API/transformers/daily_chip/utils/institution.py +90 -0
  62. neurostats_API/transformers/daily_chip/utils/margin_trading.py +2 -0
  63. neurostats_API/transformers/daily_chip/utils/security_lending.py +0 -0
  64. neurostats_API/transformers/daily_tech/__init__.py +1 -0
  65. neurostats_API/transformers/daily_tech/base.py +5 -0
  66. neurostats_API/transformers/daily_tech/tech.py +84 -0
  67. neurostats_API/transformers/daily_tech/utils/__init__.py +1 -0
  68. neurostats_API/transformers/daily_tech/utils/processor.py +251 -0
  69. neurostats_API/transformers/finance_overview/__init__.py +2 -0
  70. neurostats_API/transformers/finance_overview/agent_overview.py +55 -0
  71. neurostats_API/transformers/finance_overview/base.py +824 -0
  72. neurostats_API/transformers/finance_overview/stats_overview.py +64 -0
  73. neurostats_API/transformers/month_revenue/__init__.py +1 -0
  74. neurostats_API/transformers/month_revenue/base.py +60 -0
  75. neurostats_API/transformers/month_revenue/twse.py +129 -0
  76. neurostats_API/transformers/profit_lose/__init__.py +2 -0
  77. neurostats_API/transformers/profit_lose/base.py +82 -0
  78. neurostats_API/transformers/profit_lose/twse.py +133 -0
  79. neurostats_API/transformers/profit_lose/us.py +25 -0
  80. neurostats_API/transformers/tej/__init__.py +1 -0
  81. neurostats_API/transformers/tej/base.py +149 -0
  82. neurostats_API/transformers/tej/finance_statement.py +80 -0
  83. neurostats_API/transformers/value/__init__.py +1 -0
  84. neurostats_API/transformers/value/base.py +5 -0
  85. neurostats_API/transformers/value/tej.py +8 -0
  86. neurostats_API/transformers/value/twse.py +48 -0
  87. neurostats_API/utils/__init__.py +1 -1
  88. neurostats_API/utils/data_process.py +10 -6
  89. neurostats_API/utils/exception.py +8 -0
  90. neurostats_API/utils/logger.py +21 -0
  91. neurostats_API-1.0.0rc2.dist-info/METADATA +102 -0
  92. neurostats_API-1.0.0rc2.dist-info/RECORD +119 -0
  93. neurostats_API-0.0.25rc1.dist-info/METADATA +0 -858
  94. neurostats_API-0.0.25rc1.dist-info/RECORD +0 -36
  95. /neurostats_API/{tools → config}/company_list/tw.json +0 -0
  96. /neurostats_API/{tools → config}/company_list/us_TradingView_list.json +0 -0
  97. /neurostats_API/{tools → config}/tej_db/tej_db_index.yaml +0 -0
  98. /neurostats_API/{tools → config}/tej_db/tej_db_percent_index.yaml +0 -0
  99. /neurostats_API/{tools → config}/tej_db/tej_db_thousand_index.yaml +0 -0
  100. /neurostats_API/{tools → config}/twse/balance_sheet.yaml +0 -0
  101. /neurostats_API/{tools → config}/twse/cash_flow_percentage.yaml +0 -0
  102. /neurostats_API/{tools → config}/twse/finance_overview_dict.yaml +0 -0
  103. /neurostats_API/{tools → config}/twse/seasonal_data_field_dict.txt +0 -0
  104. {neurostats_API-0.0.25rc1.dist-info → neurostats_API-1.0.0rc2.dist-info}/WHEEL +0 -0
  105. {neurostats_API-0.0.25rc1.dist-info → neurostats_API-1.0.0rc2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,56 @@
1
+ from .base import AsyncBaseFetcher
2
+ from ..db_extractors import AsyncCashFlowExtractor
3
+ from neurostats_API.async_mode.factory import get_extractor
4
+ from neurostats_API.transformers import (
5
+ TWSECashFlowTransformer, USCashFlowTransformer
6
+ )
7
+ from neurostats_API.utils import NoCompanyError, NotSupportedError
8
+
9
+
10
+ class AsyncCashFlowFetcher(AsyncBaseFetcher):
11
+
12
+ def __init__(self, ticker, client):
13
+
14
+ super().__init__()
15
+ self.transformer_map = {
16
+ "tw": TWSECashFlowTransformer,
17
+ "us": USCashFlowTransformer
18
+ }
19
+ self.ticker = ticker
20
+ try:
21
+ self.extractor = get_extractor("DB_cash_flow", self.ticker, client)
22
+ self.company_name = self.extractor.get_company_name()
23
+ self.zone = self.extractor.get_zone()
24
+
25
+ transformer = self.get_transformer(self.zone)
26
+ self.transformer = transformer(ticker, self.company_name, self.zone)
27
+
28
+ except NotSupportedError as e:
29
+ raise NotSupportedError(
30
+ f"{self.__class__.__name__} only support {list(self.transformer_map.keys())} companies now, {ticker} is not available"
31
+ ) from e
32
+ except NoCompanyError:
33
+ raise
34
+
35
+ async def query_data(self, start_date=None, end_date=None):
36
+ fetched_data = await self.extractor.query_data(start_date, end_date)
37
+
38
+ transformed_data = self.transformer.process_transform(fetched_data)
39
+
40
+ return transformed_data
41
+
42
+ async def query_data_stats_only(self, start_date=None, end_date=None):
43
+ fetched_data = await self.extractor.query_data(start_date, end_date)
44
+
45
+ transformed_data = self.transformer.process_stats_page(fetched_data)
46
+
47
+ return transformed_data
48
+
49
+ async def query_data_QoQ_and_YoY_only(self, start_date=None, end_date=None):
50
+ if (self.zone != 'tw'):
51
+ raise NotSupportedError("query_data_QoQ_and_YoY_only() only supports for TW companies")
52
+ fetched_data = await self.extractor.query_data(start_date, end_date)
53
+
54
+ transformed_data = self.transformer.process_QoQ(fetched_data)
55
+
56
+ return transformed_data
@@ -0,0 +1,134 @@
1
+ from .base import AsyncBaseFetcher
2
+ from datetime import datetime
3
+ import importlib.resources as pkg_resources
4
+
5
+ from neurostats_API.async_mode.db_extractors import (
6
+ AsyncBalanceSheetExtractor, AsyncCashFlowExtractor, AsyncProfitLoseExtractor
7
+ )
8
+ from neurostats_API.async_mode.factory import get_extractor
9
+ from neurostats_API.transformers import AgentOverviewTransformer, FinanceOverviewTransformer
10
+ from neurostats_API.utils import StatsDateTime, StatsProcessor, NoCompanyError, NotSupportedError
11
+ import numpy as np
12
+ import pandas as pd
13
+ import pytz
14
+ import holidays
15
+ import warnings
16
+
17
+ warnings.filterwarnings(
18
+ "ignore",
19
+ category=holidays.deprecations.v1_incompatibility.
20
+ FutureIncompatibilityWarning
21
+ )
22
+ import yaml
23
+
24
+
25
+ class AsyncFinanceOverviewFetcher(AsyncBaseFetcher):
26
+ """
27
+ 對應iFa.ai -> 財務分析 -> 重要指標(finance_overview)
28
+ """
29
+
30
+ def __init__(self, ticker, db_client):
31
+ super().__init__()
32
+
33
+ self.target_fields = StatsProcessor.load_yaml(
34
+ "twse/finance_overview_dict.yaml"
35
+ )
36
+ self.inverse_dict = StatsProcessor.load_txt(
37
+ "twse/seasonal_data_field_dict.txt", json_load=True
38
+ )
39
+ try:
40
+ self.balance_sheet_extractor = get_extractor(
41
+ "DB_balance_sheet", ticker, db_client
42
+ )
43
+ self.profit_lose_extractor = get_extractor(
44
+ "DB_profit_lose", ticker, db_client
45
+ )
46
+ self.cashflow_extractor = get_extractor(
47
+ "DB_cash_flow", ticker, db_client
48
+ )
49
+
50
+ company_name = self.balance_sheet_extractor.get_company_name()
51
+ zone = self.balance_sheet_extractor.get_zone()
52
+
53
+ if (zone != 'tw'):
54
+ raise NotSupportedError(None)
55
+
56
+ self.transformer = FinanceOverviewTransformer(
57
+ ticker, company_name, zone
58
+ )
59
+ except NotSupportedError as e:
60
+ raise NotSupportedError("FinanceOverviewFetcher only supports TW corporation now") from e
61
+
62
+ async def query_data(self, date=None):
63
+
64
+ balance_sheet = await self.balance_sheet_extractor.query_data(
65
+ end_date=date, get_latest=True
66
+ )
67
+ profit_lose = await self.profit_lose_extractor.query_data(
68
+ end_date=date, get_latest=True
69
+ )
70
+ cash_flow = await self.cashflow_extractor.query_data(
71
+ end_date=date, get_latest=True
72
+ )
73
+
74
+ transformed_data = self.transformer.process_transform(
75
+ balance_sheet, profit_lose, cash_flow
76
+ )
77
+
78
+ return transformed_data
79
+
80
+
81
+ class AsyncAgentOverviewFetcher(AsyncBaseFetcher):
82
+ """
83
+ 用於P1-Agent 的 公司股市經濟概況頁面
84
+ """
85
+
86
+ def __init__(self, ticker, db_client):
87
+ from neurostats_API.async_mode.fetchers import AsyncTechFetcher
88
+ self.ticker = ticker
89
+ self.tech_fetcher = AsyncTechFetcher(
90
+ ticker=self.ticker, client=db_client
91
+ )
92
+ try:
93
+ self.balance_sheet_extractor = AsyncBalanceSheetExtractor(
94
+ ticker=self.ticker, client=db_client
95
+ )
96
+ self.profit_lose_extractor = AsyncProfitLoseExtractor(
97
+ ticker=self.ticker, client=db_client
98
+ )
99
+ self.cash_flow_extractor = AsyncCashFlowExtractor(
100
+ ticker=self.ticker, client=db_client
101
+ )
102
+
103
+ company_name = self.balance_sheet_extractor.get_company_name()
104
+ zone = self.balance_sheet_extractor.get_zone()
105
+
106
+ self.transformer_map = {'us': AgentOverviewTransformer}
107
+
108
+ transformer = self.get_transformer(zone)
109
+ self.transformer = transformer(ticker, company_name, zone)
110
+
111
+ except NotSupportedError as e:
112
+ raise NotSupportedError(
113
+ f'Agent Overview only supports US corporation now, Got zone={zone}, ticker={ticker}'
114
+ ) from e
115
+
116
+ async def query_data(self, date=None):
117
+
118
+ tech_data = await self.tech_fetcher.get_daily(
119
+ start_date=None, end_date=date
120
+ )
121
+ balance_sheet = await self.balance_sheet_extractor.query_data(
122
+ end_date=date
123
+ )
124
+ profit_lose = await self.profit_lose_extractor.query_data(end_date=date)
125
+ cash_flow = await self.cash_flow_extractor.query_data(end_date=date)
126
+
127
+ return_data = self.transformer.process_transform(
128
+ tech_data=tech_data,
129
+ balance_sheet_list=balance_sheet,
130
+ profit_lose_list=profit_lose,
131
+ cash_flow_list=cash_flow
132
+ )
133
+
134
+ return return_data
@@ -0,0 +1,35 @@
1
+ from .base import AsyncBaseFetcher
2
+ from ..db_extractors import AsyncTWSEMonthlyRevenueExtractor
3
+ from neurostats_API.async_mode.factory import get_extractor
4
+ from neurostats_API.transformers import TWSEMonthlyRevenueTransformer
5
+ from neurostats_API.utils import NoCompanyError, NotSupportedError
6
+
7
+
8
+ class AsyncMonthlyRevenueFetcher(AsyncBaseFetcher):
9
+
10
+ def __init__(self, ticker, client):
11
+ self.ticker = ticker
12
+ self.transformer_map = {
13
+ "tw": TWSEMonthlyRevenueTransformer,
14
+ }
15
+
16
+ try:
17
+ self.extractor = get_extractor("TWSE_month_revenue", ticker, client)
18
+ company_name = self.extractor.get_company_name()
19
+ zone = self.extractor.get_zone()
20
+
21
+ transformer = self.get_transformer(zone)
22
+
23
+ self.transformer = transformer(ticker, company_name, zone)
24
+ except NotSupportedError as e:
25
+ raise NotSupportedError(
26
+ "AsyncMonthRevenueFetcher only supports tw company now"
27
+ ) from e
28
+
29
+
30
+ async def query_data(self, start_date=None, end_date=None):
31
+ fetched_data = await self.extractor.query_data(start_date, end_date)
32
+
33
+ transformed_data = self.transformer.process_transform(fetched_data)
34
+
35
+ return transformed_data
@@ -0,0 +1,46 @@
1
+ from neurostats_API.async_mode.db_extractors import AsyncProfitLoseExtractor
2
+ from neurostats_API.async_mode.factory import get_extractor
3
+ from neurostats_API.transformers import (
4
+ TWSEProfitLoseTransformer,
5
+ USProfitLoseTransformer
6
+ )
7
+ from neurostats_API.utils import (
8
+ NoCompanyError,
9
+ NotSupportedError
10
+ )
11
+
12
+ from .base import AsyncBaseFetcher
13
+
14
+ class AsyncProfitLoseFetcher(AsyncBaseFetcher):
15
+ def __init__(
16
+ self,
17
+ ticker,
18
+ client
19
+ ):
20
+ self.ticker = ticker
21
+
22
+ self.transformer_map = {
23
+ "tw": TWSEProfitLoseTransformer,
24
+ "us": USProfitLoseTransformer
25
+ }
26
+ try:
27
+ self.extractor = get_extractor("DB_profit_lose", ticker, client)
28
+ company_name = self.extractor.get_company_name()
29
+ zone = self.extractor.get_zone()
30
+
31
+ transformer = self.get_transformer(zone)
32
+ self.transformer = transformer(ticker, company_name, zone)
33
+
34
+ except NotSupportedError as e:
35
+ raise NotSupportedError(
36
+ f"{self.__class__.__name__} only support {list(self.transformer_map.keys())} companies now, {ticker} is not available"
37
+ ) from e
38
+
39
+ async def query_data(self, start_date = None, end_date = None):
40
+ fetched_data = await self.extractor.query_data(start_date, end_date)
41
+
42
+ transformed_data = self.transformer.process_transform(
43
+ fetched_data
44
+ )
45
+
46
+ return transformed_data
@@ -0,0 +1,205 @@
1
+ from .base import AsyncBaseFetcher
2
+ from datetime import datetime
3
+ from ..db_extractors import (
4
+ AsyncYFDailyTechDBExtractor, AsyncTEJDailyTechDBExtractor
5
+ )
6
+ from neurostats_API.async_mode.factory import get_extractor
7
+ from neurostats_API.transformers import DailyTechTransformer
8
+ from neurostats_API.utils import NotSupportedError
9
+ import pandas as pd
10
+ import yfinance as yf
11
+
12
+
13
+ class AsyncTechFetcher(AsyncBaseFetcher):
14
+
15
+ def __init__(self, ticker, client):
16
+ self.ticker = ticker
17
+ self.transformer_map = {
18
+ "tw": DailyTechTransformer,
19
+ "us": DailyTechTransformer
20
+ }
21
+ try:
22
+ self.yf_db_extractor = get_extractor("YF_tech", ticker, client)
23
+
24
+ self.tej_db_extractor = None
25
+ if (self.yf_db_extractor.get_zone() == 'tw'):
26
+ self.tej_db_extractor = get_extractor("TEJ_tech", ticker, client)
27
+
28
+ self.company_name = self.yf_db_extractor.get_company_name()
29
+ self.zone = self.yf_db_extractor.get_zone()
30
+
31
+ self.required_cols = [
32
+ 'date', 'open', 'high', 'low', 'close', 'volume'
33
+ ]
34
+
35
+ transformer = self.get_transformer(self.zone)
36
+ self.transformer = transformer(ticker, self.company_name, self.zone)
37
+
38
+ except NotSupportedError as e:
39
+ raise NotSupportedError(
40
+ f"{self.__class__.__name__} only supports {list(self.transformer_map.keys())}, got {self.zone} with ticker = \"{self.ticker}\""
41
+ ) from e
42
+
43
+ async def query_data(self, start_date=None, end_date=None):
44
+ if (start_date is None):
45
+ start_date = datetime.strptime("1991-01-01", "%Y-%m-%d")
46
+ if (end_date is None):
47
+ end_date = datetime.today()
48
+
49
+ fetched_data = await self._fetch_data(start_date, end_date)
50
+
51
+ transformed_data = self.transformer.process_transform(fetched_data)
52
+
53
+ return transformed_data
54
+
55
+ async def get_daily(self, start_date=None, end_date=None):
56
+ await self.query_data(start_date, end_date)
57
+
58
+ return self.transformer.get_daily()
59
+
60
+ async def get_weekly(self, start_date=None, end_date=None):
61
+ await self.query_data(start_date, end_date)
62
+
63
+ return self.transformer.get_weekly()
64
+
65
+ async def get_monthly(self, start_date=None, end_date=None):
66
+ await self.query_data(start_date, end_date)
67
+
68
+ return self.transformer.get_monthly()
69
+
70
+ async def get_quarterly(self, start_date=None, end_date=None):
71
+ await self.query_data(start_date, end_date)
72
+
73
+ return self.transformer.get_quarterly()
74
+
75
+ async def get_yearly(self, start_date=None, end_date=None):
76
+ await self.query_data(start_date, end_date)
77
+
78
+ return self.transformer.get_yearly()
79
+
80
+ async def _fetch_data(self, start_date, end_date):
81
+
82
+ if (self.ticker in ['GSPC', 'IXIC', 'DJI', 'TWII']):
83
+ full_tick = f'^{self.ticker}'
84
+ df = self._conduct_yf_search(full_tick, start_date, end_date)
85
+
86
+ return df[self.required_cols]
87
+
88
+ else:
89
+ search_fn_map = {
90
+ 'tw': self._conduct_tw_db_search,
91
+ 'us': self._conduct_us_db_search
92
+ }
93
+ search_fn = search_fn_map.get(self.zone)
94
+ df = await search_fn(start_date, end_date)
95
+
96
+ return df
97
+
98
+ def _conduct_yf_search(self, ticker, start_date, end_date):
99
+ yf_ticker = yf.Ticker(ticker)
100
+ origin_df = yf_ticker.history(period="10y")
101
+
102
+ if origin_df.empty:
103
+ return origin_df
104
+
105
+ origin_df = origin_df.reset_index()
106
+ origin_df["Date"] = pd.to_datetime(origin_df["Date"])
107
+ df = origin_df.rename(
108
+ columns={
109
+ "Date": "date",
110
+ "Open": "open",
111
+ "High": "high",
112
+ "Low": "low",
113
+ "Close": "close",
114
+ "Volume": "volume"
115
+ }
116
+ )
117
+
118
+ df = df.loc[(df['date'] >= start_date) & (df['date'] <= end_date)]
119
+ return df
120
+
121
+ async def _conduct_tw_db_search(self, start_date, end_date):
122
+ search_fns = [
123
+ self._conduct_tw_db_search_yf,
124
+ self._conduct_tw_db_search_tej,
125
+ ]
126
+
127
+ sync_search_fns = [
128
+ lambda s_date, e_date: self.
129
+ _conduct_yf_search(f'{self.ticker}.tw', s_date, e_date),
130
+ lambda s_date, e_date: self.
131
+ _conduct_yf_search(f'{self.ticker}.two', s_date, e_date),
132
+ ]
133
+
134
+ for search_method in search_fns:
135
+ try:
136
+ fetched_data = await search_method(start_date, end_date)
137
+ if not fetched_data.empty:
138
+ break
139
+ except (KeyError, ValueError, TypeError) as e:
140
+ print(e)
141
+ continue
142
+ else: # 找不到資料
143
+ for search_method in sync_search_fns:
144
+ fetched_data = search_method(start_date, end_date)
145
+ if not fetched_data.empty:
146
+ break
147
+ else:
148
+ return pd.DataFrame(self.required_cols)
149
+
150
+ return fetched_data[self.required_cols]
151
+
152
+ async def _conduct_tw_db_search_yf(self, start_date, end_date):
153
+ """
154
+ 尋找從yf與twse爬下來的台股資料
155
+ """
156
+ fetched_data = await self.yf_db_extractor.query_data(
157
+ start_date, end_date
158
+ )
159
+
160
+ if (len(fetched_data) > 0):
161
+ df = pd.DataFrame(fetched_data)
162
+ return df
163
+ else:
164
+ return None
165
+
166
+ async def _conduct_tw_db_search_tej(self, start_date, end_date):
167
+ """
168
+ 尋找從TEJ爬下來的台股資料
169
+ """
170
+ fetched_data = await self.tej_db_extractor.query_data(
171
+ start_date, end_date
172
+ )
173
+
174
+ if (len(fetched_data) > 0):
175
+ df = pd.DataFrame(fetched_data)
176
+ df = df.rename(
177
+ columns={
178
+ "open_d": "open",
179
+ "high_d": "high",
180
+ "low_d": "low",
181
+ "close_d": "close",
182
+ "vol": "volume"
183
+ }
184
+ )
185
+
186
+ return df
187
+ else:
188
+ return None
189
+
190
+ def _conduct_us_db_search(self, start_date, end_date):
191
+ search_fns = [
192
+ self.yf_db_extractor.query_data, lambda s_date, e_date: self.
193
+ _conduct_yf_search(f"{self.ticker}", s_date, e_date)
194
+ ]
195
+
196
+ for search_method in search_fns:
197
+ try:
198
+ df = search_method(start_date, end_date)
199
+ break
200
+ except (KeyError, ValueError, TypeError):
201
+ continue
202
+ else: # 回傳空df
203
+ df = pd.DataFrame(columns=self.required_cols)
204
+
205
+ return df
@@ -0,0 +1,88 @@
1
+ from .base import AsyncBaseFetcher
2
+ from datetime import datetime
3
+ from neurostats_API.async_mode.db_extractors import (
4
+ AsyncTEJFinanceStatementDBExtractor, AsyncTEJSelfSettlementDBExtractor
5
+ )
6
+ from neurostats_API.async_mode.factory import get_extractor
7
+ from neurostats_API.transformers import TEJFinanceStatementTransformer
8
+ from neurostats_API.utils import NotSupportedError
9
+
10
+
11
+ class AsyncTEJSeasonalFetcher(AsyncBaseFetcher):
12
+
13
+ def __init__(
14
+ self,
15
+ ticker,
16
+ client,
17
+ collection='TEJ_finance_statement',
18
+ fetch_type='Q'
19
+ ):
20
+ self.ticker = ticker
21
+ self.fetch_type = fetch_type
22
+ self.transformer_map = {"tw": TEJFinanceStatementTransformer}
23
+ try:
24
+ self.db_extractor = get_extractor(
25
+ collection=collection,
26
+ ticker=ticker,
27
+ client=client,
28
+ fetch_type=fetch_type
29
+ )
30
+
31
+ self.company_name = self.db_extractor.get_company_name()
32
+ self.zone = self.db_extractor.get_zone()
33
+
34
+
35
+
36
+ transformer = self.get_transformer(self.zone)
37
+
38
+ self.transformer = transformer(
39
+ ticker=ticker,
40
+ company_name=self.company_name,
41
+ zone=self.zone,
42
+ target_column=fetch_type
43
+ )
44
+
45
+ except NotSupportedError as e:
46
+ raise NotSupportedError(
47
+ f"{self.__class__.__name__} only support {list(self.transformer_map.keys())} companies now, {ticker} is not available"
48
+ ) from e
49
+
50
+ async def query_data(
51
+ self,
52
+ start_date=None,
53
+ end_date=None,
54
+ fetch_mode='QoQ',
55
+ use_cal=True,
56
+ indexes=None
57
+ ):
58
+ fetched_data = await self.db_extractor.query_data(
59
+ start_date=None, end_date=end_date
60
+ ) # 先索取目標日期之前的之後再截斷
61
+
62
+ if (start_date is None):
63
+ start_date = datetime.strptime("1991-01-01", "%Y-%m-%d")
64
+
65
+ transformed_data = self.transformer.process_transform(
66
+ fetched_data=fetched_data,
67
+ fetch_mode=fetch_mode,
68
+ start_date=start_date,
69
+ use_cal=use_cal,
70
+ indexes=indexes
71
+ ) # 轉換並根據開始日期截斷
72
+
73
+ return transformed_data
74
+
75
+ def _get_extractor(self, collection):
76
+ EXTRACTOR_MAP = {
77
+ "TEJ_finance_statement": AsyncTEJFinanceStatementDBExtractor,
78
+ "TEJ_self_settlement": AsyncTEJSelfSettlementDBExtractor,
79
+ }
80
+
81
+ extractor = EXTRACTOR_MAP.get(collection, None)
82
+
83
+ if (extractor is None):
84
+ raise ValueError(
85
+ f"{collection} not a regular argument for collection, only {list(EXTRACTOR_MAP.keys())} available"
86
+ )
87
+
88
+ return extractor
@@ -0,0 +1,62 @@
1
+ from .base import AsyncBaseFetcher
2
+ from datetime import datetime, timedelta
3
+ from ..db_extractors import (
4
+ AsyncTWSEChipDBExtractor,
5
+ AsyncYFDailyTechDBExtractor,
6
+ )
7
+ from neurostats_API.async_mode.factory import get_extractor
8
+ from neurostats_API.utils import NotSupportedError
9
+ from neurostats_API.transformers import TWSEChipTransformer
10
+
11
+
12
+ class AsyncTWSEInstitutionFetcher(AsyncBaseFetcher):
13
+
14
+ def __init__(self, ticker, client):
15
+ self.ticker = ticker
16
+ self.transformer_map = {"tw": TWSEChipTransformer}
17
+ try:
18
+ self.extractor = get_extractor(
19
+ "TWSE_chip", ticker, client, fetch_type='I'
20
+ )
21
+ self.daily_extractor = get_extractor("YF_tech", ticker, client)
22
+
23
+ company_name = self.extractor.get_company_name()
24
+ zone = self.extractor.get_zone()
25
+
26
+ transformer = self.get_transformer(zone)
27
+ self.transformer = transformer(ticker, company_name, zone)
28
+
29
+ except NotSupportedError as e:
30
+ raise NotSupportedError(
31
+ f"{self.__class__.__name__} only support {list(self.transformer_map.keys())} companies now, {ticker} is not available"
32
+ ) from e
33
+
34
+ async def query_data(
35
+ self, start_date=None, end_date=None, get_latest=False
36
+ ):
37
+ fetched_data = await self.extractor.query_data(
38
+ start_date, end_date, get_latest
39
+ )
40
+ tech_data = await self.daily_extractor.query_data(
41
+ start_date, end_date, get_latest
42
+ )
43
+
44
+ fetched_data = {"institution_trading": fetched_data}
45
+ transformed_data = self.transformer.process_transform(
46
+ tech_data=tech_data, **fetched_data
47
+ )
48
+
49
+ return transformed_data
50
+
51
+ async def query_data_annual(self):
52
+ """
53
+ 取一年內的資料
54
+ """
55
+ end_date = datetime.today()
56
+ start_date = end_date - timedelta(days=365)
57
+
58
+ fetched_data = await self.query_data(
59
+ start_date, end_date, get_latest=False
60
+ )
61
+
62
+ return fetched_data