neurostats-API 0.0.6__py3-none-any.whl → 0.0.7__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.
- neurostats_API/__init__.py +1 -1
- neurostats_API/fetchers/__init__.py +4 -0
- neurostats_API/fetchers/balance_sheet.py +122 -0
- neurostats_API/fetchers/cash_flow.py +181 -0
- neurostats_API/fetchers/finance_overview.py +3 -1
- neurostats_API/fetchers/month_revenue.py +92 -0
- neurostats_API/fetchers/profit_lose.py +131 -0
- neurostats_API/tools/balance_sheet.yaml +26 -0
- neurostats_API/tools/cash_flow_percentage.yaml +39 -0
- neurostats_API/tools/profit_lose.yaml +1 -1
- neurostats_API/utils/data_process.py +123 -3
- {neurostats_API-0.0.6.dist-info → neurostats_API-0.0.7.dist-info}/METADATA +135 -187
- neurostats_API-0.0.7.dist-info/RECORD +26 -0
- neurostats_API-0.0.6.dist-info/RECORD +0 -23
- {neurostats_API-0.0.6.dist-info → neurostats_API-0.0.7.dist-info}/WHEEL +0 -0
- {neurostats_API-0.0.6.dist-info → neurostats_API-0.0.7.dist-info}/top_level.txt +0 -0
neurostats_API/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__='0.0.
|
1
|
+
__version__='0.0.7'
|
@@ -1,3 +1,7 @@
|
|
1
1
|
from .base import StatsDateTime, StatsFetcher
|
2
|
+
from .balance_sheet import BalanceSheetFetcher
|
3
|
+
from .cash_flow import CashFlowFetcher
|
2
4
|
from .finance_overview import FinanceOverviewFetcher
|
5
|
+
from .month_revenue import MonthRevenueFetcher
|
6
|
+
from .profit_lose import ProfitLoseFetcher
|
3
7
|
from .value_invest import ValueFetcher
|
@@ -0,0 +1,122 @@
|
|
1
|
+
from .base import StatsFetcher, StatsDateTime
|
2
|
+
import json
|
3
|
+
import pandas as pd
|
4
|
+
from ..utils import StatsDateTime, StatsProcessor
|
5
|
+
import importlib.resources as pkg_resources
|
6
|
+
import yaml
|
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("balance_sheet.yaml")
|
16
|
+
|
17
|
+
def prepare_query(self, target_year, target_season):
|
18
|
+
pipeline = super().prepare_query()
|
19
|
+
|
20
|
+
target_query = {
|
21
|
+
"year": "$$target_season_data.year",
|
22
|
+
"season": "$$target_season_data.season",
|
23
|
+
"balance_sheet": "$$$$target_season_data.balance_sheet"
|
24
|
+
}
|
25
|
+
|
26
|
+
pipeline.append({
|
27
|
+
"$project": {
|
28
|
+
"_id": 0,
|
29
|
+
"ticker": 1,
|
30
|
+
"company_name": 1,
|
31
|
+
"balance_sheets": {
|
32
|
+
"$sortArray": {
|
33
|
+
"input": {
|
34
|
+
"$map": {
|
35
|
+
"input": {
|
36
|
+
"$filter": {
|
37
|
+
"input": "$seasonal_data",
|
38
|
+
"as": "season",
|
39
|
+
"cond": {
|
40
|
+
"$eq": ["$$season.season", target_season]
|
41
|
+
}
|
42
|
+
}
|
43
|
+
},
|
44
|
+
"as": "target_season_data",
|
45
|
+
"in": {
|
46
|
+
"year": "$$target_season_data.year",
|
47
|
+
"season": "$$target_season_data.season",
|
48
|
+
"balance_sheet": "$$target_season_data.balance_sheet"
|
49
|
+
}
|
50
|
+
}
|
51
|
+
},
|
52
|
+
"sortBy": { "year": -1 } # 按 year 降序排序
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
})
|
57
|
+
|
58
|
+
return pipeline
|
59
|
+
|
60
|
+
def collect_data(self, target_year, target_season):
|
61
|
+
pipeline = self.prepare_query(target_year, target_season)
|
62
|
+
|
63
|
+
fetched_data = self.collection.aggregate(pipeline)
|
64
|
+
|
65
|
+
fetched_data = list(fetched_data)
|
66
|
+
|
67
|
+
return fetched_data[-1]
|
68
|
+
|
69
|
+
def query_data(self):
|
70
|
+
today = StatsDateTime.get_today()
|
71
|
+
|
72
|
+
year = today.year - 1 if (today.season == 1) else today.year
|
73
|
+
season = 4 if (today.season == 1) else today.season - 2
|
74
|
+
fetched_data = self.collect_data(year, season)
|
75
|
+
|
76
|
+
return self.process_data(season, fetched_data)
|
77
|
+
|
78
|
+
def process_data(self, target_season, fetched_data):
|
79
|
+
return_dict = {
|
80
|
+
"ticker": self.ticker,
|
81
|
+
"company_name": fetched_data['company_name']
|
82
|
+
}
|
83
|
+
|
84
|
+
index_names = []
|
85
|
+
|
86
|
+
table_dict = dict()
|
87
|
+
|
88
|
+
balance_sheets = fetched_data['balance_sheets']
|
89
|
+
|
90
|
+
# 將value與percentage跟著年分季度一筆筆取出
|
91
|
+
for data in balance_sheets:
|
92
|
+
year = data['year']
|
93
|
+
|
94
|
+
time_index = f"{year}Q{target_season}"
|
95
|
+
|
96
|
+
# 蒐集整體的keys
|
97
|
+
index_names += list(data['balance_sheet'].keys())
|
98
|
+
balance_sheet = data['balance_sheet']
|
99
|
+
|
100
|
+
for index_name, value_dict in balance_sheet.items():
|
101
|
+
for item_name, item in value_dict.items():
|
102
|
+
try: # table_dict[項目][(2020Q1, '%')]
|
103
|
+
table_dict[index_name][(time_index,item_name)] = item
|
104
|
+
|
105
|
+
except KeyError:
|
106
|
+
if (index_name not in table_dict.keys()):
|
107
|
+
table_dict[index_name] = dict()
|
108
|
+
|
109
|
+
table_dict[index_name][(time_index,item_name)] = item
|
110
|
+
|
111
|
+
total_table = pd.DataFrame.from_dict(table_dict, orient='index')
|
112
|
+
total_table.columns = pd.MultiIndex.from_tuples(total_table.columns)
|
113
|
+
|
114
|
+
for name, setting in self.table_settings.items():
|
115
|
+
return_dict[name] = StatsProcessor.slice_multi_col_table(
|
116
|
+
total_table=total_table,
|
117
|
+
mode=setting['mode'],
|
118
|
+
target_index=setting['target_index']
|
119
|
+
if "target_index" in setting.keys() else None)
|
120
|
+
|
121
|
+
print(f"{name}: {return_dict[name].columns}")
|
122
|
+
return return_dict
|
@@ -0,0 +1,181 @@
|
|
1
|
+
from .base import StatsFetcher, StatsDateTime
|
2
|
+
import json
|
3
|
+
import pandas as pd
|
4
|
+
from ..utils import StatsDateTime, StatsProcessor
|
5
|
+
import importlib.resources as pkg_resources
|
6
|
+
import yaml
|
7
|
+
|
8
|
+
class CashFlowFetcher(StatsFetcher):
|
9
|
+
def __init__(self, ticker, db_client):
|
10
|
+
super().__init__(ticker, db_client)
|
11
|
+
|
12
|
+
self.cash_flow_dict = StatsProcessor.load_yaml(
|
13
|
+
"cash_flow_percentage.yaml"
|
14
|
+
) # 計算子表格用
|
15
|
+
|
16
|
+
def prepare_query(self, target_season):
|
17
|
+
pipeline = super().prepare_query()
|
18
|
+
|
19
|
+
pipeline.append({
|
20
|
+
"$project": {
|
21
|
+
"_id": 0,
|
22
|
+
"ticker": 1,
|
23
|
+
"company_name": 1,
|
24
|
+
"cash_flows": {
|
25
|
+
"$sortArray": {
|
26
|
+
"input": {
|
27
|
+
"$map": {
|
28
|
+
"input": {
|
29
|
+
"$filter": {
|
30
|
+
"input": "$seasonal_data",
|
31
|
+
"as": "season",
|
32
|
+
"cond": {
|
33
|
+
"$eq":
|
34
|
+
["$$season.season", target_season]
|
35
|
+
}
|
36
|
+
}
|
37
|
+
},
|
38
|
+
"as": "target_season_data",
|
39
|
+
"in": {
|
40
|
+
"year":
|
41
|
+
"$$target_season_data.year",
|
42
|
+
"season":
|
43
|
+
"$$target_season_data.season",
|
44
|
+
"cash_flow":
|
45
|
+
"$$target_season_data.cash_flow"
|
46
|
+
}
|
47
|
+
}
|
48
|
+
},
|
49
|
+
"sortBy": {
|
50
|
+
"year": -1
|
51
|
+
} # 按 year 降序排序
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
})
|
56
|
+
|
57
|
+
return pipeline
|
58
|
+
|
59
|
+
def collect_data(self, target_season):
|
60
|
+
pipeline = self.prepare_query(target_season)
|
61
|
+
|
62
|
+
fetched_data = self.collection.aggregate(pipeline)
|
63
|
+
|
64
|
+
return list(fetched_data)[0]
|
65
|
+
|
66
|
+
def query_data(self):
|
67
|
+
today = StatsDateTime.get_today()
|
68
|
+
|
69
|
+
target_season = today.season - 1 if (today.season > 1) else 4
|
70
|
+
|
71
|
+
fetched_data = self.collect_data(target_season)
|
72
|
+
|
73
|
+
return self.process_data(fetched_data, target_season)
|
74
|
+
|
75
|
+
def process_data(self, fetched_data, target_season):
|
76
|
+
"""
|
77
|
+
處理現金流量表頁面的所有表格
|
78
|
+
金流表本身沒有比例 但是Ifa有算,
|
79
|
+
項目所屬的情況也不一(分別所屬營業,投資,籌資三個活動)
|
80
|
+
所以這裡選擇不用slicing處理
|
81
|
+
"""
|
82
|
+
cash_flows = fetched_data['cash_flows']
|
83
|
+
|
84
|
+
index_names = []
|
85
|
+
column_names = []
|
86
|
+
|
87
|
+
table_dict = dict()
|
88
|
+
CASHO_dict = dict()
|
89
|
+
CASHI_dict = dict()
|
90
|
+
CASHF_dict = dict()
|
91
|
+
|
92
|
+
return_dict = {
|
93
|
+
"ticker": fetched_data['ticker'],
|
94
|
+
"company_name": fetched_data['company_name'],
|
95
|
+
"cash_flow": dict(),
|
96
|
+
"CASHO": dict(),
|
97
|
+
"CASHI": dict(),
|
98
|
+
"CASHF": dict()
|
99
|
+
}
|
100
|
+
|
101
|
+
checkpoints = ["營業活動之現金流量-間接法", "投資活動之現金流量", "籌資活動之現金流量", "匯率變動對現金及約當現金之影響"]
|
102
|
+
main_cash_flows = [
|
103
|
+
"營業活動之淨現金流入(流出)", "投資活動之淨現金流入(流出)", "籌資活動之淨現金流入(流出)", None
|
104
|
+
] # 主要的比例對象
|
105
|
+
partial_cash_flows = [CASHO_dict, CASHI_dict, CASHF_dict, dict()]
|
106
|
+
|
107
|
+
# 作法: dictionary中也有checkpoints,如果出現了就換下一個index去計算
|
108
|
+
|
109
|
+
for data in cash_flows:
|
110
|
+
year = data['year']
|
111
|
+
|
112
|
+
time_index = f"{year}Q{target_season}"
|
113
|
+
|
114
|
+
cash_flow = data['cash_flow']
|
115
|
+
main_cash_flow_name = None
|
116
|
+
partial_cash_flow = None
|
117
|
+
next_checkpoint = 0
|
118
|
+
|
119
|
+
for index_name, value in cash_flow.items():
|
120
|
+
if (next_checkpoint < 3
|
121
|
+
and index_name == checkpoints[next_checkpoint]): # 找到了主要的變動點
|
122
|
+
main_cash_flow_name = main_cash_flows[next_checkpoint]
|
123
|
+
partial_cash_flow = partial_cash_flows[next_checkpoint]
|
124
|
+
next_checkpoint += 1
|
125
|
+
try:
|
126
|
+
table_dict[time_index][index_name]['value'] = value[
|
127
|
+
'value']
|
128
|
+
if (value['value']):
|
129
|
+
table_dict[time_index][index_name][
|
130
|
+
'percentage'] = value['value'] / cash_flow[
|
131
|
+
main_cash_flow_name]['value']
|
132
|
+
else:
|
133
|
+
table_dict[time_index][index_name][
|
134
|
+
'percentage'] = None
|
135
|
+
except:
|
136
|
+
if (time_index not in table_dict.keys()):
|
137
|
+
table_dict[time_index] = dict()
|
138
|
+
table_dict[time_index][index_name] = dict()
|
139
|
+
|
140
|
+
table_dict[time_index][index_name]['value'] = value[
|
141
|
+
'value']
|
142
|
+
if (value['value']):
|
143
|
+
table_dict[time_index][index_name][
|
144
|
+
'percentage'] = value['value'] / cash_flow[
|
145
|
+
main_cash_flow_name]['value']
|
146
|
+
else:
|
147
|
+
table_dict[time_index][index_name][
|
148
|
+
'percentage'] = None
|
149
|
+
|
150
|
+
try:
|
151
|
+
partial_cash_flow[time_index][index_name] = table_dict[
|
152
|
+
time_index][index_name]
|
153
|
+
except:
|
154
|
+
if (time_index not in partial_cash_flow.keys()):
|
155
|
+
partial_cash_flow[time_index] = dict()
|
156
|
+
partial_cash_flow[time_index][index_name] = table_dict[
|
157
|
+
time_index][index_name]
|
158
|
+
|
159
|
+
index_names += list(cash_flow.keys())
|
160
|
+
|
161
|
+
# 轉成dictionary keys
|
162
|
+
index_names = list(dict.fromkeys(index_names))
|
163
|
+
|
164
|
+
cash_flow_table = pd.DataFrame(table_dict)
|
165
|
+
cash_flow_table = StatsProcessor.expand_value_percentage(cash_flow_table)
|
166
|
+
|
167
|
+
CASHO_table = pd.DataFrame(CASHO_dict)
|
168
|
+
CASHO_table = StatsProcessor.expand_value_percentage(CASHO_table)
|
169
|
+
|
170
|
+
CASHI_table = pd.DataFrame(CASHI_dict)
|
171
|
+
CASHI_table = StatsProcessor.expand_value_percentage(CASHI_table)
|
172
|
+
|
173
|
+
CASHF_table = pd.DataFrame(CASHF_dict)
|
174
|
+
CASHF_table = StatsProcessor.expand_value_percentage(CASHF_table)
|
175
|
+
|
176
|
+
return_dict['cash_flow'] = cash_flow_table
|
177
|
+
return_dict['CASHO'] = CASHO_table
|
178
|
+
return_dict['CASHI'] = CASHI_table
|
179
|
+
return_dict['CASHF'] = CASHF_table
|
180
|
+
|
181
|
+
return return_dict
|
@@ -82,7 +82,9 @@ class FinanceOverviewFetcher(StatsFetcher):
|
|
82
82
|
def query_data(self):
|
83
83
|
today = StatsDateTime.get_today()
|
84
84
|
|
85
|
-
|
85
|
+
year = today.year - 1 if (today.season == 1) else today.year
|
86
|
+
season = 4 if (today.season == 1) else today.season - 2
|
87
|
+
fetched_data = self.collect_data(year, season)
|
86
88
|
finance_dict = fetched_data['seasonal_data'][0]
|
87
89
|
FinanceOverviewProcessor.process_all(finance_dict)
|
88
90
|
fetched_data['seasonal_data'] = finance_dict
|
@@ -0,0 +1,92 @@
|
|
1
|
+
from .base import StatsFetcher, StatsDateTime
|
2
|
+
import json
|
3
|
+
import pandas as pd
|
4
|
+
from ..utils import StatsDateTime, StatsProcessor
|
5
|
+
import importlib.resources as pkg_resources
|
6
|
+
import yaml
|
7
|
+
|
8
|
+
|
9
|
+
class MonthRevenueFetcher(StatsFetcher):
|
10
|
+
"""
|
11
|
+
iFa.ai: 財務分析 -> 每月營收
|
12
|
+
"""
|
13
|
+
|
14
|
+
def __init__(self, ticker, db_client):
|
15
|
+
super().__init__(ticker, db_client)
|
16
|
+
|
17
|
+
def prepare_query(self, target_year, target_month):
|
18
|
+
pipeline = super().prepare_query()
|
19
|
+
|
20
|
+
pipeline.append({
|
21
|
+
"$project": {
|
22
|
+
"_id": 0,
|
23
|
+
"ticker": 1,
|
24
|
+
"company_name": 1,
|
25
|
+
"monthly_data": {
|
26
|
+
"$sortArray": {
|
27
|
+
"input": "$monthly_data",
|
28
|
+
"sortBy": {
|
29
|
+
"year": -1,
|
30
|
+
"month": -1
|
31
|
+
}
|
32
|
+
}
|
33
|
+
},
|
34
|
+
}
|
35
|
+
})
|
36
|
+
|
37
|
+
return pipeline
|
38
|
+
|
39
|
+
def collect_data(self, target_year, target_month):
|
40
|
+
pipeline = self.prepare_query(target_year, target_month)
|
41
|
+
|
42
|
+
fetched_data = self.collection.aggregate(pipeline)
|
43
|
+
|
44
|
+
fetched_data = list(fetched_data)
|
45
|
+
|
46
|
+
return fetched_data[-1]
|
47
|
+
|
48
|
+
def query_data(self):
|
49
|
+
today = StatsDateTime.get_today()
|
50
|
+
target_month = today.month
|
51
|
+
target_year = today.year
|
52
|
+
|
53
|
+
# Query data
|
54
|
+
fetched_data = self.collect_data(target_year, target_month)
|
55
|
+
|
56
|
+
return self.process_data(fetched_data)
|
57
|
+
|
58
|
+
def process_data(self, fetched_data):
|
59
|
+
|
60
|
+
monthly_data = fetched_data['monthly_data']
|
61
|
+
target_month = monthly_data[0]['month']
|
62
|
+
monthly_df = pd.DataFrame(monthly_data)
|
63
|
+
target_month_df = monthly_df[monthly_df['month'] == target_month]
|
64
|
+
month_revenue_df = monthly_df.pivot(index='month',
|
65
|
+
columns='year',
|
66
|
+
values='revenue')
|
67
|
+
|
68
|
+
grand_total_df = target_month_df.pivot(index='month',
|
69
|
+
columns='year',
|
70
|
+
values='grand_total')
|
71
|
+
|
72
|
+
grand_total_df.rename(index={target_month: f"grand_total"},
|
73
|
+
inplace=True)
|
74
|
+
month_revenue_df = month_revenue_df.sort_index(ascending = False)
|
75
|
+
month_revenue_df = pd.concat([grand_total_df, month_revenue_df],
|
76
|
+
axis=0)
|
77
|
+
|
78
|
+
fetched_data['month_revenue'] = month_revenue_df[sorted(month_revenue_df.columns, reverse = True)]
|
79
|
+
# 歷年月營收
|
80
|
+
fetched_data[
|
81
|
+
'this_month_revenue_over_years'] = target_month_df.set_index(
|
82
|
+
"year")[["revenue", "revenue_increment_ratio", "YoY_1",
|
83
|
+
"YoY_3", "YoY_5", "YoY_10"]].T
|
84
|
+
# 歷年營收成長量
|
85
|
+
fetched_data['grand_total_over_years'] = target_month_df.set_index(
|
86
|
+
"year")[["grand_total", "grand_total_increment_ratio",
|
87
|
+
"grand_total_YoY_1", "grand_total_YoY_3",
|
88
|
+
"grand_total_YoY_5", "grand_total_YoY_10"]].T
|
89
|
+
|
90
|
+
fetched_data.pop("monthly_data")
|
91
|
+
|
92
|
+
return fetched_data
|
@@ -0,0 +1,131 @@
|
|
1
|
+
from .base import StatsFetcher, StatsDateTime
|
2
|
+
import json
|
3
|
+
import pandas as pd
|
4
|
+
from ..utils import StatsDateTime, StatsProcessor
|
5
|
+
import importlib.resources as pkg_resources
|
6
|
+
import yaml
|
7
|
+
|
8
|
+
|
9
|
+
class ProfitLoseFetcher(StatsFetcher):
|
10
|
+
"""
|
11
|
+
iFa.ai: 財務分析 -> 損益表
|
12
|
+
"""
|
13
|
+
|
14
|
+
def __init__(self, ticker, db_client):
|
15
|
+
super().__init__(ticker, db_client)
|
16
|
+
|
17
|
+
self.table_settings = StatsProcessor.load_yaml("profit_lose.yaml")
|
18
|
+
|
19
|
+
def prepare_query(self, target_season):
|
20
|
+
pipeline = super().prepare_query()
|
21
|
+
|
22
|
+
target_query = {
|
23
|
+
"year": "$$target_season_data.year",
|
24
|
+
"season": "$$target_season_data.season",
|
25
|
+
"balance_sheet": "$$$$target_season_data.balance_sheet"
|
26
|
+
}
|
27
|
+
|
28
|
+
pipeline.append({
|
29
|
+
"$project": {
|
30
|
+
"_id": 0,
|
31
|
+
"ticker": 1,
|
32
|
+
"company_name": 1,
|
33
|
+
"profit_loses": {
|
34
|
+
"$sortArray": {
|
35
|
+
"input": {
|
36
|
+
"$map": {
|
37
|
+
"input": {
|
38
|
+
"$filter": {
|
39
|
+
"input": "$seasonal_data",
|
40
|
+
"as": "season",
|
41
|
+
"cond": {
|
42
|
+
"$eq":
|
43
|
+
["$$season.season", target_season]
|
44
|
+
}
|
45
|
+
}
|
46
|
+
},
|
47
|
+
"as": "target_season_data",
|
48
|
+
"in": {
|
49
|
+
"year":
|
50
|
+
"$$target_season_data.year",
|
51
|
+
"season":
|
52
|
+
"$$target_season_data.season",
|
53
|
+
"profit_lose":
|
54
|
+
"$$target_season_data.profit_lose"
|
55
|
+
}
|
56
|
+
}
|
57
|
+
},
|
58
|
+
"sortBy": {
|
59
|
+
"year": -1
|
60
|
+
} # 按 year 降序排序
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
})
|
65
|
+
|
66
|
+
return pipeline
|
67
|
+
|
68
|
+
def collect_data(self, target_season):
|
69
|
+
pipeline = self.prepare_query(target_season)
|
70
|
+
|
71
|
+
fetched_data = self.collection.aggregate(pipeline)
|
72
|
+
|
73
|
+
return list(fetched_data)[-1]
|
74
|
+
|
75
|
+
def query_data(self):
|
76
|
+
today = StatsDateTime.get_today()
|
77
|
+
|
78
|
+
target_season = today.season
|
79
|
+
target_season = target_season - 1 if target_season > 1 else 4
|
80
|
+
|
81
|
+
fetched_data = self.collect_data(target_season)
|
82
|
+
|
83
|
+
return self.process_data(fetched_data, target_season)
|
84
|
+
|
85
|
+
def process_data(self, fetched_data, target_season):
|
86
|
+
|
87
|
+
profit_loses = fetched_data['profit_loses']
|
88
|
+
|
89
|
+
index_names = []
|
90
|
+
|
91
|
+
table_dict = dict()
|
92
|
+
grand_total_dict = dict()
|
93
|
+
|
94
|
+
return_dict = {
|
95
|
+
"ticker": fetched_data['ticker'],
|
96
|
+
"company_name": fetched_data['company_name'],
|
97
|
+
}
|
98
|
+
|
99
|
+
for data in profit_loses:
|
100
|
+
year = data['year']
|
101
|
+
|
102
|
+
time_index = f"{year}Q{target_season}"
|
103
|
+
|
104
|
+
# 蒐集整體的keys
|
105
|
+
index_names += list(data['profit_lose'].keys())
|
106
|
+
profit_lose = data['profit_lose']
|
107
|
+
|
108
|
+
for index_name, value_dict in profit_lose.items():
|
109
|
+
# (2020Q1, 項目, 金額或%)
|
110
|
+
for item_name, item in value_dict.items():
|
111
|
+
try:
|
112
|
+
table_dict[index_name][(time_index, item_name)] = item
|
113
|
+
|
114
|
+
except KeyError:
|
115
|
+
if (index_name not in table_dict.keys()):
|
116
|
+
table_dict[index_name] = dict()
|
117
|
+
grand_total_dict[index_name] = dict()
|
118
|
+
|
119
|
+
table_dict[index_name][(time_index, item_name)] = item
|
120
|
+
|
121
|
+
total_table = pd.DataFrame.from_dict(table_dict, orient='index')
|
122
|
+
total_table.columns = pd.MultiIndex.from_tuples(total_table.columns)
|
123
|
+
|
124
|
+
for name, setting in self.table_settings.items():
|
125
|
+
return_dict[name] = StatsProcessor.slice_multi_col_table(
|
126
|
+
total_table=total_table,
|
127
|
+
mode=setting['mode'],
|
128
|
+
target_index=setting['target_index']
|
129
|
+
if "target_index" in setting.keys() else None)
|
130
|
+
|
131
|
+
return return_dict
|
@@ -0,0 +1,26 @@
|
|
1
|
+
balance_sheet:
|
2
|
+
mode: value_and_percentage
|
3
|
+
|
4
|
+
total_asset:
|
5
|
+
mode: value_and_percentage
|
6
|
+
target_index: 資產總額 負債總額 權益總額
|
7
|
+
|
8
|
+
current_asset:
|
9
|
+
mode: value_and_percentage
|
10
|
+
target_index: 流動資產合計
|
11
|
+
|
12
|
+
non_current_asset:
|
13
|
+
mode: value_and_percentage
|
14
|
+
target_index: 非流動資產合計
|
15
|
+
|
16
|
+
current_debt:
|
17
|
+
mode: value_and_percentage
|
18
|
+
target_index: 流動負債合計
|
19
|
+
|
20
|
+
non_current_debt:
|
21
|
+
mode: value_and_percentage
|
22
|
+
target_index: 非流動負債合計
|
23
|
+
|
24
|
+
equity:
|
25
|
+
mode: value_and_percentage
|
26
|
+
target_index: 權益總額
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# 注意此並非用於slicing
|
2
|
+
CASHO:
|
3
|
+
main_index: 營業活動之淨現金流入(流出)
|
4
|
+
index:
|
5
|
+
- 繼續營業單位稅前淨利(淨損)
|
6
|
+
- 收益費損項目合計
|
7
|
+
- 折舊費用
|
8
|
+
- 攤銷費用
|
9
|
+
- 與營業活動相關之資產及負債之淨變動合計
|
10
|
+
- 營業活動之淨現金流入(流出)
|
11
|
+
|
12
|
+
CASHI:
|
13
|
+
main_index: 投資活動之淨現金流入(流出)
|
14
|
+
index:
|
15
|
+
- 投資活動之淨現金流入(流出)
|
16
|
+
- 取得不動產、廠房及設備
|
17
|
+
- 處分不動產、廠房及設備
|
18
|
+
- 取得無形資產
|
19
|
+
- 處分無形資產
|
20
|
+
- 取得透過損益按公允價值衡量之金融資產
|
21
|
+
- 處分透過損益按公允價值衡量之金融資產
|
22
|
+
- 取得透過其他綜合損益按公允價值衡量之金融資產
|
23
|
+
- 處分透過其他綜合損益按公允價值衡量之金融資產
|
24
|
+
- 取得按攤銷後成本衡量之金融資產
|
25
|
+
- 處分按攤銷後成本衡量之金融資產
|
26
|
+
- 按攤銷後成本衡量之金融資產到期還本
|
27
|
+
|
28
|
+
CASHO:
|
29
|
+
main_index: 籌資活動之淨現金流入(流出)
|
30
|
+
index:
|
31
|
+
- 籌資活動之淨現金流入(流出)
|
32
|
+
- 短期借款增加
|
33
|
+
- 短期借款減少
|
34
|
+
- 發行公司債
|
35
|
+
- 償還公司債
|
36
|
+
- 舉借長期借款
|
37
|
+
- 償還長期借款
|
38
|
+
- 發放現金股利
|
39
|
+
- 庫藏股票買回成本
|
@@ -1,18 +1,138 @@
|
|
1
1
|
from importlib.resources import files
|
2
2
|
import json
|
3
|
+
import pandas as pd
|
3
4
|
import yaml
|
4
5
|
|
6
|
+
target_metric_dict = {
|
7
|
+
'value': ['value'],
|
8
|
+
'value_and_percentage': ['value', 'percentage'],
|
9
|
+
'percentage': ['percentage'],
|
10
|
+
'grand_total': ['grand_total'],
|
11
|
+
'grand_total_values': ['grand_total', 'grand_total_percentage'],
|
12
|
+
'grand_total_percentage': ['grand_total_percentage'],
|
13
|
+
'growth': [f'YoY_{i}' for i in [1, 3, 5, 10]],
|
14
|
+
'grand_total_growth': [f"grand_total_YoY_{i}" for i in [1, 3, 5, 10]]
|
15
|
+
}
|
16
|
+
|
17
|
+
|
5
18
|
class StatsProcessor:
|
19
|
+
|
6
20
|
@classmethod
|
7
|
-
def load_txt(cls, filename, json_load
|
21
|
+
def load_txt(cls, filename, json_load=True):
|
8
22
|
txt_path = files('neurostats_API.tools').joinpath(filename)
|
9
23
|
with open(txt_path, 'r', encoding='utf-8') as f:
|
10
|
-
data = json.load(f) if (json_load) else f.read()
|
24
|
+
data = json.load(f) if (json_load) else f.read()
|
11
25
|
return data
|
26
|
+
|
12
27
|
@classmethod
|
13
28
|
def load_yaml(cls, filename):
|
14
29
|
yaml_path = files('neurostats_API.tools').joinpath(filename)
|
15
30
|
with open(yaml_path, 'r', encoding='utf-8') as f:
|
16
31
|
data = yaml.safe_load(f)
|
17
32
|
|
18
|
-
return data
|
33
|
+
return data
|
34
|
+
|
35
|
+
@classmethod
|
36
|
+
def expand_value_percentage(cls, dataframe):
|
37
|
+
|
38
|
+
expanded_columns = {}
|
39
|
+
for col in dataframe.columns:
|
40
|
+
# Use json_normalize to split 'value' and 'percentage'
|
41
|
+
expanded_df = pd.json_normalize(
|
42
|
+
dataframe[col]).add_prefix(f"{col}_")
|
43
|
+
expanded_df.index = dataframe.index
|
44
|
+
# Append the expanded columns to the new DataFrame
|
45
|
+
expanded_columns[col] = expanded_df
|
46
|
+
|
47
|
+
expanded_df = pd.concat(expanded_columns.values(), axis=1)
|
48
|
+
|
49
|
+
return expanded_df
|
50
|
+
|
51
|
+
@classmethod
|
52
|
+
def slice_table(
|
53
|
+
cls,
|
54
|
+
total_table,
|
55
|
+
mode='value',
|
56
|
+
target_index=None, # None or Str, 要特別抓哪個index
|
57
|
+
):
|
58
|
+
"""
|
59
|
+
total_table: column應為 <時間>_<單位>
|
60
|
+
對只有單層column的table,切出想要的index
|
61
|
+
"""
|
62
|
+
times = [
|
63
|
+
column.split("_")[0] for column in total_table.columns.unique()
|
64
|
+
] #取出timeIndex
|
65
|
+
try:
|
66
|
+
target_metrics = target_metric_dict[mode]
|
67
|
+
except KeyError as e:
|
68
|
+
return f"mode Error: Get mode should be {list(target_metric_dict.keys())} but get {mode}"
|
69
|
+
|
70
|
+
desired_order = [
|
71
|
+
f"{time}_{value_name}" for time in times
|
72
|
+
for value_name in target_metrics
|
73
|
+
]
|
74
|
+
|
75
|
+
if (target_index):
|
76
|
+
target_index = target_index.split()
|
77
|
+
sliced_table = total_table.loc[target_index, desired_order].T
|
78
|
+
|
79
|
+
return sliced_table.T
|
80
|
+
|
81
|
+
else:
|
82
|
+
return total_table.loc[:, desired_order]
|
83
|
+
|
84
|
+
@classmethod
|
85
|
+
def slice_multi_col_table(
|
86
|
+
cls,
|
87
|
+
total_table,
|
88
|
+
mode='value',
|
89
|
+
target_index=None, # None or Str, 要特別抓哪個index
|
90
|
+
):
|
91
|
+
"""
|
92
|
+
對Multicolumn的dataframe切出目標的index
|
93
|
+
"""
|
94
|
+
times = total_table.columns.get_level_values(0).unique()
|
95
|
+
try:
|
96
|
+
target_metrics = target_metric_dict[mode]
|
97
|
+
except KeyError as e:
|
98
|
+
return f"mode Error: Get mode should be {list(target_metric_dict.keys())} but get {mode}"
|
99
|
+
|
100
|
+
desired_order = [(time, value_name) for time in times
|
101
|
+
for value_name in target_metrics]
|
102
|
+
|
103
|
+
if (target_index):
|
104
|
+
target_index = target_index.split()
|
105
|
+
sliced_table = total_table.loc[
|
106
|
+
target_index, pd.IndexSlice[:,
|
107
|
+
target_metrics]][desired_order].T
|
108
|
+
if (mode == 'value_and_percentage'): # 因應balance_sheet 頁面的格式
|
109
|
+
return_table = sliced_table.T
|
110
|
+
return_table.columns = [
|
111
|
+
"_".join(flatten_indexs)
|
112
|
+
for flatten_indexs in return_table.columns.to_flat_index()
|
113
|
+
]
|
114
|
+
return return_table
|
115
|
+
|
116
|
+
sliced_table = sliced_table.reset_index()
|
117
|
+
sliced_table = sliced_table.pivot(index='level_1',
|
118
|
+
columns='level_0',
|
119
|
+
values=target_index).sort_index(
|
120
|
+
axis=1, level = 1,ascending = False
|
121
|
+
)
|
122
|
+
|
123
|
+
sliced_table.columns = sliced_table.columns.get_level_values(1)
|
124
|
+
sliced_table.columns.name = None
|
125
|
+
sliced_table.index.name = None
|
126
|
+
|
127
|
+
return sliced_table.reindex(target_metrics)
|
128
|
+
|
129
|
+
else:
|
130
|
+
return_table = total_table.loc[:, pd.IndexSlice[:,
|
131
|
+
target_metrics]][
|
132
|
+
desired_order]
|
133
|
+
return_table.columns = [
|
134
|
+
"_".join(flatten_indexs)
|
135
|
+
for flatten_indexs in return_table.columns.to_flat_index()
|
136
|
+
]
|
137
|
+
return return_table
|
138
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: neurostats-API
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.7
|
4
4
|
Summary: The service of NeuroStats website
|
5
5
|
Home-page: https://github.com/NeurowattStats/NeuroStats_API.git
|
6
6
|
Author: JasonWang@Neurowatt
|
@@ -30,10 +30,15 @@ Description-Content-Type: text/markdown
|
|
30
30
|
│ ├── fetchers
|
31
31
|
│ │ ├── __init__.py
|
32
32
|
│ │ ├── base.py
|
33
|
+
│ │ ├── balance_sheet.py
|
34
|
+
│ │ ├── cash_flow.py
|
33
35
|
│ │ ├── finance_overview.py
|
36
|
+
│ │ ├── profit_lose.py
|
34
37
|
│ │ ├── tech.py
|
35
|
-
│ │
|
38
|
+
│ │ ├── value_invest.py
|
36
39
|
│ ├── tools
|
40
|
+
│ │ ├── balance_sheet.yaml
|
41
|
+
│ │ ├── cash_flow_percentage.yaml
|
37
42
|
│ │ ├── finance_overview_dict.yaml
|
38
43
|
│ │ ├── profit_lose.yaml
|
39
44
|
│ │ └── seasonal_data_field_dict.txt
|
@@ -73,14 +78,15 @@ pip install neurostats-API
|
|
73
78
|
```Python
|
74
79
|
>>> import neurostats_API
|
75
80
|
>>> print(neurostats_API.__version__)
|
76
|
-
0.0.
|
81
|
+
0.0.6
|
77
82
|
```
|
78
83
|
|
79
84
|
### 得到最新一期的評價資料與歷年評價
|
80
85
|
``` Python
|
81
|
-
from neurostats_API.
|
82
|
-
|
83
|
-
|
86
|
+
from neurostats_API.utils import ValueFetcher, DBClient
|
87
|
+
db_client = DBClient("<連接的DB位置>").get_client()
|
88
|
+
ticker = "2330" # 換成tw50內任意ticker
|
89
|
+
fetcher = ValueFetcher(ticker, db_client)
|
84
90
|
data = stats_fetcher.query_data()
|
85
91
|
```
|
86
92
|
|
@@ -118,43 +124,42 @@ data = stats_fetcher.query_data()
|
|
118
124
|
|
119
125
|
### 回傳月營收表
|
120
126
|
``` Python
|
121
|
-
from neurostats_API.
|
127
|
+
from neurostats_API.fetchers import MonthRevenueFetcher, DBClient
|
122
128
|
db_client = DBClient("<連接的DB位置>").get_client()
|
123
|
-
ticker = 2330 # 換成tw50內任意ticker
|
124
|
-
fetcher =
|
125
|
-
data =
|
129
|
+
ticker = "2330" # 換成tw50內任意ticker
|
130
|
+
fetcher = MonthRevenueFetcherFetcher(ticker, db_client)
|
131
|
+
data = fetcher.query_data()
|
126
132
|
```
|
127
133
|
|
128
134
|
#### 回傳
|
129
135
|
```Python
|
130
136
|
{
|
131
|
-
"
|
132
|
-
"
|
133
|
-
"company_name":台積電
|
137
|
+
"ticker": "2330",
|
138
|
+
"company_name": "台積電",
|
134
139
|
"month_revenue":
|
135
|
-
|
136
|
-
|
137
|
-
2
|
138
|
-
...
|
139
|
-
|
140
|
-
|
140
|
+
year 2024 ... 2014
|
141
|
+
month ...
|
142
|
+
grand_total 2.025847e+09 ... NaN
|
143
|
+
12 NaN ... 69510190.0
|
144
|
+
... ... ... ...
|
145
|
+
2 1.816483e+08 ... 46829051.0
|
146
|
+
1 2.157851e+08 ... 51429993.0
|
141
147
|
|
142
148
|
"this_month_revenue_over_years":
|
143
|
-
|
144
|
-
revenue
|
145
|
-
|
146
|
-
...
|
147
|
-
YoY_5
|
148
|
-
YoY_10
|
149
|
-
|
149
|
+
year 2024 ... 2015
|
150
|
+
revenue 2.518727e+08 ... 64514083.0
|
151
|
+
revenue_increment_ratio 3.960000e+01 ... -13.8
|
152
|
+
... ... ... ...
|
153
|
+
YoY_5 1.465200e+02 ... NaN
|
154
|
+
YoY_10 NaN ... NaN
|
150
155
|
|
151
156
|
"grand_total_over_years":
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
...
|
156
|
-
|
157
|
-
|
157
|
+
year 2024 ... 2015
|
158
|
+
grand_total 2.025847e+09 ... 6.399788e+08
|
159
|
+
grand_total_increment_ratio 3.187000e+01 ... 1.845000e+01
|
160
|
+
... ... ... ...
|
161
|
+
grand_total_YoY_5 1.691300e+02 ... NaN
|
162
|
+
grand_total_YoY_10 NaN ... NaN
|
158
163
|
|
159
164
|
|
160
165
|
}
|
@@ -171,7 +176,7 @@ YoY_10 None None ... None None
|
|
171
176
|
### 財務分析: 重要指標
|
172
177
|
對應https://ifa.ai/tw-stock/2330/finance-overview
|
173
178
|
```Python
|
174
|
-
from neurostats_API.
|
179
|
+
from neurostats_API.fetchers import FinanceOverviewFetcher, DBClient
|
175
180
|
db_client = DBClient("<連接的DB位置>").get_client()
|
176
181
|
ticker = "2330"
|
177
182
|
fetcher = FinanceOverviewFetcher(ticker = "2330", db_client = db_client)
|
@@ -194,6 +199,7 @@ markdown
|
|
194
199
|
複製程式碼
|
195
200
|
| 英文 | 中文 |
|
196
201
|
|-----------------------------------|-----------------------------|
|
202
|
+
|**財務概況**|
|
197
203
|
| revenue | 營業收入 |
|
198
204
|
| gross_profit | 營業毛利 |
|
199
205
|
| operating_income | 營業利益 |
|
@@ -201,6 +207,7 @@ markdown
|
|
201
207
|
| operating_cash_flow | 營業活動之現金流 |
|
202
208
|
| invest_cash_flow | 投資活動之淨現金流 |
|
203
209
|
| financing_cash_flow | 籌資活動之淨現金流 |
|
210
|
+
|**每股財務狀況**|
|
204
211
|
| revenue_per_share | 每股營收 |
|
205
212
|
| gross_per_share | 每股營業毛利 |
|
206
213
|
| operating_income_per_share | 每股營業利益 |
|
@@ -209,6 +216,7 @@ markdown
|
|
209
216
|
| fcf_per_share | 每股自由現金流 |
|
210
217
|
| debt_to_operating_cash_flow | 每股有息負債 |
|
211
218
|
| equity | 每股淨值 |
|
219
|
+
|**獲利能力**|
|
212
220
|
| roa | 資產報酬率 |
|
213
221
|
| roe | 股東權益報酬率 |
|
214
222
|
| gross_over_asset | 營業毛利÷總資產 |
|
@@ -217,10 +225,12 @@ markdown
|
|
217
225
|
| operation_profit_rate | 營業利益率 |
|
218
226
|
| net_income_rate | 淨利率 |
|
219
227
|
| operating_cash_flow_profit_rate | 營業現金流利潤率 |
|
228
|
+
|**成長動能**|
|
220
229
|
| revenue_YoY | 營收年成長率 |
|
221
230
|
| gross_prof_YoY | 營業毛利年成長率 |
|
222
231
|
| operating_income_YoY | 營業利益年成長率 |
|
223
232
|
| net_income_YoY | 淨利年成長率 |
|
233
|
+
|**營運指標**|
|
224
234
|
| dso | 應收帳款收現天數 |
|
225
235
|
| account_receive_over_revenue | 應收帳款佔營收比率 |
|
226
236
|
| dio | 平均售貨天數 |
|
@@ -229,6 +239,7 @@ markdown
|
|
229
239
|
| cash_of_conversion_cycle | 現金循環週期 |
|
230
240
|
| asset_turnover | 總資產週轉率 |
|
231
241
|
| applcation_turnover | 不動產、廠房及設備週轉率 |
|
242
|
+
|**財務韌性**|
|
232
243
|
| current_ratio | 流動比率 |
|
233
244
|
| quick_ratio | 速動比率 |
|
234
245
|
| debt_to_equity_ratio | 負債權益比率 |
|
@@ -237,6 +248,7 @@ markdown
|
|
237
248
|
| debt_to_operating_cash_flow | 有息負債÷營業活動現金流 |
|
238
249
|
| debt_to_free_cash_flow | 有息負債÷自由現金流 |
|
239
250
|
| cash_flow_ratio | 現金流量比率 |
|
251
|
+
|**資產負債表**|
|
240
252
|
| current_assets | 流動資產 |
|
241
253
|
| current_liabilities | 流動負債 |
|
242
254
|
| non_current_assets | 非流動資產 |
|
@@ -248,18 +260,19 @@ markdown
|
|
248
260
|
#### 以下數值未在回傳資料中,待資料庫更新
|
249
261
|
|英文|中文|
|
250
262
|
|---|----|
|
251
|
-
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
263
|
+
|**成長動能**|
|
264
|
+
| operating_cash_flow_YoY | 營業現金流年成長率 |
|
265
|
+
| fcf_YoY | 自由現金流年成長率 |
|
266
|
+
| operating_cash_flow_per_share_YoY | 每股營業現金流年成長率 |
|
267
|
+
| fcf_per_share_YoY | 每股自由現金流年成長率 |
|
255
268
|
|
256
269
|
### 損益表
|
257
270
|
```Python
|
258
|
-
from neurostats_API.
|
271
|
+
from neurostats_API.fetchers import ProfitLoseFetcher, DBClient
|
259
272
|
db_client = DBClient("<連接的DB位置>").get_client()
|
260
|
-
fetcher =
|
261
|
-
ticker = 2330 # 換成tw50內任意ticker
|
262
|
-
data = fetcher.
|
273
|
+
fetcher = ProfitLoseFetcher(db_client)
|
274
|
+
ticker = "2330" # 換成tw50內任意ticker
|
275
|
+
data = fetcher.query_data()
|
263
276
|
```
|
264
277
|
|
265
278
|
#### 回傳
|
@@ -272,83 +285,85 @@ data = fetcher.get_profit_lose(ticker)
|
|
272
285
|
"profit_lose": #損益表,
|
273
286
|
"grand_total_profit_lose": #今年度累計損益表,
|
274
287
|
# 營業收入
|
275
|
-
"revenue":
|
276
|
-
"grand_total_revenue":
|
288
|
+
"revenue": # 營收成長率
|
289
|
+
"grand_total_revenue": # 營收累計成場濾
|
277
290
|
# 毛利
|
278
|
-
"gross_profit":
|
279
|
-
"grand_total_gross_profit":
|
280
|
-
"gross_profit_percentage":
|
281
|
-
"grand_total_gross_profit_percentage"
|
291
|
+
"gross_profit": # 毛利成長率
|
292
|
+
"grand_total_gross_profit": # 累計毛利成長率
|
293
|
+
"gross_profit_percentage": # 毛利率
|
294
|
+
"grand_total_gross_profit_percentage" # 累計毛利率
|
282
295
|
# 營利
|
283
|
-
"operating_income":
|
284
|
-
"grand_total_operating_income":
|
285
|
-
"operating_income_percentage":
|
286
|
-
"grand_total_operating_income_percentage":
|
296
|
+
"operating_income": # 營利成長率
|
297
|
+
"grand_total_operating_income": # 累計營利成長率
|
298
|
+
"operating_income_percentage": # 營利率
|
299
|
+
"grand_total_operating_income_percentage": # 累計營利率
|
287
300
|
# 稅前淨利
|
288
|
-
"net_income_before_tax":
|
289
|
-
"grand_total_net_income_before_tax":
|
290
|
-
"net_income_before_tax_percentage":
|
291
|
-
"grand_total_net_income_before_tax_percentage":
|
301
|
+
"net_income_before_tax": # 稅前淨利成長率
|
302
|
+
"grand_total_net_income_before_tax": # 累計稅前淨利成長率
|
303
|
+
"net_income_before_tax_percentage": # 稅前淨利率
|
304
|
+
"grand_total_net_income_before_tax_percentage": # 累計稅前淨利率
|
292
305
|
# 本期淨利
|
293
|
-
"net_income":
|
294
|
-
"grand_total_net_income":
|
295
|
-
"net_income_percentage":
|
296
|
-
"grand_total_income_percentage":
|
306
|
+
"net_income": # 本期淨利成長率
|
307
|
+
"grand_total_net_income": # 累計本期淨利成長率
|
308
|
+
"net_income_percentage": # 本期淨利率
|
309
|
+
"grand_total_income_percentage": # 累計本期淨利率
|
297
310
|
# EPS
|
298
|
-
"EPS":
|
299
|
-
"EPS_growth":
|
300
|
-
"grand_total_EPS":
|
301
|
-
"grand_total_EPS_growth":
|
311
|
+
"EPS": # EPS
|
312
|
+
"EPS_growth": # EPS成長率
|
313
|
+
"grand_total_EPS": # 累計EPS
|
314
|
+
"grand_total_EPS_growth": # 累計EPS成長率
|
302
315
|
}
|
303
316
|
```
|
304
317
|
|
305
318
|
### 資產負債表
|
306
319
|
``` Python
|
307
|
-
from neurostats_API.
|
320
|
+
from neurostats_API.fetchers import BalanceSheetFetcher, DBClient
|
308
321
|
db_client = DBClient("<連接的DB位置>").get_client()
|
309
|
-
|
310
|
-
|
311
|
-
|
322
|
+
ticker = "2330" # 換成tw50內任意ticker
|
323
|
+
fetcher = BalanceSheetFetcher(ticker, db_client)
|
324
|
+
|
325
|
+
stats_fetcher.query_data()
|
312
326
|
```
|
313
327
|
|
314
328
|
#### 回傳
|
315
329
|
```Python
|
316
330
|
{
|
317
331
|
"ticker": "2330"
|
318
|
-
"company_name":
|
332
|
+
"company_name":"台積電"
|
319
333
|
"balance_sheet":
|
320
|
-
|
321
|
-
流動資產
|
322
|
-
現金及約當現金
|
323
|
-
...
|
324
|
-
|
325
|
-
|
334
|
+
2024Q2_value ... 2018Q2_percentage
|
335
|
+
流動資產 NaN ... NaN
|
336
|
+
現金及約當現金 1.799127e+09 ... 30.79
|
337
|
+
... ... ... ...
|
338
|
+
避險之衍生金融負債-流動 NaN ... 0.00
|
339
|
+
負債準備-流動 NaN ... 0.00
|
326
340
|
|
327
341
|
"total_asset":
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
342
|
+
2024Q2_value ... 2018Q2_percentage
|
343
|
+
資產總額 5.982364e+09 ... 100.00
|
344
|
+
負債總額 2.162216e+09 ... 27.41
|
345
|
+
權益總額 3.820148e+09 ... 72.59
|
346
|
+
|
332
347
|
|
333
348
|
"current_asset":
|
334
|
-
|
335
|
-
|
349
|
+
2024Q2_value ... 2018Q2_percentage
|
350
|
+
流動資產合計 2.591658e+09 ... 46.7
|
336
351
|
|
337
352
|
"non_current_asset":
|
338
|
-
|
339
|
-
|
353
|
+
2024Q2_value ... 2018Q2_percentage
|
354
|
+
非流動資產合計 3.390706e+09 ... 53.3
|
340
355
|
|
341
356
|
"current_debt":
|
342
|
-
|
343
|
-
|
357
|
+
2024Q2_value ... 2018Q2_percentage
|
358
|
+
流動負債合計 1.048916e+09 ... 22.55
|
344
359
|
|
345
360
|
"non_current_debt":
|
346
|
-
|
347
|
-
|
361
|
+
2024Q2_value ... 2018Q2_percentage
|
362
|
+
非流動負債合計 1.113300e+09 ... 4.86
|
348
363
|
|
349
364
|
"equity":
|
350
|
-
|
351
|
-
|
365
|
+
2024Q2_value ... 2018Q2_percentage
|
366
|
+
權益總額 3.820148e+09 ... 72.59
|
352
367
|
|
353
368
|
}
|
354
369
|
```
|
@@ -373,68 +388,39 @@ stats_fetcher.get_cash_flow(ticker)
|
|
373
388
|
#### 回傳
|
374
389
|
```Python
|
375
390
|
{
|
376
|
-
"ticker":2330
|
377
|
-
"company_name"
|
391
|
+
"ticker": "2330"
|
392
|
+
"company_name": "台積電"
|
378
393
|
"cash_flow":
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
2018Q2_value 2018Q2_percentage ... 2024Q2_value \
|
410
|
-
投資活動之現金流量 NaN NaN ... NaN
|
411
|
-
取得透過其他綜合損益按公允價值衡量之金融資產 -47523622.0 0.355889 ... -43780180.0
|
412
|
-
... ... ... ... ...
|
413
|
-
其他投資活動 -149104.0 0.001117 ... 7956680.0
|
414
|
-
投資活動之淨現金流入(流出) -133534789.0 1.000000 ... -357414321.0
|
415
|
-
|
416
|
-
2024Q2_percentage
|
417
|
-
投資活動之現金流量 NaN
|
418
|
-
取得透過其他綜合損益按公允價值衡量之金融資產 0.122491
|
419
|
-
... ...
|
420
|
-
其他投資活動 -0.022262
|
421
|
-
投資活動之淨現金流入(流出) 1.000000
|
422
|
-
|
423
|
-
"CASHF":
|
424
|
-
2018Q2_value 2018Q2_percentage ... 2024Q2_value \
|
425
|
-
籌資活動之現金流量 NaN NaN ... NaN
|
426
|
-
短期借款減少 -33743725.0 0.387977 ... NaN
|
427
|
-
... ... ... ... ...
|
428
|
-
存出保證金增加 NaN NaN ... -122271.0
|
429
|
-
收取之股利 NaN NaN ... 895503.0
|
430
|
-
|
431
|
-
2024Q2_percentage
|
432
|
-
籌資活動之現金流量 NaN
|
433
|
-
短期借款減少 NaN
|
434
|
-
... ...
|
435
|
-
存出保證金增加 0.000755
|
436
|
-
收取之股利 -0.005530
|
437
|
-
|
394
|
+
2023Q3_value ... 2018Q3_percentage
|
395
|
+
營業活動之現金流量-間接法 NaN ... NaN
|
396
|
+
繼續營業單位稅前淨利(淨損) 700890335.0 ... 0.744778
|
397
|
+
... ... ... ...
|
398
|
+
以成本衡量之金融資產減資退回股款 NaN ... NaN
|
399
|
+
除列避險之金融負債∕避險 之衍生金融負債 NaN ... -0.000770
|
400
|
+
|
401
|
+
"CASHO":
|
402
|
+
2023Q3_value ... 2018Q3_percentage
|
403
|
+
營業活動之現金流量-間接法 NaN ... NaN
|
404
|
+
繼續營業單位稅前淨利(淨損) 700890335.0 ... 0.744778
|
405
|
+
... ... ... ...
|
406
|
+
持有供交易之金融資產(增加)減少 NaN ... 0.001664
|
407
|
+
負債準備增加(減少) NaN ... NaN
|
408
|
+
|
409
|
+
"CASHI":
|
410
|
+
2023Q3_value ... 2018Q3_percentage
|
411
|
+
投資活動之現金流量 NaN ... NaN
|
412
|
+
取得透過其他綜合損益按公允價值衡量之金融資產 -54832622.0 ... 0.367413
|
413
|
+
... ... ... ...
|
414
|
+
持有至到期日金融資產到期還本 NaN ... NaN
|
415
|
+
取得以成本衡量之金融資產 NaN ... NaN
|
416
|
+
|
417
|
+
"CASHF":
|
418
|
+
2023Q3_value ... 2018Q3_percentage
|
419
|
+
籌資活動之現金流量 NaN ... NaN
|
420
|
+
短期借款減少 0.0 ... NaN
|
421
|
+
... ... ... ...
|
422
|
+
以成本衡量之金融資產減資退回股款 NaN ... NaN
|
423
|
+
除列避險之金融負債∕避險 之衍生金融負債 NaN ... -0.00077
|
438
424
|
}
|
439
425
|
```
|
440
426
|
- `'ticker'`: 股票代碼
|
@@ -447,44 +433,6 @@ stats_fetcher.get_cash_flow(ticker)
|
|
447
433
|
> 大部分資料缺失是因為尚未計算,僅先填上已經有的資料
|
448
434
|
|
449
435
|
|
450
|
-
|
451
|
-
|
452
|
-
## cli 範例輸入
|
453
|
-
```
|
454
|
-
python ./cli.py --ticker 1101
|
455
|
-
```
|
456
|
-
|
457
|
-
### cli 輸出
|
458
|
-
```Python
|
459
|
-
_id
|
460
|
-
ObjectId('67219e046104872ef7490cd3')
|
461
|
-
ticker
|
462
|
-
'1101'
|
463
|
-
company_name
|
464
|
-
'台泥'
|
465
|
-
yearly_data
|
466
|
-
year P_E P_FCF P_B P_S EV_OPI EV_EBIT EV_EBITDA EV_S
|
467
|
-
0 107 9.78 66.346637 1.07 1.963814 16.061211 14.807325 32.858903 3.685025
|
468
|
-
1 108 10.76 23.532308 1.35 3.296749 21.995948 19.877169 44.395187 5.338454
|
469
|
-
2 109 10.29 -26.134468 1.32 4.282560 26.353871 23.417022 46.269197 6.908155
|
470
|
-
3 110 14.08 22.345215 1.50 5.558267 42.034804 32.290621 77.139298 7.973839
|
471
|
-
4 111 28.04 -63.248928 1.16 4.595606 -136332.740038 149.169022 -756.781156 7.324556
|
472
|
-
5 112 29.53 -18.313377 1.15 5.301801 98.225453 65.598234 321.991608 8.582981
|
473
|
-
6 過去4季 NaN -24.929987 NaN 4.300817 83.102921 55.788996 -1073.037084 7.436656
|
474
|
-
daily_data
|
475
|
-
{ 'EV_EBIT': 55.78899626851681,
|
476
|
-
'EV_EBITDA': -1073.037084015388,
|
477
|
-
'EV_OPI': 83.10292101832388,
|
478
|
-
'EV_S': 7.436656083243897,
|
479
|
-
'P_B': None,
|
480
|
-
'P_E': None,
|
481
|
-
'P_FCF': -24.92998660989962,
|
482
|
-
'P_S': 4.300817175744059,
|
483
|
-
'close': 32.150001525878906,
|
484
|
-
}
|
485
|
-
```
|
486
|
-
> 這裡有Nan是因為本益比與P/B等資料沒有爬到最新的時間
|
487
|
-
|
488
436
|
## TODO
|
489
437
|
- 將utils/fetcher.py中的功能切分到fetchers資料夾中
|
490
438
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
neurostats_API/__init__.py,sha256=3Kn8sHWnxjlagph2LmftcF8JLlcMlmQIbU5t_jzgK3w,19
|
2
|
+
neurostats_API/cli.py,sha256=UJSWLIw03P24p-gkBb6JSEI5dW5U12UvLf1L8HjQD-o,873
|
3
|
+
neurostats_API/main.py,sha256=QcsfmWivg2Dnqw3MTJWiI0QvEiRs0VuH-BjwQHFCv00,677
|
4
|
+
neurostats_API/fetchers/__init__.py,sha256=U_OMG-mLpsVKYnCBrW2OjFuCzvPeVQ__7A676vGzztY,313
|
5
|
+
neurostats_API/fetchers/balance_sheet.py,sha256=FPsVobaNzFOxpXCo1Ui_rPmlG1crTRj9ukqQ4J8aiJg,4268
|
6
|
+
neurostats_API/fetchers/base.py,sha256=NW2SFzrimyAIrdJx1LVmTazelyZOAtcj54kJKHc4Vaw,1662
|
7
|
+
neurostats_API/fetchers/cash_flow.py,sha256=muVnteEEyeFPapGqgBOoHa8PAieEI796rHPNi5otOMY,7009
|
8
|
+
neurostats_API/fetchers/finance_overview.py,sha256=t5QlTM0bL3fkrqlyMn8-8GB6YgMLsofH9NRI8PfPRxE,18447
|
9
|
+
neurostats_API/fetchers/month_revenue.py,sha256=RNA7ROl2vm8Xbib3k50p_1shsHDVSKIbHkyNiRa8yMw,3182
|
10
|
+
neurostats_API/fetchers/profit_lose.py,sha256=ffEVNo7-fvtnAq2_gj-Ga55TGW7pPd6WhruOZH8NGYM,4463
|
11
|
+
neurostats_API/fetchers/tech.py,sha256=wH1kkqiETQhF0HAhk-UIiucnZ3EiL85Q-yMWCcVOiFM,11395
|
12
|
+
neurostats_API/fetchers/value_invest.py,sha256=tg8yELbVnTFTEclrwgXnCRW377KkcoLiP-Gk2pyM-9Y,2886
|
13
|
+
neurostats_API/tools/balance_sheet.yaml,sha256=dKTMbsYR9EFp48WAzmm_ISHMiJQLyE0V-XWS_gkxmr0,541
|
14
|
+
neurostats_API/tools/cash_flow_percentage.yaml,sha256=fk2Z4eb1JjGFvP134eJatHacB7BgTkBenhDJr83w8RE,1345
|
15
|
+
neurostats_API/tools/finance_overview_dict.yaml,sha256=Vvf8bv23NwJP8Yyw8DPS8c0_jjT_Wctnnz51SHS4AeI,2335
|
16
|
+
neurostats_API/tools/profit_lose.yaml,sha256=qHBnqG7fR4Pxc_c3n4raL-3l7o5RnABLz9YGOXoaGiA,2086
|
17
|
+
neurostats_API/tools/seasonal_data_field_dict.txt,sha256=KlIIdTTdbvUd9TSDE9-gpzk2jt2ck_LdisX8cnrWMD4,7869
|
18
|
+
neurostats_API/utils/__init__.py,sha256=FTYKRFzW2XVXdnSHXnS3mQQaHlKF9xGqrMsgZZ2kroc,142
|
19
|
+
neurostats_API/utils/data_process.py,sha256=rRKf2H0X2J-tDXDreErcz3Y3TGb8_0Q6GKe0izRjnmA,4942
|
20
|
+
neurostats_API/utils/datetime.py,sha256=I9CIgZdE5OMzUciOS5wvapOVEIrXG_0Qb6iDKfIod6c,574
|
21
|
+
neurostats_API/utils/db_client.py,sha256=OYe6yazcR4Aa6jYmy47JrryUeh2NnKGqY2K_lSZe6i8,455
|
22
|
+
neurostats_API/utils/fetcher.py,sha256=VbrUhjA-GG5AyjPX2SHtFIbZM4dm3jo0RgZzuCbb_Io,40927
|
23
|
+
neurostats_API-0.0.7.dist-info/METADATA,sha256=Ajugxp0vnHoxdzriFfmLhTt32ckq2VnIiIO_eRU2QDo,18241
|
24
|
+
neurostats_API-0.0.7.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
|
25
|
+
neurostats_API-0.0.7.dist-info/top_level.txt,sha256=nSlQPMG0VtXivJyedp4Bkf86EOy2TpW10VGxolXrqnU,15
|
26
|
+
neurostats_API-0.0.7.dist-info/RECORD,,
|
@@ -1,23 +0,0 @@
|
|
1
|
-
neurostats_API/__init__.py,sha256=zzMTjJY407ibU6_ATOPO8KibRVB3tyW9yO0tRYzjTqw,19
|
2
|
-
neurostats_API/cli.py,sha256=UJSWLIw03P24p-gkBb6JSEI5dW5U12UvLf1L8HjQD-o,873
|
3
|
-
neurostats_API/main.py,sha256=QcsfmWivg2Dnqw3MTJWiI0QvEiRs0VuH-BjwQHFCv00,677
|
4
|
-
neurostats_API/fetchers/__init__.py,sha256=k-pPWen3gQNr6d6DPFEXP1Q6SPC6TGIuIFf8w6r75YQ,137
|
5
|
-
neurostats_API/fetchers/balance_sheet.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
neurostats_API/fetchers/base.py,sha256=NW2SFzrimyAIrdJx1LVmTazelyZOAtcj54kJKHc4Vaw,1662
|
7
|
-
neurostats_API/fetchers/finance_overview.py,sha256=_w5OzFQpzC7eL_S5iMtgrIhx5gcov9gKzc6XzFutEFU,18309
|
8
|
-
neurostats_API/fetchers/month_revenue.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
-
neurostats_API/fetchers/profit_lose.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
neurostats_API/fetchers/tech.py,sha256=wH1kkqiETQhF0HAhk-UIiucnZ3EiL85Q-yMWCcVOiFM,11395
|
11
|
-
neurostats_API/fetchers/value_invest.py,sha256=tg8yELbVnTFTEclrwgXnCRW377KkcoLiP-Gk2pyM-9Y,2886
|
12
|
-
neurostats_API/tools/finance_overview_dict.yaml,sha256=Vvf8bv23NwJP8Yyw8DPS8c0_jjT_Wctnnz51SHS4AeI,2335
|
13
|
-
neurostats_API/tools/profit_lose.yaml,sha256=f8balMTcK9elMW0k1PtbZ_6kEobTQ51fcBzqpbMObkk,2086
|
14
|
-
neurostats_API/tools/seasonal_data_field_dict.txt,sha256=KlIIdTTdbvUd9TSDE9-gpzk2jt2ck_LdisX8cnrWMD4,7869
|
15
|
-
neurostats_API/utils/__init__.py,sha256=FTYKRFzW2XVXdnSHXnS3mQQaHlKF9xGqrMsgZZ2kroc,142
|
16
|
-
neurostats_API/utils/data_process.py,sha256=AeDWS9eHlHRqzfDKph-14GXERtHLSMKijsIrzZ0pPPo,595
|
17
|
-
neurostats_API/utils/datetime.py,sha256=I9CIgZdE5OMzUciOS5wvapOVEIrXG_0Qb6iDKfIod6c,574
|
18
|
-
neurostats_API/utils/db_client.py,sha256=OYe6yazcR4Aa6jYmy47JrryUeh2NnKGqY2K_lSZe6i8,455
|
19
|
-
neurostats_API/utils/fetcher.py,sha256=VbrUhjA-GG5AyjPX2SHtFIbZM4dm3jo0RgZzuCbb_Io,40927
|
20
|
-
neurostats_API-0.0.6.dist-info/METADATA,sha256=cOomXaKrsCOt1V9ZRTuPgfLCzdWnw0fzWd7PkGKlo8U,20666
|
21
|
-
neurostats_API-0.0.6.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
|
22
|
-
neurostats_API-0.0.6.dist-info/top_level.txt,sha256=nSlQPMG0VtXivJyedp4Bkf86EOy2TpW10VGxolXrqnU,15
|
23
|
-
neurostats_API-0.0.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|