neurostats-API 0.0.25__py3-none-any.whl → 1.0.0rc1__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 +44 -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 +159 -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 +412 -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.0rc1.dist-info/METADATA +102 -0
  92. neurostats_API-1.0.0rc1.dist-info/RECORD +119 -0
  93. neurostats_API-0.0.25.dist-info/METADATA +0 -858
  94. neurostats_API-0.0.25.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.25.dist-info → neurostats_API-1.0.0rc1.dist-info}/WHEEL +0 -0
  105. {neurostats_API-0.0.25.dist-info → neurostats_API-1.0.0rc1.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- __version__='0.0.25'
1
+ __version__='1.0.0rc1'
2
2
 
3
3
  from .fetchers import (
4
4
  AgentFinanceOverviewFetcher,
@@ -0,0 +1,13 @@
1
+ from .fetchers import (
2
+ AsyncAgentOverviewFetcher,
3
+ AsyncBalanceSheetFetcher,
4
+ AsyncCashFlowFetcher,
5
+ AsyncFinanceOverviewFetcher,
6
+ AsyncMonthlyRevenueFetcher,
7
+ AsyncProfitLoseFetcher,
8
+ AsyncTechFetcher,
9
+ AsyncTEJSeasonalFetcher,
10
+ AsyncTWSEInstitutionFetcher,
11
+ AsyncTWSEMarginFetcher,
12
+ AsyncTWSEStatsValueFetcher
13
+ )
@@ -0,0 +1,3 @@
1
+ from .twse import TWSEDBClient
2
+ from .tej import TEJDBClient
3
+ from .us import USDBClient
@@ -0,0 +1,24 @@
1
+ from pymongo import AsyncMongoClient
2
+
3
+ class BaseDBClient:
4
+ def __init__(self, client: AsyncMongoClient, zone= None):
5
+ self.client = client
6
+ self.zone = zone or "tw" # 預設台灣
7
+ self.db = self._select_db()
8
+
9
+ def _select_db(self):
10
+ """
11
+ 根據 zone 選擇對應的資料庫
12
+ """
13
+ zone_db_map = {
14
+ "tw": "company_test",
15
+ "us": "company_us"
16
+ }
17
+ db_name = zone_db_map.get(self.zone, "company_test")
18
+ return self.client[db_name]
19
+
20
+ def get_collection(self, collection_name: str):
21
+ """
22
+ 傳回指定 collection
23
+ """
24
+ return self.db[collection_name]
@@ -0,0 +1,10 @@
1
+ from .base import BaseDBClient
2
+ import os
3
+ from pymongo import AsyncMongoClient
4
+ from dotenv import load_dotenv
5
+
6
+ class TEJDBClient(BaseDBClient):
7
+ def __init__(self, mongo_uri):
8
+ """初始化時接收 MongoDB 連接 URI"""
9
+ super().__init__(mongo_uri, zone = 'tw')
10
+ self.db = self.client["company_test"]
@@ -0,0 +1,8 @@
1
+ from .base import BaseDBClient
2
+ import os
3
+ from pymongo import AsyncMongoClient
4
+ from dotenv import load_dotenv
5
+
6
+ class TWSEDBClient(BaseDBClient):
7
+ def __init__(self, client):
8
+ super().__init__(client, zone= "tw")
@@ -0,0 +1,9 @@
1
+ from .base import BaseDBClient
2
+ import os
3
+ from pymongo import AsyncMongoClient
4
+ from dotenv import load_dotenv
5
+
6
+ class USDBClient(BaseDBClient):
7
+ def __init__(self, client):
8
+ """初始化時接收 MongoDB 連接 URI"""
9
+ super().__init__(client, zone = 'us')
@@ -0,0 +1,20 @@
1
+ from .daily import (
2
+ AsyncTEJDailyTechDBExtractor,
3
+ AsyncYFDailyTechDBExtractor,
4
+ AsyncDailyValueDBExtractor,
5
+ AsyncTEJDailyValueDBExtractor,
6
+ AsyncTWSEChipDBExtractor,
7
+
8
+ )
9
+
10
+ from .month_revenue import (
11
+ AsyncTWSEMonthlyRevenueExtractor
12
+ )
13
+
14
+ from .seasonal import (
15
+ AsyncBalanceSheetExtractor,
16
+ AsyncProfitLoseExtractor,
17
+ AsyncCashFlowExtractor,
18
+ AsyncTEJFinanceStatementDBExtractor,
19
+ AsyncTEJSelfSettlementDBExtractor
20
+ )
@@ -0,0 +1,66 @@
1
+ import abc
2
+ from datetime import datetime
3
+ from ..db import TWSEDBClient, USDBClient
4
+ import json
5
+ import pytz
6
+ from neurostats_API.utils import StatsDateTime, StatsProcessor, YoY_Calculator, NoCompanyError
7
+
8
+ class BaseDBExtractor(abc.ABC):
9
+ def __init__(self, ticker, client):
10
+ self.ticker = ticker
11
+ self.client = client
12
+ self.timezone = pytz.timezone("Asia/Taipei")
13
+ self.tw_company_list = StatsProcessor.load_json("company_list/tw.json")
14
+ self.us_company_list = StatsProcessor.load_json("company_list/us.json")
15
+
16
+ self.company_name, self.zone = self._set_company_name(self.ticker)
17
+
18
+ self.db_client = self._set_db_connection()
19
+
20
+ def _set_company_name(self, ticker):
21
+ company_lists = [
22
+ (self.tw_company_list, 'tw'),
23
+ (self.us_company_list, 'us')
24
+ ]
25
+
26
+ for company_list, zone in company_lists:
27
+ company_name = company_list.get(ticker, None)
28
+ if (company_name):
29
+ return company_name, zone
30
+ # 沒找到公司名稱
31
+ raise NoCompanyError(f"Ticker-{ticker} not found in any company lists")
32
+
33
+ def _set_db_connection(self):
34
+ db_map = {
35
+ 'tw': TWSEDBClient,
36
+ 'us': USDBClient
37
+ }
38
+ db_client = db_map.get(self.zone, TWSEDBClient)
39
+ return db_client(self.client)
40
+
41
+
42
+
43
+ async def query_data(self):
44
+ """
45
+ user使用的接口
46
+ """
47
+ return NotImplementedError()
48
+
49
+ @abc.abstractmethod
50
+ def _prepare_query(self):
51
+ pass
52
+
53
+ def get_company_name(self):
54
+ """
55
+ 回傳公司
56
+ """
57
+ return self.company_name
58
+
59
+ def get_zone(self):
60
+ """
61
+ 公司區域(TW, US)
62
+ """
63
+ return self.zone
64
+
65
+ def _get_today(self):
66
+ return datetime.today()
@@ -0,0 +1,7 @@
1
+ from .tej_tech import AsyncTEJDailyTechDBExtractor
2
+ from .twse_chip import AsyncTWSEChipDBExtractor
3
+ from .value import (
4
+ AsyncDailyValueDBExtractor,
5
+ AsyncTEJDailyValueDBExtractor
6
+ )
7
+ from .yf import AsyncYFDailyTechDBExtractor
@@ -0,0 +1,89 @@
1
+ from ..base import BaseDBExtractor
2
+ from datetime import datetime
3
+ from neurostats_API.utils import NotSupportedError
4
+ from pymongo import ASCENDING, DESCENDING
5
+
6
+
7
+ class BaseDailyTechDBExtractor(BaseDBExtractor):
8
+
9
+ def __init__(self, ticker, client):
10
+ super().__init__(ticker, client)
11
+
12
+ self.collection_name_map = None
13
+ self.collection_name = self._get_collection_name()
14
+
15
+ if (self.collection_name is None):
16
+ raise NotSupportedError(
17
+ f"{self.__class__.__name__} only supports {list(self.collection_name_map.keys())}, got {self.zone} with ticker = \"{self.ticker}\""
18
+ )
19
+
20
+ self.collection = self.db_client.get_collection(self.collection_name)
21
+
22
+ async def query_data(self, start_date=None, end_date=None, get_latest = False):
23
+ if (self.collection is None):
24
+ return []
25
+
26
+ if (start_date is None):
27
+ start_date = "1991-01-01"
28
+ if (end_date is None):
29
+ end_date = self._get_today()
30
+
31
+ query, projection, sort = self._prepare_query(
32
+ start_date=start_date, end_date=end_date, get_latest=get_latest
33
+ )
34
+
35
+ if (get_latest):
36
+ cursor = self.collection.find(query, projection).sort(sort).limit(1)
37
+ else:
38
+ cursor = self.collection.find(query, projection).sort(sort)
39
+
40
+ fetched_data = [data async for data in cursor]
41
+
42
+ return fetched_data
43
+
44
+ def _get_collection_name(self):
45
+ self.collection_name_map = {"tw": "twse_daily_share_price", "us": "us_technical"}
46
+ collection_name = self.collection_name_map.get(self.zone, None)
47
+
48
+ return collection_name
49
+
50
+ def _prepare_query(self, start_date=None, end_date=None, get_latest = False):
51
+ query = {"ticker": self.ticker}
52
+
53
+ query = self._update_query_with_date(query, start_date, end_date)
54
+
55
+ projection = {
56
+ "_id": 0,
57
+ }
58
+
59
+ if (get_latest):
60
+ sort = [("date", DESCENDING)]
61
+ else:
62
+ sort = [("date", ASCENDING)]
63
+
64
+ return query, projection, sort
65
+
66
+ def _update_query_with_date(self, query, start_date, end_date):
67
+ start_date = self._transform_date(start_date)
68
+ end_date = self._transform_date(end_date)
69
+
70
+ date_range = {"$gte": start_date, "$lte": end_date}
71
+
72
+ query.update({"date": date_range})
73
+
74
+ return query
75
+
76
+ def _transform_date(self, date):
77
+ if (isinstance(date, str)):
78
+ try:
79
+ return datetime.strptime(date, "%Y-%m-%d")
80
+ except Exception as e:
81
+ raise ValueError(
82
+ "date string format imcompatible, should be \"YYYY-MM-DD\""
83
+ )
84
+ elif (isinstance(date, datetime)):
85
+ return date
86
+ else:
87
+ raise ValueError(
88
+ "date type imcompatible, should be string(\"YYYY-MM-DD\") or datetime.datetime"
89
+ )
@@ -0,0 +1,14 @@
1
+ from .base import BaseDailyTechDBExtractor
2
+ from datetime import datetime
3
+ from pymongo import ASCENDING, DESCENDING
4
+
5
+
6
+ class AsyncTEJDailyChipDBExtractor(BaseDailyTechDBExtractor):
7
+
8
+ def __init__(self, ticker, client):
9
+ super().__init__(ticker, client)
10
+
11
+ def _get_collection_name(self):
12
+ self.collection_name_map = {"tw": "TEJ_chip"}
13
+
14
+ return self.collection_name_map.get(self.zone, None)
@@ -0,0 +1,12 @@
1
+ from .base import BaseDailyTechDBExtractor
2
+
3
+
4
+ class AsyncTEJDailyTechDBExtractor(BaseDailyTechDBExtractor):
5
+
6
+ def __init__(self, ticker, client):
7
+ super().__init__(ticker, client)
8
+
9
+ def _get_collection_name(self):
10
+ self.collection_name_map = {"tw": "TEJ_share_price"}
11
+
12
+ return self.collection_name_map.get(self.zone, None)
@@ -0,0 +1,44 @@
1
+ from .base import BaseDailyTechDBExtractor
2
+ from datetime import datetime
3
+ from pymongo import ASCENDING, DESCENDING
4
+ from neurostats_API.utils import NotSupportedError
5
+
6
+ class AsyncTWSEChipDBExtractor(BaseDailyTechDBExtractor):
7
+
8
+ def __init__(self, ticker, client, fetch_type = 'I'):
9
+
10
+ """
11
+ 擷取台股每日籌碼資料。
12
+
13
+ fetch_type:
14
+ - 'I' (INSTITUTION): 法人買賣
15
+ - 'M' (MARGIN): 融資融券餘額變化
16
+ - 'S' (SECURITY_LENDING): 借券債券
17
+
18
+ """
19
+ super().__init__(ticker, client)
20
+
21
+ column_name_map = {
22
+ 'tw': {
23
+ "I" : "institution_trading",
24
+ "M" : "margin_trading",
25
+ "S" : "security_lending"
26
+ },
27
+ }
28
+ self.target_column = column_name_map[self.zone][fetch_type]
29
+
30
+ def _get_collection_name(self):
31
+ self.collection_name_map = {"tw": "twse_chip"}
32
+ collection_name = self.collection_name_map.get(self.zone, None)
33
+ return collection_name
34
+
35
+ def _prepare_query(self, start_date=None, end_date=None, get_latest = False):
36
+ query, projection, sort = super()._prepare_query(start_date, end_date, get_latest)
37
+ projection.update(
38
+ {
39
+ 'date': 1,
40
+ self.target_column: 1
41
+ }
42
+ )
43
+
44
+ return query, projection, sort
@@ -0,0 +1,93 @@
1
+ from .base import BaseDailyTechDBExtractor
2
+ from pymongo import ASCENDING, DESCENDING
3
+ from neurostats_API.utils import NotSupportedError
4
+
5
+ class AsyncDailyValueDBExtractor(BaseDailyTechDBExtractor):
6
+
7
+ def __init__(self, ticker, client, fetch_type='D'):
8
+ """
9
+ fetch_type:
10
+ 'D': daily
11
+ 'Y': yearly
12
+ """
13
+ self.fetch_type = fetch_type
14
+ super().__init__(ticker, client)
15
+
16
+ def _get_collection_name(self):
17
+ self.collection_name_map = {
18
+ "tw": {
19
+ "D":"twse_daily_share_price",
20
+ "Y": "twse_yearly_value"
21
+ }
22
+ }
23
+ collection_map = self.collection_name_map.get(self.zone)
24
+ if (collection_map is None):
25
+ raise NotSupportedError(f"AsyncDailyValueDBExtractor only supports {self.collection_name_map.keys}, but get {self.zone}")
26
+ collection_name = collection_map.get(self.fetch_type)
27
+ if (collection_name is None):
28
+ raise ValueError(f"AsyncDailyValueDBExtractor: Invalid fetch type : {self.fetch_type}")
29
+ return collection_name
30
+
31
+ def _prepare_query(self, start_date = None, end_date = None, get_latest = False):
32
+ query_fn_map = {
33
+ 'D': super()._prepare_query,
34
+ 'Y': self._prepare_annual_query
35
+ }
36
+
37
+ query_fn = query_fn_map.get(self.fetch_type)
38
+ query, projection, sorting = query_fn(start_date=start_date, end_date=end_date, get_latest=get_latest)
39
+
40
+ projection.update(
41
+ {
42
+ "date": 1,
43
+ "year": 1,
44
+ "close": 1,
45
+ "P_E": 1,
46
+ "P_B": 1,
47
+ "P_FCF": 1,
48
+ "P_S": 1,
49
+ "EV_S": 1,
50
+ "EV_OPI": 1,
51
+ "EV_EBIT": 1,
52
+ "EV_EBITDA": 1
53
+ }
54
+ )
55
+
56
+ return query, projection, sorting
57
+
58
+
59
+ def _prepare_annual_query(self, start_date, end_date, get_latest = False):
60
+ start_date = self._transform_date(start_date)
61
+ end_date = self._transform_date(end_date)
62
+
63
+ start_year = start_date.year - 1911
64
+ end_year = end_date.year - 1911
65
+ query = {
66
+ "ticker": self.ticker,
67
+ "year": {
68
+ "$gte": start_year,
69
+ "$lte": end_year
70
+ }
71
+ }
72
+
73
+ projection = {
74
+ "_id": 0,
75
+ }
76
+
77
+ if (get_latest):
78
+ sort = [("year", DESCENDING)]
79
+ else:
80
+ sort = [("year", ASCENDING)]
81
+
82
+ return query, projection, sort
83
+
84
+
85
+ class AsyncTEJDailyValueDBExtractor(BaseDailyTechDBExtractor):
86
+
87
+ def __init__(self, ticker, mongo_uri):
88
+ super().__init__(ticker, mongo_uri)
89
+
90
+ def _get_collection_name(self):
91
+ self.collection_name_map = {"tw": "TEJ_share_price"}
92
+
93
+ return self.collection_name_map.get(self.zone, None)
@@ -0,0 +1,12 @@
1
+ from .base import BaseDailyTechDBExtractor
2
+
3
+
4
+ class AsyncYFDailyTechDBExtractor(BaseDailyTechDBExtractor):
5
+
6
+ def __init__(self, ticker, client):
7
+ super().__init__(ticker, client)
8
+
9
+ def _get_collection_name(self):
10
+ self.collection_name_map = {"tw": "twse_daily_share_price", "us": "us_technical"}
11
+
12
+ return self.collection_name_map.get(self.zone, None)
@@ -0,0 +1 @@
1
+ from .twse import AsyncTWSEMonthlyRevenueExtractor
@@ -0,0 +1,140 @@
1
+ from ..base import BaseDBExtractor
2
+ from datetime import datetime
3
+ import json
4
+ import pandas as pd
5
+ from pymongo import ASCENDING, DESCENDING
6
+ from neurostats_API.async_mode.db import TWSEDBClient, USDBClient
7
+ from neurostats_API.utils import StatsDateTime, StatsProcessor, NotSupportedError
8
+ import yaml
9
+
10
+
11
+ class AsyncBaseMonthlyDBExtractor(BaseDBExtractor):
12
+
13
+ def __init__(self, ticker, client):
14
+ super().__init__(ticker, client)
15
+
16
+ self.collection_name_map = None
17
+ self.collection_name = self._get_collection_name()
18
+
19
+ if (self.collection_name is None):
20
+ raise NotSupportedError(
21
+ f"{self.__class__.__name__} only supports {list(self.collection_name_map.keys())}, got {self.zone} with ticker = \"{self.ticker}\""
22
+ )
23
+
24
+ self.collection = self.db_client.get_collection(self.collection_name)
25
+
26
+ async def query_data(
27
+ self, start_date=None, end_date=None, get_latest=False
28
+ ):
29
+ if (start_date is None):
30
+ start_date = "1991-01-01"
31
+ if (end_date is None):
32
+ end_date = self._get_today()
33
+
34
+ start_year, start_month = self._get_year_and_month(date=start_date)
35
+ end_year, end_month = self._get_year_and_month(date=end_date)
36
+
37
+ query, projection, sort = self._prepare_query(
38
+ start_year, start_month, end_year, end_month, get_latest
39
+ )
40
+ cursor = self.collection.find(query, projection).sort(sort)
41
+ if (get_latest):
42
+ cursor = cursor.limit(1)
43
+
44
+ fetched_data = [data async for data in cursor]
45
+
46
+ return fetched_data
47
+
48
+ def _get_collection_name(self):
49
+ self.collection_name_map = {
50
+ "tw": "twse_monthly_revenue",
51
+ }
52
+
53
+ collection_name = self.collection_name_map.get(self.zone, None)
54
+
55
+ return collection_name
56
+
57
+ def _prepare_query(
58
+ self,
59
+ start_year=None,
60
+ start_month=None,
61
+ end_year=None,
62
+ end_month=None,
63
+ get_latest=False
64
+ ):
65
+
66
+ query = {"ticker": self.ticker}
67
+
68
+ query = self._update_query_with_year_month(
69
+ query, start_year, start_month, end_year, end_month
70
+ )
71
+
72
+ projection = {
73
+ "_id": 0,
74
+ }
75
+
76
+ if (get_latest):
77
+ sort = [("year", DESCENDING), ("month", DESCENDING)]
78
+ else:
79
+ sort = [("year", ASCENDING), ("month", ASCENDING)]
80
+
81
+ return query, projection, sort
82
+
83
+ def _get_year_and_month(self, date):
84
+ if (isinstance(date, str)):
85
+ date = datetime.strptime(date, "%Y-%m-%d")
86
+
87
+ year = date.year
88
+ month = date.month
89
+
90
+ return year, month
91
+
92
+ def _update_query_with_year_month(
93
+ self, query, start_year, start_month, end_year, end_month
94
+ ):
95
+ if all(v is not None for v in [start_year, start_month]):
96
+ # 大於start_year條件
97
+ query.update(
98
+ {
99
+ "$or": [
100
+ {
101
+ "year": {
102
+ "$gt": start_year
103
+ }
104
+ },
105
+ {
106
+ "year": start_year,
107
+ "month": {
108
+ "$gte": start_month
109
+ }
110
+ },
111
+ ]
112
+ }
113
+ )
114
+
115
+ if all(v is not None for v in [end_year, end_month]):
116
+ # 小於end_year條件
117
+ query.update(
118
+ {
119
+ "$and":
120
+ query.get("$and", []) + [
121
+ {
122
+ "$or": [
123
+ {
124
+ "year": {
125
+ "$lt": end_year
126
+ }
127
+ },
128
+ {
129
+ "year": end_year,
130
+ "month": {
131
+ "$lte": end_month
132
+ }
133
+ },
134
+ ]
135
+ }
136
+ ]
137
+ }
138
+ )
139
+
140
+ return query
@@ -0,0 +1,5 @@
1
+ from .base import AsyncBaseMonthlyDBExtractor
2
+
3
+ class AsyncTWSEMonthlyRevenueExtractor(AsyncBaseMonthlyDBExtractor):
4
+ def __init__(self, ticker, client):
5
+ super().__init__(ticker, client)
@@ -0,0 +1,4 @@
1
+ from .balance_sheet import AsyncBalanceSheetExtractor
2
+ from .profit_lose import AsyncProfitLoseExtractor
3
+ from .cashflow import AsyncCashFlowExtractor
4
+ from .tej import AsyncTEJFinanceStatementDBExtractor, AsyncTEJSelfSettlementDBExtractor
@@ -0,0 +1,19 @@
1
+ from .base import AsyncBaseSeasonalDBExtractor
2
+ from datetime import datetime
3
+ import json
4
+ import pandas as pd
5
+ from pymongo import ASCENDING, DESCENDING
6
+ from neurostats_API.async_mode.db import TWSEDBClient, USDBClient
7
+ from neurostats_API.utils import StatsDateTime, StatsProcessor
8
+ import yaml
9
+
10
+ class AsyncBalanceSheetExtractor(AsyncBaseSeasonalDBExtractor):
11
+
12
+ def __init__(self, ticker, client):
13
+
14
+ super().__init__(ticker, client)
15
+
16
+ self.column_name_map = {
17
+ 'tw': "balance_sheet",
18
+ 'us': "balance_sheet"
19
+ }