neurostats-API 0.0.6__py3-none-any.whl → 0.0.8__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1 @@
1
- __version__='0.0.6'
1
+ __version__='0.0.8'
@@ -1,3 +1,7 @@
1
1
  from .base import StatsDateTime, StatsFetcher
2
+ from .balance_sheet import BalanceSheetFetcher
3
+ from .cash_flow import CashFlowFetcher
2
4
  from .finance_overview import FinanceOverviewFetcher
5
+ from .month_revenue import MonthRevenueFetcher
6
+ from .profit_lose import ProfitLoseFetcher
3
7
  from .value_invest import ValueFetcher
@@ -0,0 +1,135 @@
1
+ from .base import StatsFetcher, StatsDateTime
2
+ import json
3
+ import numpy as np
4
+ import pandas as pd
5
+ from ..utils import StatsDateTime, StatsProcessor
6
+ import importlib.resources as pkg_resources
7
+ import yaml
8
+
9
+
10
+ class BalanceSheetFetcher(StatsFetcher):
11
+ """
12
+ 對應iFa.ai -> 財務分析 -> 資產負債表
13
+ """
14
+
15
+ def __init__(self, ticker, db_client):
16
+ super().__init__(ticker, db_client)
17
+ self.table_settings = StatsProcessor.load_yaml("balance_sheet.yaml")
18
+
19
+ def prepare_query(self, target_year, target_season):
20
+ pipeline = super().prepare_query()
21
+
22
+ target_query = {
23
+ "year": "$$target_season_data.year",
24
+ "season": "$$target_season_data.season",
25
+ "balance_sheet": "$$$$target_season_data.balance_sheet"
26
+ }
27
+
28
+ pipeline.append({
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
+ }
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"
55
+ }
56
+ }
57
+ },
58
+ "sortBy": {
59
+ "year": -1
60
+ } # 按 year 降序排序
61
+ }
62
+ }
63
+ }
64
+ })
65
+
66
+ return pipeline
67
+
68
+ def collect_data(self, target_year, target_season):
69
+ pipeline = self.prepare_query(target_year, target_season)
70
+
71
+ fetched_data = self.collection.aggregate(pipeline)
72
+
73
+ fetched_data = list(fetched_data)
74
+
75
+ return fetched_data[-1]
76
+
77
+ def query_data(self):
78
+ today = StatsDateTime.get_today()
79
+
80
+ year = today.year - 1 if (today.season == 1) else today.year
81
+ season = 4 if (today.season == 1) else today.season - 2
82
+ fetched_data = self.collect_data(year, season)
83
+
84
+ return self.process_data(season, fetched_data)
85
+
86
+ def process_data(self, target_season, fetched_data):
87
+ return_dict = {
88
+ "ticker": self.ticker,
89
+ "company_name": fetched_data['company_name']
90
+ }
91
+
92
+ index_names = []
93
+
94
+ table_dict = dict()
95
+
96
+ balance_sheets = fetched_data['balance_sheets']
97
+
98
+ # 將value與percentage跟著年分季度一筆筆取出
99
+ for data in balance_sheets:
100
+ year = data['year']
101
+
102
+ time_index = f"{year}Q{target_season}"
103
+
104
+ # 蒐集整體的keys
105
+ index_names += list(data['balance_sheet'].keys())
106
+ balance_sheet = data['balance_sheet']
107
+
108
+ for index_name, value_dict in balance_sheet.items():
109
+ for item_name, item in value_dict.items():
110
+ try: # table_dict[項目][(2020Q1, '%')]
111
+ if (item_name == 'percentage'):
112
+ if (isinstance(item, (float, int))):
113
+ item = np.round(item, 2)
114
+ if ("YoY" in item_name):
115
+ if (isinstance(item, (float, int))):
116
+ item = np.round(item * 100, 2)
117
+ table_dict[index_name][(time_index, item_name)] = item
118
+
119
+ except KeyError:
120
+ if (index_name not in table_dict.keys()):
121
+ table_dict[index_name] = dict()
122
+
123
+ table_dict[index_name][(time_index, item_name)] = item
124
+
125
+ total_table = pd.DataFrame.from_dict(table_dict, orient='index')
126
+ total_table.columns = pd.MultiIndex.from_tuples(total_table.columns)
127
+
128
+ for name, setting in self.table_settings.items():
129
+ return_dict[name] = StatsProcessor.slice_multi_col_table(
130
+ total_table=total_table,
131
+ mode=setting['mode'],
132
+ target_index=setting['target_index']
133
+ if "target_index" in setting.keys() else None)
134
+
135
+ return return_dict
@@ -0,0 +1,184 @@
1
+ from .base import StatsFetcher, StatsDateTime
2
+ import json
3
+ import numpy as np
4
+ import pandas as pd
5
+ from ..utils import StatsDateTime, StatsProcessor
6
+ import importlib.resources as pkg_resources
7
+ import yaml
8
+
9
+ class CashFlowFetcher(StatsFetcher):
10
+ def __init__(self, ticker, db_client):
11
+ super().__init__(ticker, db_client)
12
+
13
+ self.cash_flow_dict = StatsProcessor.load_yaml(
14
+ "cash_flow_percentage.yaml"
15
+ ) # 計算子表格用
16
+
17
+ def prepare_query(self, target_season):
18
+ pipeline = super().prepare_query()
19
+
20
+ pipeline.append({
21
+ "$project": {
22
+ "_id": 0,
23
+ "ticker": 1,
24
+ "company_name": 1,
25
+ "cash_flows": {
26
+ "$sortArray": {
27
+ "input": {
28
+ "$map": {
29
+ "input": {
30
+ "$filter": {
31
+ "input": "$seasonal_data",
32
+ "as": "season",
33
+ "cond": {
34
+ "$eq":
35
+ ["$$season.season", target_season]
36
+ }
37
+ }
38
+ },
39
+ "as": "target_season_data",
40
+ "in": {
41
+ "year":
42
+ "$$target_season_data.year",
43
+ "season":
44
+ "$$target_season_data.season",
45
+ "cash_flow":
46
+ "$$target_season_data.cash_flow"
47
+ }
48
+ }
49
+ },
50
+ "sortBy": {
51
+ "year": -1
52
+ } # 按 year 降序排序
53
+ }
54
+ }
55
+ }
56
+ })
57
+
58
+ return pipeline
59
+
60
+ def collect_data(self, target_season):
61
+ pipeline = self.prepare_query(target_season)
62
+
63
+ fetched_data = self.collection.aggregate(pipeline)
64
+
65
+ return list(fetched_data)[0]
66
+
67
+ def query_data(self):
68
+ today = StatsDateTime.get_today()
69
+
70
+ target_season = today.season - 1 if (today.season > 1) else 4
71
+
72
+ fetched_data = self.collect_data(target_season)
73
+
74
+ return self.process_data(fetched_data, target_season)
75
+
76
+ def process_data(self, fetched_data, target_season):
77
+ """
78
+ 處理現金流量表頁面的所有表格
79
+ 金流表本身沒有比例 但是Ifa有算,
80
+ 項目所屬的情況也不一(分別所屬營業,投資,籌資三個活動)
81
+ 所以這裡選擇不用slicing處理
82
+ """
83
+ cash_flows = fetched_data['cash_flows']
84
+
85
+ index_names = []
86
+ column_names = []
87
+
88
+ table_dict = dict()
89
+ CASHO_dict = dict()
90
+ CASHI_dict = dict()
91
+ CASHF_dict = dict()
92
+
93
+ return_dict = {
94
+ "ticker": fetched_data['ticker'],
95
+ "company_name": fetched_data['company_name'],
96
+ "cash_flow": dict(),
97
+ "CASHO": dict(),
98
+ "CASHI": dict(),
99
+ "CASHF": dict()
100
+ }
101
+
102
+ checkpoints = ["營業活動之現金流量-間接法", "投資活動之現金流量", "籌資活動之現金流量", "匯率變動對現金及約當現金之影響"]
103
+ main_cash_flows = [
104
+ "營業活動之淨現金流入(流出)", "投資活動之淨現金流入(流出)", "籌資活動之淨現金流入(流出)", None
105
+ ] # 主要的比例對象
106
+ partial_cash_flows = [CASHO_dict, CASHI_dict, CASHF_dict, dict()]
107
+
108
+ # 作法: dictionary中也有checkpoints,如果出現了就換下一個index去計算
109
+
110
+ for data in cash_flows:
111
+ year = data['year']
112
+
113
+ time_index = f"{year}Q{target_season}"
114
+
115
+ cash_flow = data['cash_flow']
116
+ main_cash_flow_name = None
117
+ partial_cash_flow = None
118
+ next_checkpoint = 0
119
+
120
+ for index_name, value in cash_flow.items():
121
+ if (next_checkpoint < 3
122
+ and index_name == checkpoints[next_checkpoint]): # 找到了主要的變動點
123
+ main_cash_flow_name = main_cash_flows[next_checkpoint]
124
+ partial_cash_flow = partial_cash_flows[next_checkpoint]
125
+ next_checkpoint += 1
126
+ try:
127
+ table_dict[time_index][index_name]['value'] = value[
128
+ 'value']
129
+ if (value['value']):
130
+ table_dict[time_index][index_name][
131
+ 'percentage'] = np.round(
132
+ (value['value'] / cash_flow[
133
+ main_cash_flow_name]['value']) * 100, 2)
134
+ else:
135
+ table_dict[time_index][index_name][
136
+ 'percentage'] = None
137
+ except:
138
+ if (time_index not in table_dict.keys()):
139
+ table_dict[time_index] = dict()
140
+ table_dict[time_index][index_name] = dict()
141
+
142
+ table_dict[time_index][index_name]['value'] = value[
143
+ 'value']
144
+ if (value['value']):
145
+ table_dict[time_index][index_name][
146
+ 'percentage'] = np.round(
147
+ (value['value'] / cash_flow[
148
+ main_cash_flow_name]['value']) * 100, 2)
149
+ else:
150
+ table_dict[time_index][index_name][
151
+ 'percentage'] = None
152
+
153
+ try:
154
+ partial_cash_flow[time_index][index_name] = table_dict[
155
+ time_index][index_name]
156
+ except:
157
+ if (time_index not in partial_cash_flow.keys()):
158
+ partial_cash_flow[time_index] = dict()
159
+ partial_cash_flow[time_index][index_name] = table_dict[
160
+ time_index][index_name]
161
+
162
+ index_names += list(cash_flow.keys())
163
+
164
+ # 轉成dictionary keys
165
+ index_names = list(dict.fromkeys(index_names))
166
+
167
+ cash_flow_table = pd.DataFrame(table_dict)
168
+ cash_flow_table = StatsProcessor.expand_value_percentage(cash_flow_table)
169
+
170
+ CASHO_table = pd.DataFrame(CASHO_dict)
171
+ CASHO_table = StatsProcessor.expand_value_percentage(CASHO_table)
172
+
173
+ CASHI_table = pd.DataFrame(CASHI_dict)
174
+ CASHI_table = StatsProcessor.expand_value_percentage(CASHI_table)
175
+
176
+ CASHF_table = pd.DataFrame(CASHF_dict)
177
+ CASHF_table = StatsProcessor.expand_value_percentage(CASHF_table)
178
+
179
+ return_dict['cash_flow'] = cash_flow_table
180
+ return_dict['CASHO'] = CASHO_table
181
+ return_dict['CASHI'] = CASHI_table
182
+ return_dict['CASHF'] = CASHF_table
183
+
184
+ return return_dict