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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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