neurostats-API 0.0.7__py3-none-any.whl → 0.0.8__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/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
|