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