neurostats-API 0.0.10__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.
@@ -1 +1 @@
1
- __version__='0.0.10'
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 = np.round(item, 2)
120
- if ("YoY" in item_name):
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 = np.round(item * 100, 2)
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,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
- table_dict[time_index][index_name][
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
- table_dict[time_index][index_name][
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]
@@ -156,6 +156,7 @@ class FinanceOverviewProcessor(StatsProcessor):
156
156
  finance_dict[index] = StatsProcessor.cal_non_percentage(finance_dict[index], postfix="千元")
157
157
  except Exception as e:
158
158
  finance_dict[index] = None
159
+
159
160
 
160
161
  @classmethod
161
162
  def process_all(cls, finance_dict):
@@ -176,9 +177,6 @@ class FinanceOverviewProcessor(StatsProcessor):
176
177
  cls.cal_net_debt_to_equity_ratio, cls.cal_interest_coverage_ratio,
177
178
  cls.cal_debt_to_operating_cash_flow,
178
179
  cls.cal_debt_to_free_cash_flow, cls.cal_cash_flow_ratio,
179
-
180
- # process to 千元
181
- cls.process_thousand_dollar
182
180
  ]
183
181
 
184
182
  for method in methods:
@@ -18,34 +18,33 @@ class InstitutionFetcher(StatsFetcher):
18
18
  """
19
19
 
20
20
  def __init__(self, ticker, db_client):
21
- raise(NotImplementedError("InstitutionFetcher : Not done yet"))
22
21
  super().__init__(ticker, db_client)
23
22
 
24
23
  def prepare_query(self, start_date, end_date):
25
24
  pipeline = super().prepare_query()
26
25
 
27
- target_query = {
28
- "date": date,
29
- "institution_trading": "$$target_season_data.institution_trading"
30
- }
31
-
26
+ # target_query = {
27
+ # "date": date,
28
+ # "institution_trading": "$$target_season_data.institution_trading"
29
+ # }
32
30
 
33
31
  pipeline.append({
34
32
  "$project": {
35
33
  "_id": 0,
36
34
  "ticker": 1,
37
35
  "company_name": 1,
38
- "profit_loses": {
36
+ "daily_data": {
39
37
  "$map": {
40
38
  "input": {
41
39
  "$filter": {
42
40
  "input": "$daily_data",
43
41
  "as": "daily",
44
42
  "cond": {
45
- "$and": [
46
- {"$gte": ["$$daily.date", start_date]},
47
- {"$lte": ["$$daily.date", end_date]}
48
- ]
43
+ "$and": [{
44
+ "$gte": ["$$daily.date", start_date]
45
+ }, {
46
+ "$lte": ["$$daily.date", end_date]
47
+ }]
49
48
  }
50
49
  }
51
50
  },
@@ -58,57 +57,158 @@ class InstitutionFetcher(StatsFetcher):
58
57
 
59
58
  return pipeline
60
59
 
61
- def collect_data(self, date):
62
- pipeline = self.prepare_query(date)
60
+ def collect_data(self, start_date, end_date):
61
+ pipeline = self.prepare_query(start_date, end_date)
63
62
 
64
63
  fetched_data = self.collection.aggregate(pipeline).to_list()
65
64
 
66
- return fetch_data[-1]
67
-
65
+ return fetched_data[-1]
66
+
68
67
  def query_data(self):
69
68
  try:
70
69
  latest_time = StatsDateTime.get_latest_time(
71
70
  self.ticker, self.collection)['last_update_time']
72
- latest_date = latest_time['daily_data']['institution_trading']['last_update']
73
- date = latest_date.replace(hour=0, minute=0, second=0, microsecond=0)
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)
74
77
  except Exception as e:
75
- print(f"No updated time for institution_trading in {self.ticker}, use current time instead")
78
+ print(
79
+ f"No updated time for institution_trading in {self.ticker}, use current time instead"
80
+ )
76
81
  date = datetime.now(self.timezone)
77
- date = date.replace(hour=0, minute=0, second=0, microsecond=0)
82
+ date = date.replace(hour=0, minute=0, second=0, microsecond=0)
78
83
 
79
84
  if (date.hour < 17): # 拿不到今天的資料
80
85
  date = date - timedelta(days=1)
81
-
82
- start_date = start_date - timedelta(days=365)
83
86
 
84
- daily_data = self.collect_data(date)
87
+ start_date = date - timedelta(days=365)
85
88
 
86
- daily_data = sorted(daily_data['daily_data'], key = lambda x : x['date'], reverse = True)
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
87
98
 
88
- self.process_data(self.ticker, daily_data)
89
-
90
99
  def process_data(self, daily_data):
91
100
  table_dict = dict()
92
101
 
93
- latest_data = daily_data[0]
102
+ latest_data = daily_data[0]
94
103
  yesterday_data = daily_data[1]
95
104
 
96
105
  # 交易價格與昨天交易
97
- table_dict = {
106
+ price_dict = {
98
107
  "open": latest_data['open'],
99
108
  'close': latest_data['close'],
100
- 'range': f"{latest_data['high']}-{latest_data['low']}",
101
- 'volumn': latest_data['volumn'] / 1000
102
-
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
103
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()
104
121
 
105
- # 今日法人買賣
106
-
107
- # 一年內法人
108
-
109
-
110
-
122
+ price_dict['52weeks_range'] = f"{lowest}-{highest}"
123
+ table_dict['price'] = price_dict
111
124
 
125
+ # 發行股數 & 市值
112
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
+ }
113
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)
114
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 = False)
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(month_revenue_df.columns, reverse = True)]
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")[["revenue", "revenue_increment_ratio", "YoY_1",
89
- "YoY_3", "YoY_5", "YoY_10"]].T
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")[["grand_total", "grand_total_increment_ratio",
93
- "grand_total_YoY_1", "grand_total_YoY_3",
94
- "grand_total_YoY_5", "grand_total_YoY_10"]].T
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 (item_name == 'percentage'):
118
+ if ('percentage' in item_name):
119
119
  if (isinstance(item, (float, int))):
120
- item = np.round(item, 2)
121
- if ('YoY' in item_name):
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 = np.round(item * 100, 2)
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: neurostats-API
3
- Version: 0.0.10
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
@@ -1,14 +1,14 @@
1
- neurostats_API/__init__.py,sha256=WzeHQJ3r8kPKWXSBuphad80I6bJ-GJORgQF6wSrYmhI,20
1
+ neurostats_API/__init__.py,sha256=oR5iCRZvbIRoODxS1VocreTo19N5L8Omvx_AgflzOO0,20
2
2
  neurostats_API/cli.py,sha256=UJSWLIw03P24p-gkBb6JSEI5dW5U12UvLf1L8HjQD-o,873
3
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=3FzVuDPm88tgljvu5gIxVXcZYQWebMrGnM5_ch9Vdgw,5549
4
+ neurostats_API/fetchers/__init__.py,sha256=27kdeBuM7dNBRcIyQ1u863CYw0P_DQz-I1G6iSFDq-c,357
5
+ neurostats_API/fetchers/balance_sheet.py,sha256=sQv4Gk5uoKURLEdh57YknOQWiyVwaXJ2Mw75jxNqUS0,5804
6
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=hmMurCSCEjYBQ6gRmVgoX6T57g8MjsdWec6LdVztVoE,27813
9
- neurostats_API/fetchers/institution.py,sha256=EYxPebJrcCMm7fW2nBlu4bVsksMMxgcQh16jJ1NxP6I,3384
10
- neurostats_API/fetchers/month_revenue.py,sha256=QmhMAO8jbkjg2R1LR0TAPE3bmDnyuLNjnD24ZsFkTBU,3501
11
- neurostats_API/fetchers/profit_lose.py,sha256=nc9YVi5kv3_loF8m82h3Fxpms7573_rPP9OM36bCK3A,5455
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
12
  neurostats_API/fetchers/tech.py,sha256=wH1kkqiETQhF0HAhk-UIiucnZ3EiL85Q-yMWCcVOiFM,11395
13
13
  neurostats_API/fetchers/value_invest.py,sha256=O5IKC8Nl7p5-E-1zoyAyWtiDznaxNemeabanmaHDdJs,3327
14
14
  neurostats_API/tools/balance_sheet.yaml,sha256=yTxrWh7m4K3LnaNunETidfNzl6S4Bf58VIg9U38XShQ,648
@@ -21,7 +21,7 @@ neurostats_API/utils/data_process.py,sha256=mDznLqAAZ7gFX3LlJkJvtrMPt38Lh5-NONqg
21
21
  neurostats_API/utils/datetime.py,sha256=XJya4G8b_-ZOaBbMXgQjWh2MC4wc-o6goQ7EQJQMWrQ,773
22
22
  neurostats_API/utils/db_client.py,sha256=OYe6yazcR4Aa6jYmy47JrryUeh2NnKGqY2K_lSZe6i8,455
23
23
  neurostats_API/utils/fetcher.py,sha256=VbrUhjA-GG5AyjPX2SHtFIbZM4dm3jo0RgZzuCbb_Io,40927
24
- neurostats_API-0.0.10.dist-info/METADATA,sha256=2zDomUXohUsLpnl4MeD6anZimrhnWvd8n0Rv8d4qkUk,18529
25
- neurostats_API-0.0.10.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
26
- neurostats_API-0.0.10.dist-info/top_level.txt,sha256=nSlQPMG0VtXivJyedp4Bkf86EOy2TpW10VGxolXrqnU,15
27
- neurostats_API-0.0.10.dist-info/RECORD,,
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,,