neurostats-API 0.0.6__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/__init__.py +4 -0
- neurostats_API/fetchers/balance_sheet.py +135 -0
- neurostats_API/fetchers/cash_flow.py +184 -0
- neurostats_API/fetchers/finance_overview.py +268 -119
- neurostats_API/fetchers/month_revenue.py +92 -0
- neurostats_API/fetchers/profit_lose.py +141 -0
- neurostats_API/tools/balance_sheet.yaml +26 -0
- neurostats_API/tools/cash_flow_percentage.yaml +39 -0
- neurostats_API/tools/finance_overview_dict.yaml +15 -8
- neurostats_API/tools/profit_lose.yaml +1 -1
- neurostats_API/tools/seasonal_data_field_dict.txt +1 -0
- neurostats_API/utils/data_process.py +149 -3
- {neurostats_API-0.0.6.dist-info → neurostats_API-0.0.8.dist-info}/METADATA +139 -190
- neurostats_API-0.0.8.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.8.dist-info}/WHEEL +0 -0
- {neurostats_API-0.0.6.dist-info → neurostats_API-0.0.8.dist-info}/top_level.txt +0 -0
@@ -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
|
|
@@ -82,8 +85,11 @@ class FinanceOverviewFetcher(StatsFetcher):
|
|
82
85
|
def query_data(self):
|
83
86
|
today = StatsDateTime.get_today()
|
84
87
|
|
85
|
-
|
88
|
+
year = today.year - 1 if (today.season == 1) else today.year
|
89
|
+
season = 4 if (today.season == 1) else today.season - 1
|
90
|
+
fetched_data = self.collect_data(year, season)
|
86
91
|
finance_dict = fetched_data['seasonal_data'][0]
|
92
|
+
FinanceOverviewProcessor.process_rate(finance_dict)
|
87
93
|
FinanceOverviewProcessor.process_all(finance_dict)
|
88
94
|
fetched_data['seasonal_data'] = finance_dict
|
89
95
|
return fetched_data
|
@@ -91,41 +97,38 @@ class FinanceOverviewFetcher(StatsFetcher):
|
|
91
97
|
|
92
98
|
class FinanceOverviewProcessor(StatsProcessor):
|
93
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
|
+
|
94
113
|
@classmethod
|
95
114
|
def process_all(cls, finance_dict):
|
96
115
|
methods = [
|
97
|
-
cls.cal_EBIT,
|
98
|
-
cls.
|
99
|
-
cls.
|
100
|
-
cls.
|
101
|
-
cls.
|
102
|
-
cls.
|
103
|
-
cls.
|
104
|
-
cls.
|
105
|
-
cls.
|
106
|
-
cls.cal_roe,
|
107
|
-
cls.cal_gross_over_asset,
|
108
|
-
cls.cal_roce,
|
109
|
-
cls.cal_gross_profit_marginal,
|
110
|
-
cls.cal_operation_profit_rate,
|
111
|
-
cls.cal_operating_cash_flow_profit_rate,
|
112
|
-
cls.cal_dso,
|
113
|
-
cls.cal_account_receive_over_revenue,
|
114
|
-
cls.cal_dpo,
|
115
|
-
cls.cal_inventories_cycle_ratio,
|
116
|
-
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,
|
117
125
|
cls.cal_inventories_revenue_ratio,
|
118
|
-
cls.cal_cash_of_conversion_cycle,
|
119
|
-
cls.
|
120
|
-
cls.
|
121
|
-
cls.
|
122
|
-
cls.cal_quick_ratio,
|
123
|
-
cls.cal_debt_to_equity_ratio,
|
124
|
-
cls.cal_net_debt_to_equity_ratio,
|
125
|
-
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,
|
126
130
|
cls.cal_debt_to_operating_cash_flow,
|
127
|
-
cls.cal_debt_to_free_cash_flow,
|
128
|
-
cls.cal_cash_flow_ratio
|
131
|
+
cls.cal_debt_to_free_cash_flow, cls.cal_cash_flow_ratio
|
129
132
|
]
|
130
133
|
|
131
134
|
for method in methods:
|
@@ -135,13 +138,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
135
138
|
def cal_EBIT(cls, finance_dict):
|
136
139
|
"""
|
137
140
|
計算EBIT
|
138
|
-
EBIT = 營業收入 - 營業成本 - 營業費用
|
141
|
+
EBIT = 營業收入 - 營業成本 - 營業費用 - 所得稅費用
|
139
142
|
"""
|
140
143
|
try:
|
141
|
-
finance_dict['
|
142
|
-
|
143
|
-
|
144
|
-
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:
|
145
148
|
finance_dict['EBIT'] = None
|
146
149
|
print(f"Error calculating EBIT: {e}")
|
147
150
|
|
@@ -152,12 +155,32 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
152
155
|
自由現金流 = 營業現金流 + 投資現金流
|
153
156
|
"""
|
154
157
|
try:
|
155
|
-
|
156
|
-
|
157
|
-
|
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:
|
158
162
|
finance_dict['fcf'] = None
|
159
163
|
print(f"Error calculating FCF: {e}")
|
160
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
|
+
|
161
184
|
@classmethod
|
162
185
|
def cal_share_outstanding(cls, finance_dict):
|
163
186
|
"""
|
@@ -167,7 +190,7 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
167
190
|
try:
|
168
191
|
finance_dict["share_outstanding"] = (finance_dict['net_income'] /
|
169
192
|
finance_dict['eps'])
|
170
|
-
except KeyError as e:
|
193
|
+
except (KeyError, ZeroDivisionError, TypeError) as e:
|
171
194
|
finance_dict['share_outstanding'] = None
|
172
195
|
print(f"share_outstanding failed because of {str(e)}")
|
173
196
|
|
@@ -178,9 +201,12 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
178
201
|
每股營收 = 營業收入 / 在外流通股數
|
179
202
|
"""
|
180
203
|
try:
|
181
|
-
finance_dict['
|
182
|
-
|
183
|
-
|
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:
|
184
210
|
finance_dict['revenue_per_share'] = None
|
185
211
|
print(f"revenue_per_share failed because of {str(e)}")
|
186
212
|
|
@@ -192,10 +218,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
192
218
|
"""
|
193
219
|
|
194
220
|
try:
|
195
|
-
finance_dict['
|
196
|
-
|
197
|
-
|
198
|
-
|
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:
|
199
228
|
finance_dict['gross_per_share'] = None
|
200
229
|
print(f"gross_per_share failed because of {str(e)}")
|
201
230
|
|
@@ -206,10 +235,12 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
206
235
|
每股營業利益= (當期營業利益)÷(當期在外流通股數)
|
207
236
|
"""
|
208
237
|
try:
|
209
|
-
finance_dict['
|
210
|
-
|
211
|
-
|
212
|
-
|
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:
|
213
244
|
finance_dict['operating_income_per_share'] = None
|
214
245
|
print(f"operating_income_per_share failed because of {str(e)}")
|
215
246
|
|
@@ -220,10 +251,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
220
251
|
= (當期營業現金流) ÷(當期在外流通股數)
|
221
252
|
"""
|
222
253
|
try:
|
223
|
-
|
254
|
+
operating_cash_flow_per_share = (
|
224
255
|
finance_dict["operating_cash_flow"] /
|
225
256
|
finance_dict['share_outstanding'])
|
226
|
-
|
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:
|
227
261
|
finance_dict['operating_cash_flow_per_share'] = None
|
228
262
|
print(f'operating_cash_flow_per_share because of {str(e)}')
|
229
263
|
|
@@ -234,9 +268,11 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
234
268
|
每股自由現金流 = (當期自由現金流) ÷(當期在外流通股數)
|
235
269
|
"""
|
236
270
|
try:
|
237
|
-
|
238
|
-
|
239
|
-
|
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:
|
240
276
|
finance_dict['fcf_per_share'] = None
|
241
277
|
print(f"fcf_per_share failed because of {str(e)}")
|
242
278
|
|
@@ -248,27 +284,35 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
248
284
|
計算資產報酬率(ROA)
|
249
285
|
ROA = [ 本期淨利 + 利息費用 × (1-有效稅率) ] ÷(資產總額)
|
250
286
|
"""
|
251
|
-
|
287
|
+
roa = (
|
252
288
|
finance_dict['net_income'] + finance_dict['interest'] +
|
253
289
|
(1 * 0.1) # 有效稅率需要改,這裡先設0.1
|
254
290
|
) / finance_dict['inventories']
|
255
291
|
|
292
|
+
finance_dict["roa"] = StatsProcessor.cal_percentage(roa)
|
293
|
+
|
256
294
|
@classmethod
|
257
295
|
def cal_roe(cls, finance_dict):
|
258
296
|
"""
|
259
297
|
計算股東權益報酬率(ROE)
|
260
298
|
ROE = (本期淨利) ÷(權益總額)
|
261
299
|
"""
|
262
|
-
|
263
|
-
|
300
|
+
roe = (finance_dict['net_income'] / finance_dict['equity'])
|
301
|
+
finance_dict['roe'] = StatsProcessor.cal_percentage(roe)
|
264
302
|
|
265
303
|
@classmethod
|
266
304
|
def cal_gross_over_asset(cls, finance_dict):
|
267
305
|
"""
|
268
306
|
計算營業毛利/總資產
|
269
307
|
"""
|
270
|
-
|
271
|
-
|
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)}")
|
272
316
|
|
273
317
|
@classmethod
|
274
318
|
def cal_roce(cls, finance_dict):
|
@@ -277,11 +321,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
277
321
|
ROCE = (稅前淨利+利息費用) / (資產總額-流動負債)
|
278
322
|
"""
|
279
323
|
try:
|
280
|
-
finance_dict['
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
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:
|
285
331
|
finance_dict['roce'] = None
|
286
332
|
print(f"ROCE failed because of {str(e)}")
|
287
333
|
|
@@ -292,8 +338,11 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
292
338
|
營業毛利率 = 營業毛利 ÷ 營業收入
|
293
339
|
"""
|
294
340
|
try:
|
295
|
-
finance_dict['
|
296
|
-
|
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)
|
297
346
|
except:
|
298
347
|
finance_dict['gross_profit_margin'] = None
|
299
348
|
print(f"gross_profit_margin failed because of {str(e)}")
|
@@ -305,10 +354,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
305
354
|
營業利益率 = ( 營業收入-營業成本-營業費用)÷ 營業收入
|
306
355
|
"""
|
307
356
|
try:
|
308
|
-
|
357
|
+
operation_profit_rate = (
|
309
358
|
finance_dict['revenue'] - finance_dict['operating_cost'] -
|
310
|
-
finance_dict['
|
311
|
-
|
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:
|
312
364
|
finance_dict["operation_profit_rate"] = None
|
313
365
|
print(f"operation_profit failed because of {str(e)}")
|
314
366
|
|
@@ -319,11 +371,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
319
371
|
營業現金流利潤率 = 營業活動現金流 ÷ 營業收入
|
320
372
|
"""
|
321
373
|
try:
|
322
|
-
|
374
|
+
operating_cash_flow_profit_rate = (
|
323
375
|
finance_dict["operating_cash_flow"] / finance_dict["revenue"])
|
324
|
-
|
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:
|
325
380
|
finance_dict["operating_cash_flow_profit_rate"] = None
|
326
|
-
|
327
381
|
print(
|
328
382
|
f"operating_cash_flow_profit_rate failed because of {str(e)}")
|
329
383
|
|
@@ -340,10 +394,16 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
340
394
|
def cal_dso(cls, finance_dict):
|
341
395
|
"""
|
342
396
|
計算應收帳款收現天數(DSO)
|
343
|
-
DSO = 365 × (
|
397
|
+
DSO = 365 × (應收帳款平均餘額 ÷ 營業收入)
|
344
398
|
"""
|
345
|
-
|
346
|
-
|
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)}")
|
347
407
|
|
348
408
|
@classmethod
|
349
409
|
def cal_account_receive_over_revenue(cls, finance_dict):
|
@@ -351,8 +411,11 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
351
411
|
計算應收帳款佔營收比率
|
352
412
|
= 應收帳款平均餘額 ÷ 營業收入
|
353
413
|
"""
|
354
|
-
|
355
|
-
|
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)
|
356
419
|
|
357
420
|
@classmethod
|
358
421
|
def cal_dpo(cls, finance_dict):
|
@@ -360,9 +423,15 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
360
423
|
計算應付帳款週轉天數
|
361
424
|
DPO = 365天 ÷ (銷貨成本÷平均應付帳款)
|
362
425
|
"""
|
363
|
-
|
364
|
-
|
365
|
-
|
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)}")
|
366
435
|
|
367
436
|
@classmethod
|
368
437
|
def cal_inventories_cycle_ratio(cls, finance_dict):
|
@@ -370,19 +439,32 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
370
439
|
計算存貨周轉率
|
371
440
|
= 銷貨成本 ÷ 存貨
|
372
441
|
"""
|
442
|
+
try:
|
443
|
+
inventories_cycle_ratio = (finance_dict['operating_cost'] /
|
444
|
+
finance_dict['inventories'])
|
373
445
|
|
374
|
-
|
375
|
-
|
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)}")
|
376
452
|
|
377
453
|
@classmethod
|
378
454
|
def cal_dio(cls, finance_dict):
|
379
455
|
"""
|
380
|
-
計算 存貨週轉天數
|
381
|
-
DIO = 365天
|
382
|
-
MUDA MUDA MUDA
|
456
|
+
計算 存貨週轉天數 or 平均售貨天數
|
457
|
+
DIO = 365天 * (存貨 ÷ 銷貨成本)
|
458
|
+
MUDA MUDA MUDA !!!
|
383
459
|
"""
|
384
|
-
|
385
|
-
|
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)}")
|
386
468
|
|
387
469
|
@classmethod
|
388
470
|
def cal_inventories_revenue_ratio(cls, finance_dict):
|
@@ -390,8 +472,16 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
390
472
|
計算存貨佔營收比率
|
391
473
|
存貨佔營收比= 存貨 ÷ 營業收入
|
392
474
|
"""
|
393
|
-
|
394
|
-
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)}")
|
395
485
|
|
396
486
|
@classmethod
|
397
487
|
def cal_cash_of_conversion_cycle(cls, finance_dict):
|
@@ -399,19 +489,42 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
399
489
|
計算現金循環週期
|
400
490
|
存貨週轉天數 + 應收帳款週轉天數 - 應付帳款週轉天數
|
401
491
|
"""
|
402
|
-
|
403
|
-
|
404
|
-
|
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
|
405
501
|
|
406
502
|
@classmethod
|
407
503
|
def cal_asset_turnover(cls, finance_dict):
|
408
|
-
|
409
|
-
|
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)
|
410
512
|
|
411
513
|
@classmethod
|
412
514
|
def cal_application_turnover(cls, finance_dict):
|
413
|
-
|
414
|
-
|
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
|
415
528
|
|
416
529
|
@classmethod
|
417
530
|
def cal_current_ratio(cls, finance_dict):
|
@@ -419,81 +532,117 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
419
532
|
計算流動比率 = 流動資產 / 流動負債
|
420
533
|
"""
|
421
534
|
try:
|
422
|
-
finance_dict['
|
423
|
-
|
535
|
+
current_ratio = (finance_dict['current_assets'] /
|
536
|
+
finance_dict['current_liabilities'])
|
537
|
+
finance_dict['current_ratio'] = StatsProcessor.cal_percentage(
|
538
|
+
current_ratio)
|
424
539
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
425
540
|
finance_dict['current_ratio'] = None
|
426
541
|
print(f"Error calculating current ratio: {e}")
|
427
542
|
|
428
543
|
@classmethod
|
429
544
|
def cal_quick_ratio(cls, finance_dict):
|
545
|
+
"""
|
546
|
+
速動比率
|
547
|
+
(流動資產 - 存貨) / 流動負債
|
548
|
+
"""
|
430
549
|
try:
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
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)
|
435
555
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
436
556
|
finance_dict['quick_ratio'] = None
|
437
557
|
print(f"Error calculating quick ratio: {e}")
|
438
558
|
|
439
559
|
@classmethod
|
440
560
|
def cal_debt_to_equity_ratio(cls, finance_dict):
|
561
|
+
"""
|
562
|
+
# 負債權益比率 = 總負債 / 股東權益
|
563
|
+
"""
|
441
564
|
try:
|
442
|
-
|
443
|
-
finance_dict['debt_to_equity_ratio'] = finance_dict[
|
565
|
+
debt_to_equity_ratio = finance_dict[
|
444
566
|
'total_liabilities'] / finance_dict['equity']
|
567
|
+
finance_dict[
|
568
|
+
'debt_to_equity_ratio'] = StatsProcessor.cal_percentage(
|
569
|
+
debt_to_equity_ratio)
|
445
570
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
446
571
|
finance_dict['debt_to_equity_ratio'] = None
|
447
572
|
print(f"Error calculating debt to equity ratio: {e}")
|
448
573
|
|
449
574
|
@classmethod
|
450
575
|
def cal_net_debt_to_equity_ratio(cls, finance_dict):
|
576
|
+
"""
|
577
|
+
# 淨負債權益比率 = (總負債 - 現金及約當現金) / 股東權益
|
578
|
+
"""
|
451
579
|
try:
|
452
|
-
|
453
|
-
finance_dict['net_debt_to_equity_ratio'] = (
|
580
|
+
net_debt_to_equity_ratio = (
|
454
581
|
finance_dict['total_liabilities'] -
|
455
582
|
finance_dict['cash_and_cash_equivalents']
|
456
583
|
) / finance_dict['equity']
|
584
|
+
finance_dict[
|
585
|
+
'net_debt_to_equity_ratio'] = StatsProcessor.cal_percentage(
|
586
|
+
net_debt_to_equity_ratio)
|
457
587
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
458
588
|
finance_dict['net_debt_to_equity_ratio'] = None
|
459
589
|
print(f"Error calculating net debt to equity ratio: {e}")
|
460
590
|
|
461
591
|
@classmethod
|
462
592
|
def cal_interest_coverage_ratio(cls, finance_dict):
|
593
|
+
"""
|
594
|
+
# 利息保障倍數 = EBIT / 利息費用
|
595
|
+
"""
|
463
596
|
try:
|
464
|
-
|
465
|
-
|
466
|
-
|
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="倍")
|
467
602
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
468
603
|
finance_dict['interest_coverage_ratio'] = None
|
469
604
|
print(f"Error calculating interest coverage ratio: {e}")
|
470
605
|
|
471
606
|
@classmethod
|
472
607
|
def cal_debt_to_operating_cash_flow(cls, finance_dict):
|
608
|
+
"""
|
609
|
+
有息負債 / 營業活動現金流
|
610
|
+
"""
|
473
611
|
try:
|
474
|
-
|
475
|
-
finance_dict['debt_to_operating_cash_flow'] = finance_dict[
|
612
|
+
debt_to_operating_cash_flow = finance_dict[
|
476
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)
|
477
617
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
478
618
|
finance_dict['debt_to_operating_cash_flow'] = None
|
479
619
|
print(f"Error calculating debt to operating cash flow: {e}")
|
480
620
|
|
481
621
|
@classmethod
|
482
622
|
def cal_debt_to_free_cash_flow(cls, finance_dict):
|
623
|
+
"""
|
624
|
+
# 有息負債 / 自由現金流
|
625
|
+
"""
|
483
626
|
try:
|
484
|
-
|
485
|
-
finance_dict['debt_to_free_cash_flow'] = finance_dict[
|
627
|
+
debt_to_free_cash_flow = finance_dict[
|
486
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)
|
487
632
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
488
633
|
finance_dict['debt_to_free_cash_flow'] = None
|
489
634
|
print(f"Error calculating debt to free cash flow: {e}")
|
490
635
|
|
491
636
|
@classmethod
|
492
637
|
def cal_cash_flow_ratio(cls, finance_dict):
|
638
|
+
"""
|
639
|
+
# 現金流量比率 = 營業活動現金流 / 流動負債
|
640
|
+
"""
|
493
641
|
try:
|
494
|
-
|
495
|
-
finance_dict['cash_flow_ratio'] = finance_dict[
|
642
|
+
cash_flow_ratio = finance_dict[
|
496
643
|
'operating_cash_flow'] / finance_dict['current_liabilities']
|
644
|
+
finance_dict['cash_flow_ratio'] = StatsProcessor.cal_percentage(
|
645
|
+
cash_flow_ratio)
|
497
646
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
498
647
|
finance_dict['cash_flow_ratio'] = None
|
499
648
|
print(f"Error calculating cash flow ratio: {e}")
|