neurostats-API 0.0.9__py3-none-any.whl → 0.0.11__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 +1 -0
- neurostats_API/fetchers/balance_sheet.py +19 -9
- neurostats_API/fetchers/cash_flow.py +8 -6
- neurostats_API/fetchers/finance_overview.py +95 -32
- neurostats_API/fetchers/institution.py +214 -0
- neurostats_API/fetchers/month_revenue.py +23 -7
- neurostats_API/fetchers/profit_lose.py +21 -9
- neurostats_API/tools/balance_sheet.yaml +15 -7
- neurostats_API/tools/finance_overview_dict.yaml +76 -34
- neurostats_API/tools/profit_lose.yaml +50 -22
- neurostats_API/tools/seasonal_data_field_dict.txt +16 -1
- neurostats_API/utils/data_process.py +13 -2
- {neurostats_API-0.0.9.dist-info → neurostats_API-0.0.11.dist-info}/METADATA +11 -4
- neurostats_API-0.0.11.dist-info/RECORD +27 -0
- neurostats_API-0.0.9.dist-info/RECORD +0 -26
- {neurostats_API-0.0.9.dist-info → neurostats_API-0.0.11.dist-info}/WHEEL +0 -0
- {neurostats_API-0.0.9.dist-info → neurostats_API-0.0.11.dist-info}/top_level.txt +0 -0
neurostats_API/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__='0.0.
|
1
|
+
__version__='0.0.11'
|
@@ -2,6 +2,7 @@ from .base import StatsDateTime, StatsFetcher
|
|
2
2
|
from .balance_sheet import BalanceSheetFetcher
|
3
3
|
from .cash_flow import CashFlowFetcher
|
4
4
|
from .finance_overview import FinanceOverviewFetcher
|
5
|
+
from .institution import InstitutionFetcher
|
5
6
|
from .month_revenue import MonthRevenueFetcher
|
6
7
|
from .profit_lose import ProfitLoseFetcher
|
7
8
|
from .value_invest import ValueFetcher
|
@@ -116,10 +116,13 @@ class BalanceSheetFetcher(StatsFetcher):
|
|
116
116
|
try: # table_dict[項目][(2020Q1, '%')]
|
117
117
|
if (item_name == 'percentage'):
|
118
118
|
if (isinstance(item, (float, int))):
|
119
|
-
item =
|
120
|
-
|
119
|
+
item = StatsProcessor.cal_non_percentage(item, to_str=True, postfix="%")
|
120
|
+
elif ("YoY" in item_name):
|
121
121
|
if (isinstance(item, (float, int))):
|
122
|
-
item =
|
122
|
+
item = StatsProcessor.cal_percentage(item)
|
123
|
+
else:
|
124
|
+
if (isinstance(item, (float, int))):
|
125
|
+
item = StatsProcessor.cal_non_percentage(item, postfix="千元")
|
123
126
|
table_dict[index_name][(time_index, item_name)] = item
|
124
127
|
|
125
128
|
except KeyError:
|
@@ -132,10 +135,17 @@ class BalanceSheetFetcher(StatsFetcher):
|
|
132
135
|
total_table.columns = pd.MultiIndex.from_tuples(total_table.columns)
|
133
136
|
|
134
137
|
for name, setting in self.table_settings.items():
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
138
|
+
if ('target_index' in setting.keys()):
|
139
|
+
target_indexes = [target_index.strip() for target_index in setting['target_index']]
|
140
|
+
else:
|
141
|
+
target_indexes = [None]
|
142
|
+
for target_index in target_indexes:
|
143
|
+
try:
|
144
|
+
return_dict[name] = StatsProcessor.slice_multi_col_table(
|
145
|
+
total_table=total_table,
|
146
|
+
mode=setting['mode'],
|
147
|
+
target_index=target_index)
|
148
|
+
break
|
149
|
+
except Exception as e:
|
150
|
+
continue
|
141
151
|
return return_dict
|
@@ -132,14 +132,15 @@ class CashFlowFetcher(StatsFetcher):
|
|
132
132
|
table_dict[time_index][index_name]['value'] = value[
|
133
133
|
'value']
|
134
134
|
if (value['value']):
|
135
|
-
|
136
|
-
'percentage'] = np.round(
|
135
|
+
ratio = np.round(
|
137
136
|
(value['value'] / cash_flow[
|
138
137
|
main_cash_flow_name]['value']) * 100, 2)
|
138
|
+
table_dict[time_index][index_name][
|
139
|
+
'percentage'] = f"{ratio}%"
|
139
140
|
else:
|
140
141
|
table_dict[time_index][index_name][
|
141
142
|
'percentage'] = None
|
142
|
-
except:
|
143
|
+
except: # 新增index再做一次
|
143
144
|
if (time_index not in table_dict.keys()):
|
144
145
|
table_dict[time_index] = dict()
|
145
146
|
table_dict[time_index][index_name] = dict()
|
@@ -147,14 +148,15 @@ class CashFlowFetcher(StatsFetcher):
|
|
147
148
|
table_dict[time_index][index_name]['value'] = value[
|
148
149
|
'value']
|
149
150
|
if (value['value']):
|
150
|
-
|
151
|
-
'percentage'] = np.round(
|
151
|
+
ratio = np.round(
|
152
152
|
(value['value'] / cash_flow[
|
153
153
|
main_cash_flow_name]['value']) * 100, 2)
|
154
|
+
table_dict[time_index][index_name][
|
155
|
+
'percentage'] = f"{ratio}%"
|
154
156
|
else:
|
155
157
|
table_dict[time_index][index_name][
|
156
158
|
'percentage'] = None
|
157
|
-
|
159
|
+
table_dict[time_index][index_name]['value'] = StatsProcessor.cal_non_percentage(value['value'], postfix="千元")
|
158
160
|
try:
|
159
161
|
partial_cash_flow[time_index][index_name] = table_dict[
|
160
162
|
time_index][index_name]
|
@@ -31,15 +31,19 @@ class FinanceOverviewFetcher(StatsFetcher):
|
|
31
31
|
|
32
32
|
for key, target_sets in self.target_fields.items():
|
33
33
|
try:
|
34
|
-
|
35
|
-
|
36
|
-
small_target] # balance_sheet/profit_lose/cash_flow
|
34
|
+
small_targets = target_sets['field']
|
35
|
+
|
37
36
|
value_index = target_sets['value'] # "金額" or "%"
|
38
37
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
for small_target in small_targets:
|
39
|
+
big_target = self.inverse_dict[
|
40
|
+
small_target] # balance_sheet/profit_lose/cash_flow
|
41
|
+
if (small_target == "利息費用_bank"):
|
42
|
+
small_target = small_target[:small_target.find("_bank")]
|
43
|
+
target_query.update({
|
44
|
+
f"{key}":
|
45
|
+
f"$$target_season_data.{big_target}.{small_target}.{value_index}"
|
46
|
+
})
|
43
47
|
except Exception:
|
44
48
|
continue
|
45
49
|
|
@@ -98,8 +102,16 @@ class FinanceOverviewFetcher(StatsFetcher):
|
|
98
102
|
finance_dict = fetched_data['seasonal_data'][0]
|
99
103
|
FinanceOverviewProcessor.process_rate(finance_dict)
|
100
104
|
FinanceOverviewProcessor.process_all(finance_dict)
|
105
|
+
self.fill_nan_index(finance_dict)
|
106
|
+
FinanceOverviewProcessor.process_thousand_dollar(finance_dict)
|
101
107
|
fetched_data['seasonal_data'] = finance_dict
|
108
|
+
|
102
109
|
return fetched_data
|
110
|
+
|
111
|
+
def fill_nan_index(self, finance_dict):
|
112
|
+
for key in self.target_fields.keys():
|
113
|
+
if (key not in finance_dict.keys()):
|
114
|
+
finance_dict[key] = None
|
103
115
|
|
104
116
|
|
105
117
|
class FinanceOverviewProcessor(StatsProcessor):
|
@@ -116,6 +128,35 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
116
128
|
else:
|
117
129
|
finance_dict[key] = StatsProcessor.cal_non_percentage(
|
118
130
|
finance_dict[key])
|
131
|
+
|
132
|
+
|
133
|
+
@classmethod
|
134
|
+
def process_thousand_dollar(cls, finance_dict):
|
135
|
+
process_index = [
|
136
|
+
"revenue",
|
137
|
+
"gross_profit",
|
138
|
+
"operating_income",
|
139
|
+
"net_income",
|
140
|
+
"operating_cash_flow",
|
141
|
+
"invest_cash_flow",
|
142
|
+
"financing_cash_flow",
|
143
|
+
"fcf",
|
144
|
+
|
145
|
+
'current_assets',
|
146
|
+
'current_liabilities',
|
147
|
+
'non_current_assets',
|
148
|
+
'non_current_liabilities',
|
149
|
+
'total_assets',
|
150
|
+
"total_liabilities",
|
151
|
+
"equity"
|
152
|
+
]
|
153
|
+
|
154
|
+
for index in process_index:
|
155
|
+
try:
|
156
|
+
finance_dict[index] = StatsProcessor.cal_non_percentage(finance_dict[index], postfix="千元")
|
157
|
+
except Exception as e:
|
158
|
+
finance_dict[index] = None
|
159
|
+
|
119
160
|
|
120
161
|
@classmethod
|
121
162
|
def process_all(cls, finance_dict):
|
@@ -135,12 +176,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
135
176
|
cls.cal_quick_ratio, cls.cal_debt_to_equity_ratio,
|
136
177
|
cls.cal_net_debt_to_equity_ratio, cls.cal_interest_coverage_ratio,
|
137
178
|
cls.cal_debt_to_operating_cash_flow,
|
138
|
-
cls.cal_debt_to_free_cash_flow, cls.cal_cash_flow_ratio
|
179
|
+
cls.cal_debt_to_free_cash_flow, cls.cal_cash_flow_ratio,
|
139
180
|
]
|
140
181
|
|
141
182
|
for method in methods:
|
142
183
|
method(finance_dict)
|
143
184
|
|
185
|
+
|
144
186
|
@classmethod
|
145
187
|
def cal_EBIT(cls, finance_dict):
|
146
188
|
"""
|
@@ -224,7 +266,14 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
224
266
|
計算每股毛利
|
225
267
|
= (當期營業毛利)÷(當期在外流通股數)
|
226
268
|
"""
|
227
|
-
|
269
|
+
if ('gross_profit' not in finance_dict.keys()):
|
270
|
+
try:
|
271
|
+
finance_dict['gross_profit'] = (
|
272
|
+
finance_dict['revenue'] -
|
273
|
+
finance_dict['operating_cost']
|
274
|
+
)
|
275
|
+
except:
|
276
|
+
finance_dict['gross_profit'] = None
|
228
277
|
try:
|
229
278
|
gross_per_share = (finance_dict['gross_profit'] /
|
230
279
|
finance_dict['share_outstanding'])
|
@@ -267,7 +316,7 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
267
316
|
operating_cash_flow_per_share)
|
268
317
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
269
318
|
finance_dict['operating_cash_flow_per_share'] = None
|
270
|
-
print(f'operating_cash_flow_per_share because of {str(e)}')
|
319
|
+
# print(f'operating_cash_flow_per_share because of {str(e)}')
|
271
320
|
|
272
321
|
@classmethod
|
273
322
|
def fcf_per_share(cls, finance_dict):
|
@@ -292,12 +341,15 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
292
341
|
計算資產報酬率(ROA)
|
293
342
|
ROA = [ 本期淨利 + 利息費用 × (1-有效稅率) ] ÷(資產總額)
|
294
343
|
"""
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
344
|
+
try:
|
345
|
+
roa = (
|
346
|
+
finance_dict['net_income'] + finance_dict['interest'] +
|
347
|
+
(1 * 0.1) # 有效稅率需要改,這裡先設0.1
|
348
|
+
) / finance_dict['inventories']
|
299
349
|
|
300
|
-
|
350
|
+
finance_dict["roa"] = StatsProcessor.cal_percentage(roa)
|
351
|
+
except Exception as e:
|
352
|
+
finance_dict["roa"] = None
|
301
353
|
|
302
354
|
@classmethod
|
303
355
|
def cal_roe(cls, finance_dict):
|
@@ -305,8 +357,11 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
305
357
|
計算股東權益報酬率(ROE)
|
306
358
|
ROE = (本期淨利) ÷(權益總額)
|
307
359
|
"""
|
308
|
-
|
309
|
-
|
360
|
+
try:
|
361
|
+
roe = (finance_dict['net_income'] / finance_dict['equity'])
|
362
|
+
finance_dict['roe'] = StatsProcessor.cal_percentage(roe)
|
363
|
+
except Exception as e:
|
364
|
+
finance_dict['roe'] = None
|
310
365
|
|
311
366
|
@classmethod
|
312
367
|
def cal_gross_over_asset(cls, finance_dict):
|
@@ -315,7 +370,7 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
315
370
|
"""
|
316
371
|
try:
|
317
372
|
gross_over_asset = (finance_dict['gross_profit'] /
|
318
|
-
finance_dict['
|
373
|
+
finance_dict['total_assets'])
|
319
374
|
finance_dict['gross_over_asset'] = StatsProcessor.cal_percentage(
|
320
375
|
gross_over_asset)
|
321
376
|
except (KeyError, ZeroDivisionError, TypeError) as e:
|
@@ -331,7 +386,7 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
331
386
|
try:
|
332
387
|
roce = ((finance_dict['net_income_before_tax'] +
|
333
388
|
finance_dict['interest']) /
|
334
|
-
(finance_dict['
|
389
|
+
(finance_dict['total_assets'] -
|
335
390
|
finance_dict['current_liabilities']))
|
336
391
|
finance_dict['roce'] = StatsProcessor.cal_percentage(roce)
|
337
392
|
|
@@ -351,7 +406,7 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
351
406
|
finance_dict[
|
352
407
|
'gross_profit_margin'] = StatsProcessor.cal_percentage(
|
353
408
|
gross_profit_margin)
|
354
|
-
except:
|
409
|
+
except Exception as e:
|
355
410
|
finance_dict['gross_profit_margin'] = None
|
356
411
|
print(f"gross_profit_margin failed because of {str(e)}")
|
357
412
|
|
@@ -409,7 +464,7 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
409
464
|
(finance_dict['account_pay'] / finance_dict['revenue']))
|
410
465
|
finance_dict['dso'] = StatsProcessor.cal_non_percentage(
|
411
466
|
dso, to_str=True, postfix="日")
|
412
|
-
except:
|
467
|
+
except Exception as e:
|
413
468
|
finance_dict['dso'] = None
|
414
469
|
print(f"Error calculating 應收帳款收現天數 because of {str(e)}")
|
415
470
|
|
@@ -419,11 +474,15 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
419
474
|
計算應收帳款佔營收比率
|
420
475
|
= 應收帳款平均餘額 ÷ 營業收入
|
421
476
|
"""
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
account_receive_over_revenue
|
477
|
+
try:
|
478
|
+
account_receive_over_revenue = (finance_dict['account_receive'] /
|
479
|
+
finance_dict['revenue'])
|
480
|
+
finance_dict[
|
481
|
+
"account_receive_over_revenue"] = StatsProcessor.cal_percentage(
|
482
|
+
account_receive_over_revenue)
|
483
|
+
except Exception as e:
|
484
|
+
finance_dict[
|
485
|
+
"account_receive_over_revenue"] = None
|
427
486
|
|
428
487
|
@classmethod
|
429
488
|
def cal_dpo(cls, finance_dict):
|
@@ -513,10 +572,13 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
513
572
|
計算資產周轉率
|
514
573
|
營業收入 ÷ 資產總額
|
515
574
|
"""
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
asset_turnover
|
575
|
+
try:
|
576
|
+
asset_turnover = (finance_dict["revenue"] /
|
577
|
+
finance_dict["inventories"])
|
578
|
+
finance_dict["asset_turnover"] = StatsProcessor.cal_percentage(
|
579
|
+
asset_turnover)
|
580
|
+
except Exception as e:
|
581
|
+
finance_dict["asset_turnover"] = None
|
520
582
|
|
521
583
|
@classmethod
|
522
584
|
def cal_application_turnover(cls, finance_dict):
|
@@ -528,11 +590,12 @@ class FinanceOverviewProcessor(StatsProcessor):
|
|
528
590
|
applcation_turnover = (finance_dict['revenue'] /
|
529
591
|
finance_dict["application"])
|
530
592
|
finance_dict[
|
531
|
-
'
|
593
|
+
'application_turnover'] = StatsProcessor.cal_percentage(
|
532
594
|
applcation_turnover)
|
533
595
|
|
534
|
-
except
|
596
|
+
except Exception as e:
|
535
597
|
finance_dict['application_turnover'] = None
|
598
|
+
|
536
599
|
|
537
600
|
@classmethod
|
538
601
|
def cal_current_ratio(cls, finance_dict):
|
@@ -0,0 +1,214 @@
|
|
1
|
+
from .base import StatsFetcher
|
2
|
+
from datetime import datetime, timedelta
|
3
|
+
import json
|
4
|
+
import numpy as np
|
5
|
+
import pandas as pd
|
6
|
+
from ..utils import StatsDateTime, StatsProcessor
|
7
|
+
import importlib.resources as pkg_resources
|
8
|
+
import yaml
|
9
|
+
|
10
|
+
|
11
|
+
class InstitutionFetcher(StatsFetcher):
|
12
|
+
"""
|
13
|
+
iFa -> 交易資訊 -> 法人買賣
|
14
|
+
|
15
|
+
包括:
|
16
|
+
1. 當日交易
|
17
|
+
2. 一年內交易
|
18
|
+
"""
|
19
|
+
|
20
|
+
def __init__(self, ticker, db_client):
|
21
|
+
super().__init__(ticker, db_client)
|
22
|
+
|
23
|
+
def prepare_query(self, start_date, end_date):
|
24
|
+
pipeline = super().prepare_query()
|
25
|
+
|
26
|
+
# target_query = {
|
27
|
+
# "date": date,
|
28
|
+
# "institution_trading": "$$target_season_data.institution_trading"
|
29
|
+
# }
|
30
|
+
|
31
|
+
pipeline.append({
|
32
|
+
"$project": {
|
33
|
+
"_id": 0,
|
34
|
+
"ticker": 1,
|
35
|
+
"company_name": 1,
|
36
|
+
"daily_data": {
|
37
|
+
"$map": {
|
38
|
+
"input": {
|
39
|
+
"$filter": {
|
40
|
+
"input": "$daily_data",
|
41
|
+
"as": "daily",
|
42
|
+
"cond": {
|
43
|
+
"$and": [{
|
44
|
+
"$gte": ["$$daily.date", start_date]
|
45
|
+
}, {
|
46
|
+
"$lte": ["$$daily.date", end_date]
|
47
|
+
}]
|
48
|
+
}
|
49
|
+
}
|
50
|
+
},
|
51
|
+
"as": "target_daily_data",
|
52
|
+
"in": "$$target_daily_data"
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
})
|
57
|
+
|
58
|
+
return pipeline
|
59
|
+
|
60
|
+
def collect_data(self, start_date, end_date):
|
61
|
+
pipeline = self.prepare_query(start_date, end_date)
|
62
|
+
|
63
|
+
fetched_data = self.collection.aggregate(pipeline).to_list()
|
64
|
+
|
65
|
+
return fetched_data[-1]
|
66
|
+
|
67
|
+
def query_data(self):
|
68
|
+
try:
|
69
|
+
latest_time = StatsDateTime.get_latest_time(
|
70
|
+
self.ticker, self.collection)['last_update_time']
|
71
|
+
latest_date = latest_time['institution_trading'][
|
72
|
+
'latest_date']
|
73
|
+
date = latest_date.replace(hour=0,
|
74
|
+
minute=0,
|
75
|
+
second=0,
|
76
|
+
microsecond=0)
|
77
|
+
except Exception as e:
|
78
|
+
print(
|
79
|
+
f"No updated time for institution_trading in {self.ticker}, use current time instead"
|
80
|
+
)
|
81
|
+
date = datetime.now(self.timezone)
|
82
|
+
date = date.replace(hour=0, minute=0, second=0, microsecond=0)
|
83
|
+
|
84
|
+
if (date.hour < 17): # 拿不到今天的資料
|
85
|
+
date = date - timedelta(days=1)
|
86
|
+
|
87
|
+
start_date = date - timedelta(days=365)
|
88
|
+
|
89
|
+
daily_data = self.collect_data(start_date, end_date=date)
|
90
|
+
|
91
|
+
daily_data = sorted(daily_data['daily_data'],
|
92
|
+
key=lambda x: x['date'],
|
93
|
+
reverse=True)
|
94
|
+
|
95
|
+
table_dict = self.process_data(daily_data)
|
96
|
+
|
97
|
+
return table_dict
|
98
|
+
|
99
|
+
def process_data(self, daily_data):
|
100
|
+
table_dict = dict()
|
101
|
+
|
102
|
+
latest_data = daily_data[0]
|
103
|
+
yesterday_data = daily_data[1]
|
104
|
+
|
105
|
+
# 交易價格與昨天交易
|
106
|
+
price_dict = {
|
107
|
+
"open": latest_data['open'],
|
108
|
+
'close': latest_data['close'],
|
109
|
+
'range': f"{latest_data['low']}-{latest_data['high']}",
|
110
|
+
'volumn': latest_data['volume'] / 1000,
|
111
|
+
'last_open': yesterday_data['open'],
|
112
|
+
'last_close': yesterday_data['close'],
|
113
|
+
'last_range': f"{yesterday_data['low']}-{yesterday_data['high']}",
|
114
|
+
'last_volumn': yesterday_data['volume'] / 1000
|
115
|
+
}
|
116
|
+
# 一年範圍
|
117
|
+
annual_lows = [data['low'] for data in daily_data]
|
118
|
+
annual_highs = [data['high'] for data in daily_data]
|
119
|
+
lowest = np.min(annual_lows).item()
|
120
|
+
highest = np.max(annual_highs).item()
|
121
|
+
|
122
|
+
price_dict['52weeks_range'] = f"{lowest}-{highest}"
|
123
|
+
table_dict['price'] = price_dict
|
124
|
+
|
125
|
+
# 發行股數 & 市值
|
126
|
+
|
127
|
+
# 今日法人買賣
|
128
|
+
table_dict['latest_trading'] = {
|
129
|
+
"date":
|
130
|
+
daily_data[0]['date'],
|
131
|
+
"table":
|
132
|
+
self.process_latest_trading(daily_data[0]['institution_trading'], daily_data[0]['volume'])
|
133
|
+
}
|
134
|
+
# 一年內法人
|
135
|
+
annual_trading = [
|
136
|
+
{
|
137
|
+
**data['institution_trading'],
|
138
|
+
"收盤價": int(data['close'])
|
139
|
+
}
|
140
|
+
for data in daily_data
|
141
|
+
] # 將close也併入這個表格
|
142
|
+
annual_dates = [data['date'] for data in daily_data]
|
143
|
+
table_dict['annual_trading'] = self.process_annual_trading(
|
144
|
+
annual_dates, annual_trading)
|
145
|
+
|
146
|
+
return table_dict
|
147
|
+
|
148
|
+
def process_latest_trading(self, latest_trading, volume):
|
149
|
+
latest_table = {
|
150
|
+
"foreign": self.default_institution_chart(),
|
151
|
+
"mutual": self.default_institution_chart(),
|
152
|
+
"prop": self.default_institution_chart(),
|
153
|
+
"institutional_investor":self.default_institution_chart(),
|
154
|
+
}
|
155
|
+
|
156
|
+
for key in latest_trading.keys():
|
157
|
+
if (key.find("外陸資") >= 0 or key.find("外資") >= 0):
|
158
|
+
self.target_institution(latest_trading, latest_table['foreign'], key, volume)
|
159
|
+
elif (key.find("自營商") >= 0):
|
160
|
+
self.target_institution(latest_trading,latest_table['prop'], key, volume)
|
161
|
+
elif (key.find("投信") >= 0):
|
162
|
+
self.target_institution(latest_trading,latest_table['mutual'], key, volume)
|
163
|
+
elif (key.find("三大法人") >= 0):
|
164
|
+
self.target_institution(latest_trading,latest_table['institutional_investor'], key, volume)
|
165
|
+
|
166
|
+
frames = []
|
167
|
+
for category, trades in latest_table.items():
|
168
|
+
temp_df = pd.DataFrame(trades).T
|
169
|
+
temp_df['category'] = category
|
170
|
+
frames.append(temp_df)
|
171
|
+
|
172
|
+
latest_df = pd.concat(frames)
|
173
|
+
latest_df = latest_df.reset_index().rename(columns={'index': 'type'})
|
174
|
+
latest_df = latest_df[['type', 'category', 'stock', 'price', 'average_price', 'percentage']]
|
175
|
+
|
176
|
+
return latest_df
|
177
|
+
|
178
|
+
def process_annual_trading(self, dates, annual_tradings):
|
179
|
+
dates = [date.strftime("%m/%d") for date in dates]
|
180
|
+
return pd.DataFrame(annual_tradings, index=dates)
|
181
|
+
|
182
|
+
def target_institution(self, old_table, new_table, key, volume):
|
183
|
+
if (key.find("買進") >= 0):
|
184
|
+
self.cal_institution(old_table, new_table['buy'], key, volume)
|
185
|
+
elif (key.find("賣出") >= 0):
|
186
|
+
self.cal_institution(old_table, new_table['sell'], key, volume)
|
187
|
+
elif (key.find("買賣超") >= 0):
|
188
|
+
self.cal_institution(old_table, new_table['over_buy_sell'], key, volume)
|
189
|
+
|
190
|
+
def cal_institution(self, old_table, new_table, key, volume):
|
191
|
+
new_table['stock'] = np.round(old_table[key] / 1000, 2).item()
|
192
|
+
new_table['percentage'] = np.round((old_table[key] / volume) * 100, 2).item()
|
193
|
+
|
194
|
+
def default_institution_chart(self):
|
195
|
+
return {
|
196
|
+
"buy": {
|
197
|
+
"stock": 0,
|
198
|
+
"price": 0,
|
199
|
+
"average_price": 0,
|
200
|
+
"percentage": 0
|
201
|
+
},
|
202
|
+
"sell": {
|
203
|
+
"stock": 0,
|
204
|
+
"price": 0,
|
205
|
+
"average_price": 0,
|
206
|
+
"percentage": 0
|
207
|
+
},
|
208
|
+
"over_buy_sell": {
|
209
|
+
"stock": 0,
|
210
|
+
"price": 0,
|
211
|
+
"average_price": 0,
|
212
|
+
"percentage": 0
|
213
|
+
},
|
214
|
+
}
|
@@ -64,6 +64,17 @@ class MonthRevenueFetcher(StatsFetcher):
|
|
64
64
|
def process_data(self, fetched_data):
|
65
65
|
|
66
66
|
monthly_data = fetched_data['monthly_data']
|
67
|
+
for data in monthly_data:
|
68
|
+
for key, value in data.items():
|
69
|
+
if ("YoY" in key):
|
70
|
+
data[key] = StatsProcessor.cal_percentage(value)
|
71
|
+
elif ("ratio" in key or 'percentage' in key):
|
72
|
+
data[key] = StatsProcessor.cal_non_percentage(value,
|
73
|
+
to_str=True,
|
74
|
+
postfix="%")
|
75
|
+
elif (key not in ('year', 'month')):
|
76
|
+
data[key] = StatsProcessor.cal_non_percentage(value,
|
77
|
+
postfix="千元")
|
67
78
|
target_month = monthly_data[0]['month']
|
68
79
|
monthly_df = pd.DataFrame(monthly_data)
|
69
80
|
target_month_df = monthly_df[monthly_df['month'] == target_month]
|
@@ -77,21 +88,26 @@ class MonthRevenueFetcher(StatsFetcher):
|
|
77
88
|
|
78
89
|
grand_total_df.rename(index={target_month: f"grand_total"},
|
79
90
|
inplace=True)
|
80
|
-
month_revenue_df = month_revenue_df.sort_index(ascending
|
91
|
+
month_revenue_df = month_revenue_df.sort_index(ascending=False)
|
81
92
|
month_revenue_df = pd.concat([grand_total_df, month_revenue_df],
|
82
93
|
axis=0)
|
83
94
|
|
84
|
-
fetched_data['month_revenue'] = month_revenue_df[sorted(
|
95
|
+
fetched_data['month_revenue'] = month_revenue_df[sorted(
|
96
|
+
month_revenue_df.columns, reverse=True)]
|
85
97
|
# 歷年月營收
|
86
98
|
fetched_data[
|
87
99
|
'this_month_revenue_over_years'] = target_month_df.set_index(
|
88
|
-
"year")[[
|
89
|
-
|
100
|
+
"year")[[
|
101
|
+
"revenue", "revenue_increment_ratio", "YoY_1", "YoY_3",
|
102
|
+
"YoY_5", "YoY_10"
|
103
|
+
]].T
|
90
104
|
# 歷年營收成長量
|
91
105
|
fetched_data['grand_total_over_years'] = target_month_df.set_index(
|
92
|
-
"year")[[
|
93
|
-
|
94
|
-
|
106
|
+
"year")[[
|
107
|
+
"grand_total", "grand_total_increment_ratio",
|
108
|
+
"grand_total_YoY_1", "grand_total_YoY_3", "grand_total_YoY_5",
|
109
|
+
"grand_total_YoY_10"
|
110
|
+
]].T
|
95
111
|
|
96
112
|
fetched_data.pop("monthly_data")
|
97
113
|
|
@@ -115,12 +115,15 @@ class ProfitLoseFetcher(StatsFetcher):
|
|
115
115
|
for index_name, value_dict in profit_lose.items():
|
116
116
|
# (2020Q1, 項目, 金額或%)
|
117
117
|
for item_name, item in value_dict.items():
|
118
|
-
if (
|
118
|
+
if ('percentage' in item_name):
|
119
119
|
if (isinstance(item, (float, int))):
|
120
|
-
item =
|
121
|
-
|
120
|
+
item = StatsProcessor.cal_non_percentage(item, to_str=True, postfix="%")
|
121
|
+
elif ('YoY' in item_name):
|
122
122
|
if (isinstance(item, (float, int))):
|
123
|
-
item =
|
123
|
+
item = StatsProcessor.cal_percentage(item)
|
124
|
+
else:
|
125
|
+
if (isinstance(item, (float, int))):
|
126
|
+
item = StatsProcessor.cal_non_percentage(item, postfix="千元")
|
124
127
|
try:
|
125
128
|
table_dict[index_name][(time_index, item_name)] = item
|
126
129
|
|
@@ -137,10 +140,19 @@ class ProfitLoseFetcher(StatsFetcher):
|
|
137
140
|
total_table = total_table.replace("N/A", None)
|
138
141
|
|
139
142
|
for name, setting in self.table_settings.items():
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
143
|
+
if ('target_index' in setting.keys()):
|
144
|
+
target_indexes = [target.strip() for target in setting['target_index']]
|
145
|
+
else:
|
146
|
+
target_indexes = [None]
|
147
|
+
|
148
|
+
for target_index in target_indexes:
|
149
|
+
try:
|
150
|
+
return_dict[name] = StatsProcessor.slice_multi_col_table(
|
151
|
+
total_table=total_table,
|
152
|
+
mode=setting['mode'],
|
153
|
+
target_index=target_index)
|
154
|
+
break
|
155
|
+
except Exception as e:
|
156
|
+
continue
|
145
157
|
|
146
158
|
return return_dict
|
@@ -3,24 +3,32 @@ balance_sheet:
|
|
3
3
|
|
4
4
|
total_asset:
|
5
5
|
mode: value_and_percentage
|
6
|
-
target_index:
|
7
|
-
|
6
|
+
target_index:
|
7
|
+
- 資產總額 負債總額 權益總額
|
8
|
+
- 資產總計 負債總計 權益總計
|
9
|
+
|
8
10
|
current_asset:
|
9
11
|
mode: value_and_percentage
|
10
|
-
target_index:
|
12
|
+
target_index:
|
13
|
+
- 流動資產合計
|
11
14
|
|
12
15
|
non_current_asset:
|
13
16
|
mode: value_and_percentage
|
14
|
-
target_index:
|
17
|
+
target_index:
|
18
|
+
- 非流動資產合計
|
15
19
|
|
16
20
|
current_debt:
|
17
21
|
mode: value_and_percentage
|
18
|
-
target_index:
|
22
|
+
target_index:
|
23
|
+
- 流動負債合計
|
19
24
|
|
20
25
|
non_current_debt:
|
21
26
|
mode: value_and_percentage
|
22
|
-
target_index:
|
27
|
+
target_index:
|
28
|
+
- 非流動負債合計
|
23
29
|
|
24
30
|
equity:
|
25
31
|
mode: value_and_percentage
|
26
|
-
target_index:
|
32
|
+
target_index:
|
33
|
+
- 權益總額
|
34
|
+
- 權益總計
|
@@ -1,89 +1,111 @@
|
|
1
1
|
# 財務概況
|
2
2
|
revenue:
|
3
|
-
field:
|
3
|
+
field:
|
4
|
+
- 營業收入合計
|
4
5
|
value: value
|
5
6
|
|
6
7
|
gross_profit:
|
7
|
-
field:
|
8
|
+
field:
|
9
|
+
- 營業毛利(毛損)淨額
|
8
10
|
value: value
|
9
11
|
|
10
12
|
operating_income:
|
11
|
-
field:
|
13
|
+
field:
|
14
|
+
- 營業利益(損失)
|
12
15
|
value: value
|
13
16
|
|
14
17
|
net_income:
|
15
|
-
field:
|
18
|
+
field:
|
19
|
+
- 本期淨利(淨損)
|
16
20
|
value: value
|
17
21
|
|
18
22
|
tax_fee:
|
19
|
-
field:
|
23
|
+
field:
|
24
|
+
- 所得稅費用(利益)合計
|
20
25
|
value: value
|
21
26
|
|
22
27
|
# TODO: 以下所爬到的資料都是累計的,Ifa有額外計算當季的變化量
|
23
28
|
operating_cash_flow:
|
24
|
-
field:
|
29
|
+
field:
|
30
|
+
- 營業活動之淨現金流入(流出)
|
25
31
|
value: single_season_value
|
26
32
|
|
27
33
|
invest_cash_flow:
|
28
|
-
field:
|
34
|
+
field:
|
35
|
+
- 投資活動之淨現金流入(流出)
|
29
36
|
value: single_season_value
|
30
37
|
|
31
38
|
financing_cash_flow:
|
32
|
-
field:
|
39
|
+
field:
|
40
|
+
- 籌資活動之淨現金流入(流出)
|
33
41
|
value: single_season_value
|
34
42
|
# ^^^ 以上皆需要額外在DataBase處理
|
35
43
|
|
36
44
|
# 每股財務狀況
|
37
45
|
capital:
|
38
|
-
field:
|
46
|
+
field:
|
47
|
+
- 普通股股本
|
39
48
|
value: value
|
49
|
+
|
40
50
|
eps:
|
41
|
-
field:
|
51
|
+
field:
|
52
|
+
- 基本每股盈餘
|
42
53
|
value: value
|
43
54
|
|
44
55
|
# 獲利能力
|
45
|
-
|
46
|
-
field:
|
56
|
+
total_assets:
|
57
|
+
field:
|
58
|
+
- 資產總額
|
47
59
|
value: value
|
48
60
|
|
49
61
|
equity:
|
50
|
-
field:
|
62
|
+
field:
|
63
|
+
- 權益總額
|
51
64
|
value: value
|
52
65
|
|
53
66
|
net_income_before_tax:
|
54
|
-
field:
|
67
|
+
field:
|
68
|
+
- 稅前淨利(淨損)
|
55
69
|
value: value
|
56
70
|
|
57
71
|
interest:
|
58
|
-
field:
|
72
|
+
field:
|
73
|
+
- 利息收入
|
59
74
|
value: value
|
60
75
|
|
61
76
|
operating_expenses:
|
62
|
-
field:
|
77
|
+
field:
|
78
|
+
- 營業費用合計
|
63
79
|
value: value
|
64
80
|
|
65
81
|
net_income_rate:
|
66
|
-
field:
|
82
|
+
field:
|
83
|
+
- 本期淨利(淨損)
|
67
84
|
value: percentage
|
68
85
|
# 成長動能
|
69
86
|
revenue_YoY:
|
70
|
-
field:
|
87
|
+
field:
|
88
|
+
- 營業收入合計
|
71
89
|
value: YoY_1
|
72
90
|
|
73
91
|
gross_prof_YoY:
|
74
|
-
field:
|
92
|
+
field:
|
93
|
+
- 營業毛利(毛損)淨額
|
75
94
|
value: YoY_1
|
76
95
|
|
77
96
|
operating_income_YoY:
|
78
|
-
field:
|
97
|
+
field:
|
98
|
+
- 營業利益(損失)
|
79
99
|
value: YoY_1
|
80
100
|
|
81
101
|
net_income_YoY:
|
82
|
-
field:
|
102
|
+
field:
|
103
|
+
- 本期淨利(淨損)
|
83
104
|
value: YoY_1
|
84
105
|
|
85
106
|
operating_cash_flow_YoY:
|
86
|
-
field:
|
107
|
+
field:
|
108
|
+
- 營業活動之淨現金流入(流出)
|
87
109
|
value: single_season_YoY
|
88
110
|
|
89
111
|
# operating_cash_flow_per_share_YoY:
|
@@ -91,53 +113,73 @@ operating_cash_flow_YoY:
|
|
91
113
|
# value: YoY_1
|
92
114
|
# 營運指標
|
93
115
|
account_receive:
|
94
|
-
field:
|
116
|
+
field:
|
117
|
+
- 應收帳款淨額
|
95
118
|
value: value
|
96
119
|
|
97
120
|
account_pay:
|
98
|
-
field:
|
121
|
+
field:
|
122
|
+
- 應付帳款
|
99
123
|
value: value
|
100
124
|
|
101
125
|
inventories:
|
102
|
-
field:
|
126
|
+
field:
|
127
|
+
- 存貨
|
103
128
|
value: value
|
104
129
|
|
105
130
|
operating_cost:
|
106
|
-
field:
|
131
|
+
field:
|
132
|
+
- 營業成本合計
|
107
133
|
value: value
|
108
134
|
|
109
135
|
application:
|
110
|
-
field:
|
136
|
+
field:
|
137
|
+
- 不動產、廠房及設備
|
111
138
|
value: value
|
112
139
|
|
113
140
|
# 財務韌性
|
114
141
|
current_assets:
|
115
|
-
field:
|
142
|
+
field:
|
143
|
+
- 流動資產合計
|
116
144
|
value: value
|
117
145
|
|
118
146
|
current_liabilities:
|
119
|
-
field:
|
147
|
+
field:
|
148
|
+
- 流動負債合計
|
120
149
|
value: value
|
121
150
|
|
122
151
|
total_liabilities:
|
123
|
-
field:
|
152
|
+
field:
|
153
|
+
- 負債總額
|
124
154
|
value: value
|
125
155
|
|
126
156
|
short_term_liabilities:
|
127
|
-
field:
|
157
|
+
field:
|
158
|
+
- 短期借款
|
128
159
|
value: value
|
129
160
|
|
130
161
|
long_term_liabilities:
|
131
|
-
field:
|
162
|
+
field:
|
163
|
+
- 長期借款
|
132
164
|
value: value
|
133
165
|
#
|
134
166
|
cash_and_cash_equivalents:
|
135
|
-
field:
|
167
|
+
field:
|
168
|
+
- 現金及約當現金
|
136
169
|
value: value
|
137
170
|
|
138
171
|
interest_expense:
|
139
|
-
field:
|
172
|
+
field:
|
173
|
+
- 利息費用
|
140
174
|
value: value
|
141
175
|
|
176
|
+
non_current_assets:
|
177
|
+
field:
|
178
|
+
- 非流動資產合計
|
179
|
+
value: value
|
142
180
|
|
181
|
+
non_current_liabilities:
|
182
|
+
field:
|
183
|
+
- 非流動負債合計
|
184
|
+
value: value
|
143
185
|
|
@@ -6,88 +6,116 @@ grand_total_profit_lose:
|
|
6
6
|
|
7
7
|
revenue:
|
8
8
|
mode: growth
|
9
|
-
target_index:
|
9
|
+
target_index:
|
10
|
+
- 營業收入合計
|
11
|
+
- 利息收入
|
10
12
|
|
11
13
|
grand_total_revenue:
|
12
14
|
mode: grand_total_growth
|
13
|
-
target_index:
|
15
|
+
target_index:
|
16
|
+
- 營業收入合計
|
17
|
+
- 利息收入
|
14
18
|
|
15
19
|
gross_profit:
|
16
20
|
mode: growth
|
17
|
-
target_index:
|
21
|
+
target_index:
|
22
|
+
- 營業毛利(毛損)淨額
|
18
23
|
|
19
24
|
grand_total_gross_profit:
|
20
25
|
mode: grand_total_growth
|
21
|
-
target_index:
|
26
|
+
target_index:
|
27
|
+
- 營業毛利(毛損)淨額
|
22
28
|
|
23
29
|
gross_profit_percentage:
|
24
30
|
mode: percentage
|
25
|
-
target_index:
|
31
|
+
target_index:
|
32
|
+
- 營業毛利(毛損)淨額
|
26
33
|
|
27
34
|
grand_total_gross_profit_percentage:
|
28
35
|
mode: grand_total_percentage
|
29
|
-
target_index:
|
36
|
+
target_index:
|
37
|
+
- 營業毛利(毛損)淨額
|
30
38
|
# 營利
|
31
39
|
operating_income:
|
32
40
|
mode: growth
|
33
|
-
target_index:
|
41
|
+
target_index:
|
42
|
+
- 營業利益(損失)
|
34
43
|
|
35
44
|
grand_total_operating_income:
|
36
45
|
mode: grand_total_growth
|
37
|
-
target_index:
|
46
|
+
target_index:
|
47
|
+
- 營業利益(損失)
|
38
48
|
|
39
49
|
operating_income_percentage:
|
40
50
|
mode: percentage
|
41
|
-
target_index:
|
51
|
+
target_index:
|
52
|
+
- 營業利益(損失)
|
42
53
|
|
43
54
|
grand_total_operating_income_percentage:
|
44
55
|
mode: grand_total_percentage
|
45
|
-
target_index:
|
56
|
+
target_index:
|
57
|
+
- 營業利益(損失)
|
46
58
|
# 稅前淨利
|
47
59
|
net_income_before_tax:
|
48
60
|
mode: growth
|
49
|
-
target_index:
|
61
|
+
target_index:
|
62
|
+
- 稅前淨利(淨損)
|
50
63
|
|
51
64
|
grand_total_net_income_before_tax:
|
52
65
|
mode: grand_total_growth
|
53
|
-
target_index:
|
66
|
+
target_index:
|
67
|
+
- 稅前淨利(淨損)
|
54
68
|
|
55
69
|
net_income_before_tax_percentage:
|
56
70
|
mode: percentage
|
57
|
-
target_index:
|
71
|
+
target_index:
|
72
|
+
- 稅前淨利(淨損)
|
58
73
|
|
59
74
|
grand_total_net_income_before_tax_percentage:
|
60
75
|
mode: grand_total_percentage
|
61
|
-
target_index:
|
76
|
+
target_index:
|
77
|
+
- 稅前淨利(淨損)
|
62
78
|
# 本期淨利
|
63
79
|
net_income:
|
64
80
|
mode: growth
|
65
|
-
target_index:
|
81
|
+
target_index:
|
82
|
+
- 本期淨利(淨損)
|
66
83
|
|
67
84
|
grand_total_net_income:
|
68
85
|
mode: grand_total_growth
|
69
|
-
target_index:
|
86
|
+
target_index:
|
87
|
+
- 本期淨利(淨損)
|
70
88
|
|
71
89
|
net_income_percentage:
|
72
90
|
mode: percentage
|
73
|
-
target_index:
|
91
|
+
target_index:
|
92
|
+
- 本期淨利(淨損)
|
74
93
|
|
75
94
|
grand_total_income_percentage:
|
76
95
|
mode: grand_total_percentage
|
77
|
-
target_index:
|
96
|
+
target_index:
|
97
|
+
- 本期淨利(淨損)
|
78
98
|
# EPS
|
79
99
|
EPS:
|
80
100
|
mode: value
|
81
|
-
target_index:
|
101
|
+
target_index:
|
102
|
+
- 基本每股盈餘
|
103
|
+
- 基本每股盈餘合計
|
82
104
|
|
83
105
|
EPS_growth:
|
84
106
|
mode: growth
|
85
|
-
target_index:
|
107
|
+
target_index:
|
108
|
+
- 基本每股盈餘
|
109
|
+
- 基本每股盈餘合計
|
86
110
|
|
87
111
|
grand_total_EPS:
|
88
112
|
mode: grand_total
|
89
|
-
target_index:
|
113
|
+
target_index:
|
114
|
+
- 基本每股盈餘
|
115
|
+
- 基本每股盈餘合計
|
90
116
|
|
91
117
|
grand_total_EPS_growth:
|
92
118
|
mode: grand_total_growth
|
93
|
-
target_index:
|
119
|
+
target_index:
|
120
|
+
- 基本每股盈餘
|
121
|
+
- 基本每股盈餘合計
|
@@ -22,11 +22,14 @@
|
|
22
22
|
"其他非流動資產": "balance_sheet",
|
23
23
|
"非流動資產合計": "balance_sheet",
|
24
24
|
"資產總額": "balance_sheet",
|
25
|
+
"資產總計": "balance_sheet",
|
25
26
|
"短期借款": "balance_sheet",
|
26
27
|
"長期借款": "balance_sheet",
|
27
28
|
"透過損益按公允價值衡量之金融負債-流動": "balance_sheet",
|
28
29
|
"應付票據": "balance_sheet",
|
29
30
|
"應付帳款": "balance_sheet",
|
31
|
+
"應收款項-淨額": "balance_sheet",
|
32
|
+
"應付款項": "balance_sheet",
|
30
33
|
"應付帳款-關係人": "balance_sheet",
|
31
34
|
"其他應付款": "balance_sheet",
|
32
35
|
"其他應付款項-關係人": "balance_sheet",
|
@@ -38,6 +41,7 @@
|
|
38
41
|
"其他非流動負債": "balance_sheet",
|
39
42
|
"非流動負債合計": "balance_sheet",
|
40
43
|
"負債總額": "balance_sheet",
|
44
|
+
"負債總計": "balance_sheet",
|
41
45
|
"普通股股本": "balance_sheet",
|
42
46
|
"股本合計": "balance_sheet",
|
43
47
|
"資本公積-發行溢價": "balance_sheet",
|
@@ -52,10 +56,12 @@
|
|
52
56
|
"歸屬於母公司業主之權益合計": "balance_sheet",
|
53
57
|
"非控制權益": "balance_sheet",
|
54
58
|
"權益總額": "balance_sheet",
|
59
|
+
"權益總計": "balance_sheet",
|
55
60
|
"負債及權益總計": "balance_sheet",
|
56
61
|
"待註銷股本股數(單位:股)": "balance_sheet",
|
57
62
|
"預收股款(權益項下)之約當發行股數(單位:股)": "balance_sheet",
|
58
63
|
"母公司暨子公司所持有之母公司庫藏股股數(單位:股)": "balance_sheet",
|
64
|
+
"應收款項-淨額": "balance_sheet",
|
59
65
|
"繼續營業單位稅前淨利(淨損)": "cash_flow",
|
60
66
|
"停業單位稅前淨利(淨損)": "cash_flow",
|
61
67
|
"本期稅前淨利(淨損)": "cash_flow",
|
@@ -135,6 +141,7 @@
|
|
135
141
|
"管理費用": "profit_lose",
|
136
142
|
"研究發展費用": "profit_lose",
|
137
143
|
"營業費用合計": "profit_lose",
|
144
|
+
"營業費用": "profit_lose",
|
138
145
|
"營業利益(損失)": "profit_lose",
|
139
146
|
"其他收入": "profit_lose",
|
140
147
|
"其他利益及損失淨額": "profit_lose",
|
@@ -142,6 +149,7 @@
|
|
142
149
|
"營業外收入及支出合計": "profit_lose",
|
143
150
|
"稅前淨利(淨損)": "profit_lose",
|
144
151
|
"所得稅費用(利益)合計": "profit_lose",
|
152
|
+
"所得稅費用(利益)": "profit_lose",
|
145
153
|
"繼續營業單位本期淨利(淨損)": "profit_lose",
|
146
154
|
"本期淨利(淨損)": "profit_lose",
|
147
155
|
"確定福利計畫之再衡量數": "profit_lose",
|
@@ -155,5 +163,12 @@
|
|
155
163
|
"母公司業主(綜合損益)": "profit_lose",
|
156
164
|
"非控制權益(綜合損益)": "profit_lose",
|
157
165
|
"基本每股盈餘": "profit_lose",
|
158
|
-
"稀釋每股盈餘": "profit_lose"
|
166
|
+
"稀釋每股盈餘": "profit_lose",
|
167
|
+
"淨收益": "profit_lose",
|
168
|
+
"利息收入": "profit_lose",
|
169
|
+
"利息費用_bank": "profit_lose",
|
170
|
+
"利息淨收益": "profit_lose",
|
171
|
+
"繼續營業單位稅前損益": "profit_lose",
|
172
|
+
"本期稅後淨利(淨損)": "profit_lose",
|
173
|
+
"減:利息費用": "profit_lose"
|
159
174
|
}
|
@@ -152,10 +152,21 @@ class StatsProcessor:
|
|
152
152
|
@classmethod
|
153
153
|
def cal_non_percentage(cls, value, to_str=False, postfix="元"):
|
154
154
|
if (isinstance(value, (float, int))):
|
155
|
+
|
155
156
|
value = np.round(value, 2).item()
|
157
|
+
if (postfix == "千元"):
|
158
|
+
value *= 1000
|
159
|
+
value = int(value)
|
160
|
+
|
161
|
+
postfix = "元"
|
162
|
+
|
156
163
|
if (to_str):
|
157
|
-
value
|
158
|
-
|
164
|
+
if (isinstance(value, float)):
|
165
|
+
value = f"{value:.2f}{postfix}"
|
166
|
+
return value
|
167
|
+
elif (isinstance(value, int)):
|
168
|
+
value = f"{value}{postfix}"
|
169
|
+
return value
|
159
170
|
|
160
171
|
else:
|
161
172
|
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.11
|
4
4
|
Summary: The service of NeuroStats website
|
5
5
|
Home-page: https://github.com/NeurowattStats/NeuroStats_API.git
|
6
6
|
Author: JasonWang@Neurowatt
|
@@ -19,6 +19,8 @@ Description-Content-Type: text/markdown
|
|
19
19
|
- [損益表](#損益表)
|
20
20
|
- [資產負債表](#資產負債表)
|
21
21
|
- [現金流量表](#現金流量表)
|
22
|
+
- [版本紀錄](#版本紀錄)
|
23
|
+
|
22
24
|
|
23
25
|
## 檔案架構
|
24
26
|
|
@@ -78,7 +80,7 @@ pip install neurostats-API
|
|
78
80
|
```Python
|
79
81
|
>>> import neurostats_API
|
80
82
|
>>> print(neurostats_API.__version__)
|
81
|
-
0.0.
|
83
|
+
0.0.10
|
82
84
|
```
|
83
85
|
|
84
86
|
### 得到最新一期的評價資料與歷年評價
|
@@ -434,6 +436,11 @@ stats_fetcher.query()
|
|
434
436
|
> 大部分資料缺失是因為尚未計算,僅先填上已經有的資料
|
435
437
|
|
436
438
|
|
437
|
-
##
|
438
|
-
|
439
|
+
## 版本紀錄
|
440
|
+
### 0.0.10
|
441
|
+
- 更新指標的資料型態: 單位為千元乘以1000之後回傳整數
|
442
|
+
|
443
|
+
- 處理銀行公司在finanace_overview會報錯誤的問題(未完全解決,因銀行公司財報有許多名稱不同,目前都會顯示為None)
|
439
444
|
|
445
|
+
### 0.0.9
|
446
|
+
- 更新指標的資料型態: 單位為日, %, 倍轉為字串
|
@@ -0,0 +1,27 @@
|
|
1
|
+
neurostats_API/__init__.py,sha256=oR5iCRZvbIRoODxS1VocreTo19N5L8Omvx_AgflzOO0,20
|
2
|
+
neurostats_API/cli.py,sha256=UJSWLIw03P24p-gkBb6JSEI5dW5U12UvLf1L8HjQD-o,873
|
3
|
+
neurostats_API/main.py,sha256=QcsfmWivg2Dnqw3MTJWiI0QvEiRs0VuH-BjwQHFCv00,677
|
4
|
+
neurostats_API/fetchers/__init__.py,sha256=27kdeBuM7dNBRcIyQ1u863CYw0P_DQz-I1G6iSFDq-c,357
|
5
|
+
neurostats_API/fetchers/balance_sheet.py,sha256=sQv4Gk5uoKURLEdh57YknOQWiyVwaXJ2Mw75jxNqUS0,5804
|
6
|
+
neurostats_API/fetchers/base.py,sha256=NW2SFzrimyAIrdJx1LVmTazelyZOAtcj54kJKHc4Vaw,1662
|
7
|
+
neurostats_API/fetchers/cash_flow.py,sha256=TY7VAWVXkj5-mzH5Iu0sIE-oV8MvGmmDy0URNotNV1E,7614
|
8
|
+
neurostats_API/fetchers/finance_overview.py,sha256=PxUdWY0x030olYMLcCHDBn068JLmCE2RTOce1dxs5vM,27753
|
9
|
+
neurostats_API/fetchers/institution.py,sha256=aODtsFyQcnD9PnMeaehMAN9wZdZ2a0EqSSZO57dY9RE,7691
|
10
|
+
neurostats_API/fetchers/month_revenue.py,sha256=nixX2llzjCFr2m2YVjxrSfkBusnZPrPb2dRDq1XLGhw,4251
|
11
|
+
neurostats_API/fetchers/profit_lose.py,sha256=xlLNsGSy4Azf4HyZyYaX3dFad-ACO-vuQToBooZi1_w,5698
|
12
|
+
neurostats_API/fetchers/tech.py,sha256=wH1kkqiETQhF0HAhk-UIiucnZ3EiL85Q-yMWCcVOiFM,11395
|
13
|
+
neurostats_API/fetchers/value_invest.py,sha256=O5IKC8Nl7p5-E-1zoyAyWtiDznaxNemeabanmaHDdJs,3327
|
14
|
+
neurostats_API/tools/balance_sheet.yaml,sha256=yTxrWh7m4K3LnaNunETidfNzl6S4Bf58VIg9U38XShQ,648
|
15
|
+
neurostats_API/tools/cash_flow_percentage.yaml,sha256=fk2Z4eb1JjGFvP134eJatHacB7BgTkBenhDJr83w8RE,1345
|
16
|
+
neurostats_API/tools/finance_overview_dict.yaml,sha256=B9nV75StXkrF3yv2-eezzitlJ38eEK86RD_VY6588gQ,2884
|
17
|
+
neurostats_API/tools/profit_lose.yaml,sha256=dcO-0J0BC4p06XBNuowu8ux0NTbyZiOkGfy6szHF6fw,2402
|
18
|
+
neurostats_API/tools/seasonal_data_field_dict.txt,sha256=X8yc_el6p8BH_3FikTqBVFGsvWdXT6MHXLfKfi44334,8491
|
19
|
+
neurostats_API/utils/__init__.py,sha256=FTYKRFzW2XVXdnSHXnS3mQQaHlKF9xGqrMsgZZ2kroc,142
|
20
|
+
neurostats_API/utils/data_process.py,sha256=mDznLqAAZ7gFX3LlJkJvtrMPt38Lh5-NONqgnqT5tSY,5990
|
21
|
+
neurostats_API/utils/datetime.py,sha256=XJya4G8b_-ZOaBbMXgQjWh2MC4wc-o6goQ7EQJQMWrQ,773
|
22
|
+
neurostats_API/utils/db_client.py,sha256=OYe6yazcR4Aa6jYmy47JrryUeh2NnKGqY2K_lSZe6i8,455
|
23
|
+
neurostats_API/utils/fetcher.py,sha256=VbrUhjA-GG5AyjPX2SHtFIbZM4dm3jo0RgZzuCbb_Io,40927
|
24
|
+
neurostats_API-0.0.11.dist-info/METADATA,sha256=Tddw5SxRekTkTtemDXgYPoiJf9sxICyRkdlFAbvniSM,18529
|
25
|
+
neurostats_API-0.0.11.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
|
26
|
+
neurostats_API-0.0.11.dist-info/top_level.txt,sha256=nSlQPMG0VtXivJyedp4Bkf86EOy2TpW10VGxolXrqnU,15
|
27
|
+
neurostats_API-0.0.11.dist-info/RECORD,,
|
@@ -1,26 +0,0 @@
|
|
1
|
-
neurostats_API/__init__.py,sha256=9_jSwg7P5SlFv0Ci2ZSYBcAbygp9XV2C8sryRO8tvko,19
|
2
|
-
neurostats_API/cli.py,sha256=UJSWLIw03P24p-gkBb6JSEI5dW5U12UvLf1L8HjQD-o,873
|
3
|
-
neurostats_API/main.py,sha256=QcsfmWivg2Dnqw3MTJWiI0QvEiRs0VuH-BjwQHFCv00,677
|
4
|
-
neurostats_API/fetchers/__init__.py,sha256=U_OMG-mLpsVKYnCBrW2OjFuCzvPeVQ__7A676vGzztY,313
|
5
|
-
neurostats_API/fetchers/balance_sheet.py,sha256=VeWhd8Z2XZnL5RzxmenLzAd4eyK2sWTuiRGkqWsEmzk,5219
|
6
|
-
neurostats_API/fetchers/base.py,sha256=NW2SFzrimyAIrdJx1LVmTazelyZOAtcj54kJKHc4Vaw,1662
|
7
|
-
neurostats_API/fetchers/cash_flow.py,sha256=4G4SIUoBSwT-BePmz-SprQ0IJRL2QNWqWdQtlgaRKd4,7371
|
8
|
-
neurostats_API/fetchers/finance_overview.py,sha256=EVP7k0JkQq3ydXy0f3t2kzy12iIQEwDniTLn98qZ460,25637
|
9
|
-
neurostats_API/fetchers/month_revenue.py,sha256=QmhMAO8jbkjg2R1LR0TAPE3bmDnyuLNjnD24ZsFkTBU,3501
|
10
|
-
neurostats_API/fetchers/profit_lose.py,sha256=C0y42RBA-s20XcG6CJ10Rt6Gm_rB6lcvBmIzbTpn64o,5123
|
11
|
-
neurostats_API/fetchers/tech.py,sha256=wH1kkqiETQhF0HAhk-UIiucnZ3EiL85Q-yMWCcVOiFM,11395
|
12
|
-
neurostats_API/fetchers/value_invest.py,sha256=O5IKC8Nl7p5-E-1zoyAyWtiDznaxNemeabanmaHDdJs,3327
|
13
|
-
neurostats_API/tools/balance_sheet.yaml,sha256=dKTMbsYR9EFp48WAzmm_ISHMiJQLyE0V-XWS_gkxmr0,541
|
14
|
-
neurostats_API/tools/cash_flow_percentage.yaml,sha256=fk2Z4eb1JjGFvP134eJatHacB7BgTkBenhDJr83w8RE,1345
|
15
|
-
neurostats_API/tools/finance_overview_dict.yaml,sha256=URL1IFqO0j5uOwN3xETHriy_u9lYbLvdwghuznenP2Q,2500
|
16
|
-
neurostats_API/tools/profit_lose.yaml,sha256=qHBnqG7fR4Pxc_c3n4raL-3l7o5RnABLz9YGOXoaGiA,2086
|
17
|
-
neurostats_API/tools/seasonal_data_field_dict.txt,sha256=Za1fJR1yERbqrX8TgsS2kmMYMbaye43Gu_5ukUNBCNM,7904
|
18
|
-
neurostats_API/utils/__init__.py,sha256=FTYKRFzW2XVXdnSHXnS3mQQaHlKF9xGqrMsgZZ2kroc,142
|
19
|
-
neurostats_API/utils/data_process.py,sha256=m1B4EhCNSzOMfTBDtYCjkQSjbDTAEFC6TNf3NNxV36k,5657
|
20
|
-
neurostats_API/utils/datetime.py,sha256=XJya4G8b_-ZOaBbMXgQjWh2MC4wc-o6goQ7EQJQMWrQ,773
|
21
|
-
neurostats_API/utils/db_client.py,sha256=OYe6yazcR4Aa6jYmy47JrryUeh2NnKGqY2K_lSZe6i8,455
|
22
|
-
neurostats_API/utils/fetcher.py,sha256=VbrUhjA-GG5AyjPX2SHtFIbZM4dm3jo0RgZzuCbb_Io,40927
|
23
|
-
neurostats_API-0.0.9.dist-info/METADATA,sha256=z--BAc0e6HHBuXSQgc5ikwjPFzTfe-2o02gFLmgY_do,18232
|
24
|
-
neurostats_API-0.0.9.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
|
25
|
-
neurostats_API-0.0.9.dist-info/top_level.txt,sha256=nSlQPMG0VtXivJyedp4Bkf86EOy2TpW10VGxolXrqnU,15
|
26
|
-
neurostats_API-0.0.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|