neurostats-API 0.0.7__py3-none-any.whl → 0.0.8__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- neurostats_API/__init__.py +1 -1
- neurostats_API/fetchers/balance_sheet.py +44 -31
- neurostats_API/fetchers/cash_flow.py +7 -4
- neurostats_API/fetchers/finance_overview.py +266 -119
- neurostats_API/fetchers/profit_lose.py +11 -1
- neurostats_API/tools/finance_overview_dict.yaml +15 -8
- neurostats_API/tools/seasonal_data_field_dict.txt +1 -0
- neurostats_API/utils/data_process.py +28 -2
- {neurostats_API-0.0.7.dist-info → neurostats_API-0.0.8.dist-info}/METADATA +6 -5
- {neurostats_API-0.0.7.dist-info → neurostats_API-0.0.8.dist-info}/RECORD +12 -12
- {neurostats_API-0.0.7.dist-info → neurostats_API-0.0.8.dist-info}/WHEEL +0 -0
- {neurostats_API-0.0.7.dist-info → neurostats_API-0.0.8.dist-info}/top_level.txt +0 -0
neurostats_API/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__='0.0.
|
1
|
+
__version__='0.0.8'
|
@@ -1,10 +1,12 @@
|
|
1
1
|
from .base import StatsFetcher, StatsDateTime
|
2
2
|
import json
|
3
|
+
import numpy as np
|
3
4
|
import pandas as pd
|
4
5
|
from ..utils import StatsDateTime, StatsProcessor
|
5
6
|
import importlib.resources as pkg_resources
|
6
7
|
import yaml
|
7
8
|
|
9
|
+
|
8
10
|
class BalanceSheetFetcher(StatsFetcher):
|
9
11
|
"""
|
10
12
|
對應iFa.ai -> 財務分析 -> 資產負債表
|
@@ -13,7 +15,7 @@ class BalanceSheetFetcher(StatsFetcher):
|
|
13
15
|
def __init__(self, ticker, db_client):
|
14
16
|
super().__init__(ticker, db_client)
|
15
17
|
self.table_settings = StatsProcessor.load_yaml("balance_sheet.yaml")
|
16
|
-
|
18
|
+
|
17
19
|
def prepare_query(self, target_year, target_season):
|
18
20
|
pipeline = super().prepare_query()
|
19
21
|
|
@@ -24,36 +26,42 @@ class BalanceSheetFetcher(StatsFetcher):
|
|
24
26
|
}
|
25
27
|
|
26
28
|
pipeline.append({
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
29
|
+
"$project": {
|
30
|
+
"_id": 0,
|
31
|
+
"ticker": 1,
|
32
|
+
"company_name": 1,
|
33
|
+
"balance_sheets": {
|
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
|
+
}
|
41
45
|
}
|
46
|
+
},
|
47
|
+
"as": "target_season_data",
|
48
|
+
"in": {
|
49
|
+
"year":
|
50
|
+
"$$target_season_data.year",
|
51
|
+
"season":
|
52
|
+
"$$target_season_data.season",
|
53
|
+
"balance_sheet":
|
54
|
+
"$$target_season_data.balance_sheet"
|
42
55
|
}
|
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
56
|
}
|
50
|
-
}
|
51
|
-
|
52
|
-
|
57
|
+
},
|
58
|
+
"sortBy": {
|
59
|
+
"year": -1
|
60
|
+
} # 按 year 降序排序
|
61
|
+
}
|
53
62
|
}
|
54
63
|
}
|
55
|
-
}
|
56
|
-
})
|
64
|
+
})
|
57
65
|
|
58
66
|
return pipeline
|
59
67
|
|
@@ -93,20 +101,26 @@ class BalanceSheetFetcher(StatsFetcher):
|
|
93
101
|
|
94
102
|
time_index = f"{year}Q{target_season}"
|
95
103
|
|
96
|
-
|
104
|
+
# 蒐集整體的keys
|
97
105
|
index_names += list(data['balance_sheet'].keys())
|
98
106
|
balance_sheet = data['balance_sheet']
|
99
107
|
|
100
108
|
for index_name, value_dict in balance_sheet.items():
|
101
109
|
for item_name, item in value_dict.items():
|
102
|
-
try:
|
103
|
-
|
110
|
+
try: # table_dict[項目][(2020Q1, '%')]
|
111
|
+
if (item_name == 'percentage'):
|
112
|
+
if (isinstance(item, (float, int))):
|
113
|
+
item = np.round(item, 2)
|
114
|
+
if ("YoY" in item_name):
|
115
|
+
if (isinstance(item, (float, int))):
|
116
|
+
item = np.round(item * 100, 2)
|
117
|
+
table_dict[index_name][(time_index, item_name)] = item
|
104
118
|
|
105
119
|
except KeyError:
|
106
120
|
if (index_name not in table_dict.keys()):
|
107
121
|
table_dict[index_name] = dict()
|
108
122
|
|
109
|
-
table_dict[index_name][(time_index,item_name)] = item
|
123
|
+
table_dict[index_name][(time_index, item_name)] = item
|
110
124
|
|
111
125
|
total_table = pd.DataFrame.from_dict(table_dict, orient='index')
|
112
126
|
total_table.columns = pd.MultiIndex.from_tuples(total_table.columns)
|
@@ -118,5 +132,4 @@ class BalanceSheetFetcher(StatsFetcher):
|
|
118
132
|
target_index=setting['target_index']
|
119
133
|
if "target_index" in setting.keys() else None)
|
120
134
|
|
121
|
-
print(f"{name}: {return_dict[name].columns}")
|
122
135
|
return return_dict
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from .base import StatsFetcher, StatsDateTime
|
2
2
|
import json
|
3
|
+
import numpy as np
|
3
4
|
import pandas as pd
|
4
5
|
from ..utils import StatsDateTime, StatsProcessor
|
5
6
|
import importlib.resources as pkg_resources
|
@@ -127,8 +128,9 @@ class CashFlowFetcher(StatsFetcher):
|
|
127
128
|
'value']
|
128
129
|
if (value['value']):
|
129
130
|
table_dict[time_index][index_name][
|
130
|
-
'percentage'] =
|
131
|
-
|
131
|
+
'percentage'] = np.round(
|
132
|
+
(value['value'] / cash_flow[
|
133
|
+
main_cash_flow_name]['value']) * 100, 2)
|
132
134
|
else:
|
133
135
|
table_dict[time_index][index_name][
|
134
136
|
'percentage'] = None
|
@@ -141,8 +143,9 @@ class CashFlowFetcher(StatsFetcher):
|
|
141
143
|
'value']
|
142
144
|
if (value['value']):
|
143
145
|
table_dict[time_index][index_name][
|
144
|
-
'percentage'] =
|
145
|
-
|
146
|
+
'percentage'] = np.round(
|
147
|
+
(value['value'] / cash_flow[
|
148
|
+
main_cash_flow_name]['value']) * 100, 2)
|
146
149
|
else:
|
147
150
|
table_dict[time_index][index_name][
|
148
151
|
'percentage'] = None
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from .base import StatsFetcher, StatsDateTime
|
2
2
|
import json
|
3
|
+
import numpy as np
|
3
4
|
import pandas as pd
|
4
5
|
from ..utils import StatsDateTime, StatsProcessor
|
5
6
|
import importlib.resources as pkg_resources
|
@@ -14,8 +15,10 @@ class FinanceOverviewFetcher(StatsFetcher):
|
|
14
15
|
def __init__(self, ticker, db_client):
|
15
16
|
super().__init__(ticker, db_client)
|
16
17
|
|
17
|
-
self.target_fields = StatsProcessor.load_yaml(
|
18
|
-
|
18
|
+
self.target_fields = StatsProcessor.load_yaml(
|
19
|
+
"finance_overview_dict.yaml")
|
20
|
+
self.inverse_dict = StatsProcessor.load_txt(
|
21
|
+
"seasonal_data_field_dict.txt", json_load=True)
|
19
22
|
|
20
23
|
def prepare_query(self, target_year, target_season):
|
21
24
|
|
@@ -83,9 +86,10 @@ class FinanceOverviewFetcher(StatsFetcher):
|
|
83
86
|
today = StatsDateTime.get_today()
|
84
87
|
|
85
88
|
year = today.year - 1 if (today.season == 1) else today.year
|
86
|
-
season = 4 if (today.season == 1) else today.season -
|
89
|
+
season = 4 if (today.season == 1) else today.season - 1
|
87
90
|
fetched_data = self.collect_data(year, season)
|
88
91
|
finance_dict = fetched_data['seasonal_data'][0]
|
92
|
+
FinanceOverviewProcessor.process_rate(finance_dict)
|
89
93
|
FinanceOverviewProcessor.process_all(finance_dict)
|
90
94
|
fetched_data['seasonal_data'] = finance_dict
|
91
95
|
return fetched_data
|
@@ -93,41 +97,38 @@ class FinanceOverviewFetcher(StatsFetcher):
|
|
93
97
|
|
94
98
|
class FinanceOverviewProcessor(StatsProcessor):
|
95
99
|
|
100
|
+
@classmethod
|
101
|
+
def process_rate(cls, finance_dict):
|
102
|
+
for key in finance_dict:
|
103
|
+
if ('YoY' in key):
|
104
|
+
finance_dict[key] = StatsProcessor.cal_percentage(
|
105
|
+
finance_dict[key])
|
106
|
+
elif ("rate" in key or 'ratio' in key):
|
107
|
+
finance_dict[key] = StatsProcessor.cal_non_percentage(
|
108
|
+
finance_dict[key], to_str=True, postfix='%')
|
109
|
+
else:
|
110
|
+
finance_dict[key] = StatsProcessor.cal_non_percentage(
|
111
|
+
finance_dict[key])
|
112
|
+
|
96
113
|
@classmethod
|
97
114
|
def process_all(cls, finance_dict):
|
98
115
|
methods = [
|
99
|
-
cls.cal_EBIT,
|
100
|
-
cls.
|
101
|
-
cls.
|
102
|
-
cls.
|
103
|
-
cls.
|
104
|
-
cls.
|
105
|
-
cls.
|
106
|
-
cls.
|
107
|
-
cls.
|
108
|
-
cls.cal_roe,
|
109
|
-
cls.cal_gross_over_asset,
|
110
|
-
cls.cal_roce,
|
111
|
-
cls.cal_gross_profit_marginal,
|
112
|
-
cls.cal_operation_profit_rate,
|
113
|
-
cls.cal_operating_cash_flow_profit_rate,
|
114
|
-
cls.cal_dso,
|
115
|
-
cls.cal_account_receive_over_revenue,
|
116
|
-
cls.cal_dpo,
|
117
|
-
cls.cal_inventories_cycle_ratio,
|
118
|
-
cls.cal_dio,
|
116
|
+
cls.cal_EBIT, cls.cal_share_outstanding, cls.cal_fcf,
|
117
|
+
cls.cal_interest_bearing_debt, cls.cal_revenue_per_share,
|
118
|
+
cls.cal_gross_per_share, cls.cal_operating_income_per_share,
|
119
|
+
cls.cal_operating_cash_flow_per_share, cls.fcf_per_share,
|
120
|
+
cls.cal_roa, cls.cal_roe, cls.cal_gross_over_asset, cls.cal_roce,
|
121
|
+
cls.cal_gross_profit_marginal, cls.cal_operation_profit_rate,
|
122
|
+
cls.cal_operating_cash_flow_profit_rate, cls.cal_dso,
|
123
|
+
cls.cal_account_receive_over_revenue, cls.cal_dpo,
|
124
|
+
cls.cal_inventories_cycle_ratio, cls.cal_dio,
|
119
125
|
cls.cal_inventories_revenue_ratio,
|
120
|
-
cls.cal_cash_of_conversion_cycle,
|
121
|
-
cls.
|
122
|
-
cls.
|
123
|
-
cls.
|
124
|
-
cls.cal_quick_ratio,
|
125
|
-
cls.cal_debt_to_equity_ratio,
|
126
|
-
cls.cal_net_debt_to_equity_ratio,
|
127
|
-
cls.cal_interest_coverage_ratio,
|
126
|
+
cls.cal_cash_of_conversion_cycle, cls.cal_asset_turnover,
|
127
|
+
cls.cal_application_turnover, cls.cal_current_ratio,
|
128
|
+
cls.cal_quick_ratio, cls.cal_debt_to_equity_ratio,
|
129
|
+
cls.cal_net_debt_to_equity_ratio, cls.cal_interest_coverage_ratio,
|
128
130
|
cls.cal_debt_to_operating_cash_flow,
|
129
|
-
cls.cal_debt_to_free_cash_flow,
|
130
|
-
cls.cal_cash_flow_ratio
|
131
|
+
cls.cal_debt_to_free_cash_flow, cls.cal_cash_flow_ratio
|
131
132
|
]
|
132
133
|
|
133
134
|
for method in methods:
|
@@ -137,13 +138,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
137
138
|
def cal_EBIT(cls, finance_dict):
|
138
139
|
"""
|
139
140
|
計算EBIT
|
140
|
-
EBIT = 營業收入 - 營業成本 - 營業費用
|
141
|
+
EBIT = 營業收入 - 營業成本 - 營業費用 - 所得稅費用
|
141
142
|
"""
|
142
143
|
try:
|
143
|
-
finance_dict['
|
144
|
-
|
145
|
-
|
146
|
-
except (KeyError, TypeError) as e:
|
144
|
+
EBIT = (finance_dict['revenue'] - finance_dict['operating_cost'] -
|
145
|
+
finance_dict['operating_expenses'] - finance_dict['tax_fee'])
|
146
|
+
finance_dict['EBIT'] = StatsProcessor.cal_non_percentage(EBIT)
|
147
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
147
148
|
finance_dict['EBIT'] = None
|
148
149
|
print(f"Error calculating EBIT: {e}")
|
149
150
|
|
@@ -154,12 +155,32 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
154
155
|
自由現金流 = 營業現金流 + 投資現金流
|
155
156
|
"""
|
156
157
|
try:
|
157
|
-
|
158
|
-
|
159
|
-
|
158
|
+
fcf = (finance_dict["operating_cash_flow"] +
|
159
|
+
finance_dict["financing_cash_flow"])
|
160
|
+
finance_dict["fcf"] = StatsProcessor.cal_non_percentage(fcf)
|
161
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
160
162
|
finance_dict['fcf'] = None
|
161
163
|
print(f"Error calculating FCF: {e}")
|
162
164
|
|
165
|
+
@classmethod
|
166
|
+
def cal_interest_bearing_debt(cls, finance_dict):
|
167
|
+
"""
|
168
|
+
計算有息負債
|
169
|
+
短期借款+長期借款
|
170
|
+
"""
|
171
|
+
finance_dict['interest_bearing_debt'] = 0.0
|
172
|
+
|
173
|
+
try:
|
174
|
+
finance_dict['interest_bearing_debt'] += finance_dict[
|
175
|
+
'short_term_liabilities']
|
176
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
177
|
+
finance_dict['interest_bearing_debt'] += 0.0
|
178
|
+
try:
|
179
|
+
finance_dict['interest_bearing_debt'] += finance_dict[
|
180
|
+
'long_term_liabilities']
|
181
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
182
|
+
finance_dict['interest_bearing_debt'] += 0.0
|
183
|
+
|
163
184
|
@classmethod
|
164
185
|
def cal_share_outstanding(cls, finance_dict):
|
165
186
|
"""
|
@@ -169,7 +190,7 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
169
190
|
try:
|
170
191
|
finance_dict["share_outstanding"] = (finance_dict['net_income'] /
|
171
192
|
finance_dict['eps'])
|
172
|
-
except KeyError as e:
|
193
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
173
194
|
finance_dict['share_outstanding'] = None
|
174
195
|
print(f"share_outstanding failed because of {str(e)}")
|
175
196
|
|
@@ -180,9 +201,12 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
180
201
|
每股營收 = 營業收入 / 在外流通股數
|
181
202
|
"""
|
182
203
|
try:
|
183
|
-
finance_dict['
|
184
|
-
|
185
|
-
|
204
|
+
revenue_per_share = (finance_dict['revenue'] /
|
205
|
+
finance_dict['share_outstanding'])
|
206
|
+
finance_dict[
|
207
|
+
'revenue_per_share'] = StatsProcessor.cal_non_percentage(
|
208
|
+
revenue_per_share, False)
|
209
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
186
210
|
finance_dict['revenue_per_share'] = None
|
187
211
|
print(f"revenue_per_share failed because of {str(e)}")
|
188
212
|
|
@@ -194,10 +218,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
194
218
|
"""
|
195
219
|
|
196
220
|
try:
|
197
|
-
finance_dict['
|
198
|
-
|
199
|
-
|
200
|
-
|
221
|
+
gross_per_share = (finance_dict['gross_profit'] /
|
222
|
+
finance_dict['share_outstanding'])
|
223
|
+
finance_dict[
|
224
|
+
'gross_per_share'] = StatsProcessor.cal_non_percentage(
|
225
|
+
gross_per_share, False)
|
226
|
+
|
227
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
201
228
|
finance_dict['gross_per_share'] = None
|
202
229
|
print(f"gross_per_share failed because of {str(e)}")
|
203
230
|
|
@@ -208,10 +235,12 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
208
235
|
每股營業利益= (當期營業利益)÷(當期在外流通股數)
|
209
236
|
"""
|
210
237
|
try:
|
211
|
-
finance_dict['
|
212
|
-
|
213
|
-
|
214
|
-
|
238
|
+
operating_income_per_share = (finance_dict['operating_income'] /
|
239
|
+
finance_dict['share_outstanding'])
|
240
|
+
finance_dict[
|
241
|
+
'operating_income_per_share'] = StatsProcessor.cal_non_percentage(
|
242
|
+
operating_income_per_share)
|
243
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
215
244
|
finance_dict['operating_income_per_share'] = None
|
216
245
|
print(f"operating_income_per_share failed because of {str(e)}")
|
217
246
|
|
@@ -222,10 +251,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
222
251
|
= (當期營業現金流) ÷(當期在外流通股數)
|
223
252
|
"""
|
224
253
|
try:
|
225
|
-
|
254
|
+
operating_cash_flow_per_share = (
|
226
255
|
finance_dict["operating_cash_flow"] /
|
227
256
|
finance_dict['share_outstanding'])
|
228
|
-
|
257
|
+
finance_dict[
|
258
|
+
"operating_cash_flow_per_share"] = StatsProcessor.cal_non_percentage(
|
259
|
+
operating_cash_flow_per_share)
|
260
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
229
261
|
finance_dict['operating_cash_flow_per_share'] = None
|
230
262
|
print(f'operating_cash_flow_per_share because of {str(e)}')
|
231
263
|
|
@@ -236,9 +268,11 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
236
268
|
每股自由現金流 = (當期自由現金流) ÷(當期在外流通股數)
|
237
269
|
"""
|
238
270
|
try:
|
239
|
-
|
240
|
-
|
241
|
-
|
271
|
+
fcf_per_share = (finance_dict['fcf'] /
|
272
|
+
finance_dict['share_outstanding'])
|
273
|
+
finance_dict['fcf_per_share'] = StatsProcessor.cal_non_percentage(
|
274
|
+
fcf_per_share)
|
275
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
242
276
|
finance_dict['fcf_per_share'] = None
|
243
277
|
print(f"fcf_per_share failed because of {str(e)}")
|
244
278
|
|
@@ -250,27 +284,35 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
250
284
|
計算資產報酬率(ROA)
|
251
285
|
ROA = [ 本期淨利 + 利息費用 × (1-有效稅率) ] ÷(資產總額)
|
252
286
|
"""
|
253
|
-
|
287
|
+
roa = (
|
254
288
|
finance_dict['net_income'] + finance_dict['interest'] +
|
255
289
|
(1 * 0.1) # 有效稅率需要改,這裡先設0.1
|
256
290
|
) / finance_dict['inventories']
|
257
291
|
|
292
|
+
finance_dict["roa"] = StatsProcessor.cal_percentage(roa)
|
293
|
+
|
258
294
|
@classmethod
|
259
295
|
def cal_roe(cls, finance_dict):
|
260
296
|
"""
|
261
297
|
計算股東權益報酬率(ROE)
|
262
298
|
ROE = (本期淨利) ÷(權益總額)
|
263
299
|
"""
|
264
|
-
|
265
|
-
|
300
|
+
roe = (finance_dict['net_income'] / finance_dict['equity'])
|
301
|
+
finance_dict['roe'] = StatsProcessor.cal_percentage(roe)
|
266
302
|
|
267
303
|
@classmethod
|
268
304
|
def cal_gross_over_asset(cls, finance_dict):
|
269
305
|
"""
|
270
306
|
計算營業毛利/總資產
|
271
307
|
"""
|
272
|
-
|
273
|
-
|
308
|
+
try:
|
309
|
+
gross_over_asset = (finance_dict['gross_profit'] /
|
310
|
+
finance_dict['total_asset'])
|
311
|
+
finance_dict['gross_over_asset'] = StatsProcessor.cal_percentage(
|
312
|
+
gross_over_asset)
|
313
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
314
|
+
finance_dict['gross_over_asset'] = None
|
315
|
+
print(f"營業毛利/總資產 failed because of {str(e)}")
|
274
316
|
|
275
317
|
@classmethod
|
276
318
|
def cal_roce(cls, finance_dict):
|
@@ -279,11 +321,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
279
321
|
ROCE = (稅前淨利+利息費用) / (資產總額-流動負債)
|
280
322
|
"""
|
281
323
|
try:
|
282
|
-
finance_dict['
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
324
|
+
roce = ((finance_dict['net_income_before_tax'] +
|
325
|
+
finance_dict['interest']) /
|
326
|
+
(finance_dict['total_asset'] -
|
327
|
+
finance_dict['current_liabilities']))
|
328
|
+
finance_dict['roce'] = StatsProcessor.cal_percentage(roce)
|
329
|
+
|
330
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
287
331
|
finance_dict['roce'] = None
|
288
332
|
print(f"ROCE failed because of {str(e)}")
|
289
333
|
|
@@ -294,8 +338,11 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
294
338
|
營業毛利率 = 營業毛利 ÷ 營業收入
|
295
339
|
"""
|
296
340
|
try:
|
297
|
-
finance_dict['
|
298
|
-
|
341
|
+
gross_profit_margin = (finance_dict['gross_profit'] /
|
342
|
+
finance_dict['revenue'])
|
343
|
+
finance_dict[
|
344
|
+
'gross_profit_margin'] = StatsProcessor.cal_percentage(
|
345
|
+
gross_profit_margin)
|
299
346
|
except:
|
300
347
|
finance_dict['gross_profit_margin'] = None
|
301
348
|
print(f"gross_profit_margin failed because of {str(e)}")
|
@@ -307,10 +354,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
307
354
|
營業利益率 = ( 營業收入-營業成本-營業費用)÷ 營業收入
|
308
355
|
"""
|
309
356
|
try:
|
310
|
-
|
357
|
+
operation_profit_rate = (
|
311
358
|
finance_dict['revenue'] - finance_dict['operating_cost'] -
|
312
|
-
finance_dict['
|
313
|
-
|
359
|
+
finance_dict['operating_expenses']) / finance_dict['revenue']
|
360
|
+
finance_dict[
|
361
|
+
"operation_profit_rate"] = StatsProcessor.cal_percentage(
|
362
|
+
operation_profit_rate)
|
363
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
314
364
|
finance_dict["operation_profit_rate"] = None
|
315
365
|
print(f"operation_profit failed because of {str(e)}")
|
316
366
|
|
@@ -321,11 +371,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
321
371
|
營業現金流利潤率 = 營業活動現金流 ÷ 營業收入
|
322
372
|
"""
|
323
373
|
try:
|
324
|
-
|
374
|
+
operating_cash_flow_profit_rate = (
|
325
375
|
finance_dict["operating_cash_flow"] / finance_dict["revenue"])
|
326
|
-
|
376
|
+
finance_dict[
|
377
|
+
"operating_cash_flow_profit_rate"] = StatsProcessor.cal_percentage(
|
378
|
+
operating_cash_flow_profit_rate)
|
379
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
327
380
|
finance_dict["operating_cash_flow_profit_rate"] = None
|
328
|
-
|
329
381
|
print(
|
330
382
|
f"operating_cash_flow_profit_rate failed because of {str(e)}")
|
331
383
|
|
@@ -342,10 +394,16 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
342
394
|
def cal_dso(cls, finance_dict):
|
343
395
|
"""
|
344
396
|
計算應收帳款收現天數(DSO)
|
345
|
-
DSO = 365 × (
|
397
|
+
DSO = 365 × (應收帳款平均餘額 ÷ 營業收入)
|
346
398
|
"""
|
347
|
-
|
348
|
-
|
399
|
+
try:
|
400
|
+
dso = (365 *
|
401
|
+
(finance_dict['account_pay'] / finance_dict['revenue']))
|
402
|
+
finance_dict['dso'] = StatsProcessor.cal_non_percentage(
|
403
|
+
dso, to_str=True, postfix="日")
|
404
|
+
except:
|
405
|
+
finance_dict['dso'] = None
|
406
|
+
print(f"Error calculating 應收帳款收現天數 because of {str(e)}")
|
349
407
|
|
350
408
|
@classmethod
|
351
409
|
def cal_account_receive_over_revenue(cls, finance_dict):
|
@@ -353,8 +411,11 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
353
411
|
計算應收帳款佔營收比率
|
354
412
|
= 應收帳款平均餘額 ÷ 營業收入
|
355
413
|
"""
|
356
|
-
|
357
|
-
|
414
|
+
account_receive_over_revenue = (finance_dict['account_receive'] /
|
415
|
+
finance_dict['revenue'])
|
416
|
+
finance_dict[
|
417
|
+
"account_receive_over_revenue"] = StatsProcessor.cal_percentage(
|
418
|
+
account_receive_over_revenue)
|
358
419
|
|
359
420
|
@classmethod
|
360
421
|
def cal_dpo(cls, finance_dict):
|
@@ -362,9 +423,15 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
362
423
|
計算應付帳款週轉天數
|
363
424
|
DPO = 365天 ÷ (銷貨成本÷平均應付帳款)
|
364
425
|
"""
|
365
|
-
|
366
|
-
|
367
|
-
|
426
|
+
try:
|
427
|
+
dpo = (
|
428
|
+
365 *
|
429
|
+
(finance_dict['account_pay'] / finance_dict['operating_cost']))
|
430
|
+
finance_dict["dpo"] = StatsProcessor.cal_non_percentage(
|
431
|
+
dpo, to_str=True, postfix="日")
|
432
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
433
|
+
finance_dict["dpo"] = None
|
434
|
+
print(f"應付帳款週轉天數 failed because of {str(e)}")
|
368
435
|
|
369
436
|
@classmethod
|
370
437
|
def cal_inventories_cycle_ratio(cls, finance_dict):
|
@@ -372,19 +439,32 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
372
439
|
計算存貨周轉率
|
373
440
|
= 銷貨成本 ÷ 存貨
|
374
441
|
"""
|
442
|
+
try:
|
443
|
+
inventories_cycle_ratio = (finance_dict['operating_cost'] /
|
444
|
+
finance_dict['inventories'])
|
375
445
|
|
376
|
-
|
377
|
-
|
446
|
+
finance_dict[
|
447
|
+
"inventories_cycle_ratio"] = StatsProcessor.cal_percentage(
|
448
|
+
inventories_cycle_ratio)
|
449
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
450
|
+
finance_dict["inventories_cycle_ratio"] = None
|
451
|
+
print(f"Error calculating 存貨周轉率 because of {str(e)}")
|
378
452
|
|
379
453
|
@classmethod
|
380
454
|
def cal_dio(cls, finance_dict):
|
381
455
|
"""
|
382
|
-
計算 存貨週轉天數
|
383
|
-
DIO = 365天
|
384
|
-
MUDA MUDA MUDA
|
456
|
+
計算 存貨週轉天數 or 平均售貨天數
|
457
|
+
DIO = 365天 * (存貨 ÷ 銷貨成本)
|
458
|
+
MUDA MUDA MUDA !!!
|
385
459
|
"""
|
386
|
-
|
387
|
-
|
460
|
+
try:
|
461
|
+
dio = 365 * (finance_dict["inventories"] /
|
462
|
+
finance_dict["operating_cost"])
|
463
|
+
finance_dict["dio"] = StatsProcessor.cal_non_percentage(
|
464
|
+
dio, to_str=True, postfix="日")
|
465
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
466
|
+
finance_dict["dio"] = None
|
467
|
+
print(f"Error calculating 存貨週轉天數 because of {str(e)}")
|
388
468
|
|
389
469
|
@classmethod
|
390
470
|
def cal_inventories_revenue_ratio(cls, finance_dict):
|
@@ -392,8 +472,16 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
392
472
|
計算存貨佔營收比率
|
393
473
|
存貨佔營收比= 存貨 ÷ 營業收入
|
394
474
|
"""
|
395
|
-
|
396
|
-
finance_dict['inventories'] /
|
475
|
+
try:
|
476
|
+
inventories_revenue_ratio = (finance_dict['inventories'] /
|
477
|
+
finance_dict['revenue'])
|
478
|
+
|
479
|
+
finance_dict[
|
480
|
+
"inventories_revenue_ratio"] = StatsProcessor.cal_percentage(
|
481
|
+
inventories_revenue_ratio)
|
482
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
483
|
+
finance_dict["inventories_revenue_ratio"] = None
|
484
|
+
print(f"Error calculating 存貨佔營收比率 because of {str(e)}")
|
397
485
|
|
398
486
|
@classmethod
|
399
487
|
def cal_cash_of_conversion_cycle(cls, finance_dict):
|
@@ -401,19 +489,42 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
401
489
|
計算現金循環週期
|
402
490
|
存貨週轉天數 + 應收帳款週轉天數 - 應付帳款週轉天數
|
403
491
|
"""
|
404
|
-
|
405
|
-
|
406
|
-
|
492
|
+
try:
|
493
|
+
cash_of_conversion_cycle = (finance_dict["dio"] +
|
494
|
+
finance_dict["dso"] -
|
495
|
+
finance_dict['dpo'])
|
496
|
+
finance_dict[
|
497
|
+
"cash_of_conversion_cycle"] = StatsProcessor.cal_non_percentage(
|
498
|
+
cash_of_conversion_cycle, to_str=True, postfix="日")
|
499
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
500
|
+
finance_dict["cash_of_conversion_cycle"] = None
|
407
501
|
|
408
502
|
@classmethod
|
409
503
|
def cal_asset_turnover(cls, finance_dict):
|
410
|
-
|
411
|
-
|
504
|
+
"""
|
505
|
+
計算資產周轉率
|
506
|
+
營業收入 ÷ 資產總額
|
507
|
+
"""
|
508
|
+
asset_turnover = (finance_dict["revenue"] /
|
509
|
+
finance_dict["inventories"])
|
510
|
+
finance_dict["asset_turnover"] = StatsProcessor.cal_percentage(
|
511
|
+
asset_turnover)
|
412
512
|
|
413
513
|
@classmethod
|
414
514
|
def cal_application_turnover(cls, finance_dict):
|
415
|
-
|
416
|
-
|
515
|
+
"""
|
516
|
+
不動產、廠房及設備週轉率
|
517
|
+
營業收入 ÷ 不動產、廠房與設備平均餘額
|
518
|
+
"""
|
519
|
+
try:
|
520
|
+
applcation_turnover = (finance_dict['revenue'] /
|
521
|
+
finance_dict["application"])
|
522
|
+
finance_dict[
|
523
|
+
'applcation_turnover'] = StatsProcessor.cal_percentage(
|
524
|
+
applcation_turnover)
|
525
|
+
|
526
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
527
|
+
finance_dict['application_turnover'] = None
|
417
528
|
|
418
529
|
@classmethod
|
419
530
|
def cal_current_ratio(cls, finance_dict):
|
@@ -421,81 +532,117 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
421
532
|
計算流動比率 = 流動資產 / 流動負債
|
422
533
|
"""
|
423
534
|
try:
|
424
|
-
finance_dict['
|
425
|
-
|
535
|
+
current_ratio = (finance_dict['current_assets'] /
|
536
|
+
finance_dict['current_liabilities'])
|
537
|
+
finance_dict['current_ratio'] = StatsProcessor.cal_percentage(
|
538
|
+
current_ratio)
|
426
539
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
427
540
|
finance_dict['current_ratio'] = None
|
428
541
|
print(f"Error calculating current ratio: {e}")
|
429
542
|
|
430
543
|
@classmethod
|
431
544
|
def cal_quick_ratio(cls, finance_dict):
|
545
|
+
"""
|
546
|
+
速動比率
|
547
|
+
(流動資產 - 存貨) / 流動負債
|
548
|
+
"""
|
432
549
|
try:
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
550
|
+
quick_ratio = (finance_dict['current_assets'] -
|
551
|
+
finance_dict['inventories']
|
552
|
+
) / finance_dict['current_liabilities']
|
553
|
+
finance_dict['quick_ratio'] = StatsProcessor.cal_percentage(
|
554
|
+
quick_ratio)
|
437
555
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
438
556
|
finance_dict['quick_ratio'] = None
|
439
557
|
print(f"Error calculating quick ratio: {e}")
|
440
558
|
|
441
559
|
@classmethod
|
442
560
|
def cal_debt_to_equity_ratio(cls, finance_dict):
|
561
|
+
"""
|
562
|
+
# 負債權益比率 = 總負債 / 股東權益
|
563
|
+
"""
|
443
564
|
try:
|
444
|
-
|
445
|
-
finance_dict['debt_to_equity_ratio'] = finance_dict[
|
565
|
+
debt_to_equity_ratio = finance_dict[
|
446
566
|
'total_liabilities'] / finance_dict['equity']
|
567
|
+
finance_dict[
|
568
|
+
'debt_to_equity_ratio'] = StatsProcessor.cal_percentage(
|
569
|
+
debt_to_equity_ratio)
|
447
570
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
448
571
|
finance_dict['debt_to_equity_ratio'] = None
|
449
572
|
print(f"Error calculating debt to equity ratio: {e}")
|
450
573
|
|
451
574
|
@classmethod
|
452
575
|
def cal_net_debt_to_equity_ratio(cls, finance_dict):
|
576
|
+
"""
|
577
|
+
# 淨負債權益比率 = (總負債 - 現金及約當現金) / 股東權益
|
578
|
+
"""
|
453
579
|
try:
|
454
|
-
|
455
|
-
finance_dict['net_debt_to_equity_ratio'] = (
|
580
|
+
net_debt_to_equity_ratio = (
|
456
581
|
finance_dict['total_liabilities'] -
|
457
582
|
finance_dict['cash_and_cash_equivalents']
|
458
583
|
) / finance_dict['equity']
|
584
|
+
finance_dict[
|
585
|
+
'net_debt_to_equity_ratio'] = StatsProcessor.cal_percentage(
|
586
|
+
net_debt_to_equity_ratio)
|
459
587
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
460
588
|
finance_dict['net_debt_to_equity_ratio'] = None
|
461
589
|
print(f"Error calculating net debt to equity ratio: {e}")
|
462
590
|
|
463
591
|
@classmethod
|
464
592
|
def cal_interest_coverage_ratio(cls, finance_dict):
|
593
|
+
"""
|
594
|
+
# 利息保障倍數 = EBIT / 利息費用
|
595
|
+
"""
|
465
596
|
try:
|
466
|
-
|
467
|
-
|
468
|
-
|
597
|
+
interest_coverage_ratio = finance_dict['EBIT'] / finance_dict[
|
598
|
+
'interest_expense']
|
599
|
+
finance_dict[
|
600
|
+
'interest_coverage_ratio'] = StatsProcessor.cal_non_percentage(
|
601
|
+
interest_coverage_ratio, to_str=True, postfix="倍")
|
469
602
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
470
603
|
finance_dict['interest_coverage_ratio'] = None
|
471
604
|
print(f"Error calculating interest coverage ratio: {e}")
|
472
605
|
|
473
606
|
@classmethod
|
474
607
|
def cal_debt_to_operating_cash_flow(cls, finance_dict):
|
608
|
+
"""
|
609
|
+
有息負債 / 營業活動現金流
|
610
|
+
"""
|
475
611
|
try:
|
476
|
-
|
477
|
-
finance_dict['debt_to_operating_cash_flow'] = finance_dict[
|
612
|
+
debt_to_operating_cash_flow = finance_dict[
|
478
613
|
'interest_bearing_debt'] / finance_dict['operating_cash_flow']
|
614
|
+
finance_dict[
|
615
|
+
'debt_to_operating_cash_flow'] = StatsProcessor.cal_percentage(
|
616
|
+
debt_to_operating_cash_flow)
|
479
617
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
480
618
|
finance_dict['debt_to_operating_cash_flow'] = None
|
481
619
|
print(f"Error calculating debt to operating cash flow: {e}")
|
482
620
|
|
483
621
|
@classmethod
|
484
622
|
def cal_debt_to_free_cash_flow(cls, finance_dict):
|
623
|
+
"""
|
624
|
+
# 有息負債 / 自由現金流
|
625
|
+
"""
|
485
626
|
try:
|
486
|
-
|
487
|
-
finance_dict['debt_to_free_cash_flow'] = finance_dict[
|
627
|
+
debt_to_free_cash_flow = finance_dict[
|
488
628
|
'interest_bearing_debt'] / finance_dict['fcf']
|
629
|
+
finance_dict[
|
630
|
+
'debt_to_free_cash_flow'] = StatsProcessor.cal_percentage(
|
631
|
+
debt_to_free_cash_flow)
|
489
632
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
490
633
|
finance_dict['debt_to_free_cash_flow'] = None
|
491
634
|
print(f"Error calculating debt to free cash flow: {e}")
|
492
635
|
|
493
636
|
@classmethod
|
494
637
|
def cal_cash_flow_ratio(cls, finance_dict):
|
638
|
+
"""
|
639
|
+
# 現金流量比率 = 營業活動現金流 / 流動負債
|
640
|
+
"""
|
495
641
|
try:
|
496
|
-
|
497
|
-
finance_dict['cash_flow_ratio'] = finance_dict[
|
642
|
+
cash_flow_ratio = finance_dict[
|
498
643
|
'operating_cash_flow'] / finance_dict['current_liabilities']
|
644
|
+
finance_dict['cash_flow_ratio'] = StatsProcessor.cal_percentage(
|
645
|
+
cash_flow_ratio)
|
499
646
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
500
647
|
finance_dict['cash_flow_ratio'] = None
|
501
648
|
print(f"Error calculating cash flow ratio: {e}")
|
@@ -1,11 +1,13 @@
|
|
1
1
|
from .base import StatsFetcher, StatsDateTime
|
2
|
+
import importlib.resources as pkg_resources
|
2
3
|
import json
|
4
|
+
import numpy as np
|
3
5
|
import pandas as pd
|
4
6
|
from ..utils import StatsDateTime, StatsProcessor
|
5
|
-
import importlib.resources as pkg_resources
|
6
7
|
import yaml
|
7
8
|
|
8
9
|
|
10
|
+
|
9
11
|
class ProfitLoseFetcher(StatsFetcher):
|
10
12
|
"""
|
11
13
|
iFa.ai: 財務分析 -> 損益表
|
@@ -108,6 +110,12 @@ class ProfitLoseFetcher(StatsFetcher):
|
|
108
110
|
for index_name, value_dict in profit_lose.items():
|
109
111
|
# (2020Q1, 項目, 金額或%)
|
110
112
|
for item_name, item in value_dict.items():
|
113
|
+
if (item_name == 'percentage'):
|
114
|
+
if (isinstance(item, (float, int))):
|
115
|
+
item = np.round(item, 2)
|
116
|
+
if ('YoY' in item_name):
|
117
|
+
if (isinstance(item, (float, int))):
|
118
|
+
item = np.round(item * 100, 2)
|
111
119
|
try:
|
112
120
|
table_dict[index_name][(time_index, item_name)] = item
|
113
121
|
|
@@ -121,6 +129,8 @@ class ProfitLoseFetcher(StatsFetcher):
|
|
121
129
|
total_table = pd.DataFrame.from_dict(table_dict, orient='index')
|
122
130
|
total_table.columns = pd.MultiIndex.from_tuples(total_table.columns)
|
123
131
|
|
132
|
+
total_table = total_table.replace("N/A", None)
|
133
|
+
|
124
134
|
for name, setting in self.table_settings.items():
|
125
135
|
return_dict[name] = StatsProcessor.slice_multi_col_table(
|
126
136
|
total_table=total_table,
|
@@ -15,22 +15,22 @@ net_income:
|
|
15
15
|
field: 本期淨利(淨損)
|
16
16
|
value: value
|
17
17
|
|
18
|
+
tax_fee:
|
19
|
+
field: 所得稅費用(利益)合計
|
20
|
+
value: value
|
21
|
+
|
18
22
|
# TODO: 以下所爬到的資料都是累計的,Ifa有額外計算當季的變化量
|
19
23
|
operating_cash_flow:
|
20
24
|
field: 營業活動之淨現金流入(流出)
|
21
|
-
value:
|
25
|
+
value: single_season_value
|
22
26
|
|
23
27
|
invest_cash_flow:
|
24
28
|
field: 投資活動之淨現金流入(流出)
|
25
|
-
value:
|
29
|
+
value: single_season_value
|
26
30
|
|
27
31
|
financing_cash_flow:
|
28
32
|
field: 籌資活動之淨現金流入(流出)
|
29
|
-
value:
|
30
|
-
|
31
|
-
fcf:
|
32
|
-
field: 本期現金及約當現金增加(減少)數
|
33
|
-
value: value
|
33
|
+
value: single_season_value
|
34
34
|
# ^^^ 以上皆需要額外在DataBase處理
|
35
35
|
|
36
36
|
# 每股財務狀況
|
@@ -84,7 +84,7 @@ net_income_YoY:
|
|
84
84
|
|
85
85
|
operating_cash_flow_YoY:
|
86
86
|
field: 營業活動之淨現金流入(流出)
|
87
|
-
value:
|
87
|
+
value: single_season_YoY
|
88
88
|
|
89
89
|
# operating_cash_flow_per_share_YoY:
|
90
90
|
# field: 每股營業現金流年成長率
|
@@ -123,6 +123,13 @@ total_liabilities:
|
|
123
123
|
field: 負債總額
|
124
124
|
value: value
|
125
125
|
|
126
|
+
short_term_liabilities:
|
127
|
+
field: 短期借款
|
128
|
+
value: value
|
129
|
+
|
130
|
+
long_term_liabilities:
|
131
|
+
field: 長期借款
|
132
|
+
value: value
|
126
133
|
#
|
127
134
|
cash_and_cash_equivalents:
|
128
135
|
field: 現金及約當現金
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from importlib.resources import files
|
2
2
|
import json
|
3
|
+
import numpy as np
|
3
4
|
import pandas as pd
|
4
5
|
import yaml
|
5
6
|
|
@@ -117,8 +118,9 @@ class StatsProcessor:
|
|
117
118
|
sliced_table = sliced_table.pivot(index='level_1',
|
118
119
|
columns='level_0',
|
119
120
|
values=target_index).sort_index(
|
120
|
-
|
121
|
-
|
121
|
+
axis=1,
|
122
|
+
level=1,
|
123
|
+
ascending=False)
|
122
124
|
|
123
125
|
sliced_table.columns = sliced_table.columns.get_level_values(1)
|
124
126
|
sliced_table.columns.name = None
|
@@ -136,3 +138,27 @@ class StatsProcessor:
|
|
136
138
|
]
|
137
139
|
return return_table
|
138
140
|
|
141
|
+
@classmethod
|
142
|
+
def cal_percentage(cls, value, postfix="%"):
|
143
|
+
if (isinstance(value, (float, int))):
|
144
|
+
value = np.round(value * 100 , 2).item()
|
145
|
+
value = f"{value:.2f}{postfix}"
|
146
|
+
|
147
|
+
return value
|
148
|
+
|
149
|
+
else:
|
150
|
+
return value
|
151
|
+
|
152
|
+
@classmethod
|
153
|
+
def cal_non_percentage(cls, value, to_str=False, postfix="元"):
|
154
|
+
if (isinstance(value, (float, int))):
|
155
|
+
value = np.round(value, 2).item()
|
156
|
+
if (to_str):
|
157
|
+
value = f"{value:.2f}{postfix}"
|
158
|
+
return value
|
159
|
+
|
160
|
+
else:
|
161
|
+
return value
|
162
|
+
|
163
|
+
else:
|
164
|
+
return value
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: neurostats-API
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.8
|
4
4
|
Summary: The service of NeuroStats website
|
5
5
|
Home-page: https://github.com/NeurowattStats/NeuroStats_API.git
|
6
6
|
Author: JasonWang@Neurowatt
|
@@ -78,7 +78,7 @@ pip install neurostats-API
|
|
78
78
|
```Python
|
79
79
|
>>> import neurostats_API
|
80
80
|
>>> print(neurostats_API.__version__)
|
81
|
-
0.0.
|
81
|
+
0.0.8
|
82
82
|
```
|
83
83
|
|
84
84
|
### 得到最新一期的評價資料與歷年評價
|
@@ -379,11 +379,12 @@ stats_fetcher.query_data()
|
|
379
379
|
|
380
380
|
### 現金流量表
|
381
381
|
``` Python
|
382
|
-
from neurostats_API.
|
382
|
+
from neurostats_API.fetchers import CashFlowFetcher
|
383
383
|
db_client = DBClient("<連接的DB位置>").get_client()
|
384
|
-
fetcher = StatsFetcher(db_client)
|
385
384
|
ticker = 2330 # 換成tw50內任意ticker
|
386
|
-
|
385
|
+
fetcher = StatsFetcher(ticker, db_client)
|
386
|
+
|
387
|
+
stats_fetcher.query()
|
387
388
|
```
|
388
389
|
#### 回傳
|
389
390
|
```Python
|
@@ -1,26 +1,26 @@
|
|
1
|
-
neurostats_API/__init__.py,sha256=
|
1
|
+
neurostats_API/__init__.py,sha256=9_jSwg7P5SlFv0Ci2ZSYBcAbygp9XV2C8sryRO8tvko,19
|
2
2
|
neurostats_API/cli.py,sha256=UJSWLIw03P24p-gkBb6JSEI5dW5U12UvLf1L8HjQD-o,873
|
3
3
|
neurostats_API/main.py,sha256=QcsfmWivg2Dnqw3MTJWiI0QvEiRs0VuH-BjwQHFCv00,677
|
4
4
|
neurostats_API/fetchers/__init__.py,sha256=U_OMG-mLpsVKYnCBrW2OjFuCzvPeVQ__7A676vGzztY,313
|
5
|
-
neurostats_API/fetchers/balance_sheet.py,sha256=
|
5
|
+
neurostats_API/fetchers/balance_sheet.py,sha256=kOpk_83qeNgfhjF44UEmma8k6V6qTsIaFYiEcSVV20A,4910
|
6
6
|
neurostats_API/fetchers/base.py,sha256=NW2SFzrimyAIrdJx1LVmTazelyZOAtcj54kJKHc4Vaw,1662
|
7
|
-
neurostats_API/fetchers/cash_flow.py,sha256=
|
8
|
-
neurostats_API/fetchers/finance_overview.py,sha256
|
7
|
+
neurostats_API/fetchers/cash_flow.py,sha256=5xN5YPGb7i4slDYe_KI2ucL4kh733iC5LLOEmm4J8mM,7137
|
8
|
+
neurostats_API/fetchers/finance_overview.py,sha256=-cUb4wWr02xKhNCAXLuduhpvXsO0b14hJLqJqhagooY,25307
|
9
9
|
neurostats_API/fetchers/month_revenue.py,sha256=RNA7ROl2vm8Xbib3k50p_1shsHDVSKIbHkyNiRa8yMw,3182
|
10
|
-
neurostats_API/fetchers/profit_lose.py,sha256=
|
10
|
+
neurostats_API/fetchers/profit_lose.py,sha256=aCvcTbe1FjR3oi8QIDZg0c6G7-r0B-cCdfj6Rtlw0Jw,4870
|
11
11
|
neurostats_API/fetchers/tech.py,sha256=wH1kkqiETQhF0HAhk-UIiucnZ3EiL85Q-yMWCcVOiFM,11395
|
12
12
|
neurostats_API/fetchers/value_invest.py,sha256=tg8yELbVnTFTEclrwgXnCRW377KkcoLiP-Gk2pyM-9Y,2886
|
13
13
|
neurostats_API/tools/balance_sheet.yaml,sha256=dKTMbsYR9EFp48WAzmm_ISHMiJQLyE0V-XWS_gkxmr0,541
|
14
14
|
neurostats_API/tools/cash_flow_percentage.yaml,sha256=fk2Z4eb1JjGFvP134eJatHacB7BgTkBenhDJr83w8RE,1345
|
15
|
-
neurostats_API/tools/finance_overview_dict.yaml,sha256=
|
15
|
+
neurostats_API/tools/finance_overview_dict.yaml,sha256=URL1IFqO0j5uOwN3xETHriy_u9lYbLvdwghuznenP2Q,2500
|
16
16
|
neurostats_API/tools/profit_lose.yaml,sha256=qHBnqG7fR4Pxc_c3n4raL-3l7o5RnABLz9YGOXoaGiA,2086
|
17
|
-
neurostats_API/tools/seasonal_data_field_dict.txt,sha256=
|
17
|
+
neurostats_API/tools/seasonal_data_field_dict.txt,sha256=Za1fJR1yERbqrX8TgsS2kmMYMbaye43Gu_5ukUNBCNM,7904
|
18
18
|
neurostats_API/utils/__init__.py,sha256=FTYKRFzW2XVXdnSHXnS3mQQaHlKF9xGqrMsgZZ2kroc,142
|
19
|
-
neurostats_API/utils/data_process.py,sha256=
|
19
|
+
neurostats_API/utils/data_process.py,sha256=m1B4EhCNSzOMfTBDtYCjkQSjbDTAEFC6TNf3NNxV36k,5657
|
20
20
|
neurostats_API/utils/datetime.py,sha256=I9CIgZdE5OMzUciOS5wvapOVEIrXG_0Qb6iDKfIod6c,574
|
21
21
|
neurostats_API/utils/db_client.py,sha256=OYe6yazcR4Aa6jYmy47JrryUeh2NnKGqY2K_lSZe6i8,455
|
22
22
|
neurostats_API/utils/fetcher.py,sha256=VbrUhjA-GG5AyjPX2SHtFIbZM4dm3jo0RgZzuCbb_Io,40927
|
23
|
-
neurostats_API-0.0.
|
24
|
-
neurostats_API-0.0.
|
25
|
-
neurostats_API-0.0.
|
26
|
-
neurostats_API-0.0.
|
23
|
+
neurostats_API-0.0.8.dist-info/METADATA,sha256=SCspApNeq7b9pflJC30SaOVCdZtQjBIbh6QOps9HnGw,18232
|
24
|
+
neurostats_API-0.0.8.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
|
25
|
+
neurostats_API-0.0.8.dist-info/top_level.txt,sha256=nSlQPMG0VtXivJyedp4Bkf86EOy2TpW10VGxolXrqnU,15
|
26
|
+
neurostats_API-0.0.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|