neurostats-API 0.0.6__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/__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}")
|