neurostats-API 0.0.11__py3-none-any.whl → 0.0.13__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/institution.py +132 -53
- neurostats_API/fetchers/margin_trading.py +279 -0
- neurostats_API/fetchers/value_invest.py +72 -0
- neurostats_API/utils/data_process.py +15 -0
- {neurostats_API-0.0.11.dist-info → neurostats_API-0.0.13.dist-info}/METADATA +250 -5
- {neurostats_API-0.0.11.dist-info → neurostats_API-0.0.13.dist-info}/RECORD +10 -9
- {neurostats_API-0.0.11.dist-info → neurostats_API-0.0.13.dist-info}/WHEEL +0 -0
- {neurostats_API-0.0.11.dist-info → neurostats_API-0.0.13.dist-info}/top_level.txt +0 -0
neurostats_API/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__='0.0.
|
1
|
+
__version__='0.0.13'
|
@@ -3,6 +3,7 @@ from .balance_sheet import BalanceSheetFetcher
|
|
3
3
|
from .cash_flow import CashFlowFetcher
|
4
4
|
from .finance_overview import FinanceOverviewFetcher
|
5
5
|
from .institution import InstitutionFetcher
|
6
|
+
from .margin_trading import MarginTradingFetcher
|
6
7
|
from .month_revenue import MonthRevenueFetcher
|
7
8
|
from .profit_lose import ProfitLoseFetcher
|
8
9
|
from .value_invest import ValueFetcher
|
@@ -51,6 +51,27 @@ class InstitutionFetcher(StatsFetcher):
|
|
51
51
|
"as": "target_daily_data",
|
52
52
|
"in": "$$target_daily_data"
|
53
53
|
}
|
54
|
+
},
|
55
|
+
"institution_trading": {
|
56
|
+
"$map": {
|
57
|
+
"input": {
|
58
|
+
"$filter": {
|
59
|
+
"input": "$institution_trading",
|
60
|
+
"as": "institution",
|
61
|
+
"cond": {
|
62
|
+
"$and": [{
|
63
|
+
"$gte":
|
64
|
+
["$$institution.date", start_date]
|
65
|
+
}, {
|
66
|
+
"$lte":
|
67
|
+
["$$institution.date", end_date]
|
68
|
+
}]
|
69
|
+
}
|
70
|
+
}
|
71
|
+
},
|
72
|
+
"as": "target_institution_data",
|
73
|
+
"in": "$$target_institution_data"
|
74
|
+
},
|
54
75
|
}
|
55
76
|
}
|
56
77
|
})
|
@@ -68,81 +89,110 @@ class InstitutionFetcher(StatsFetcher):
|
|
68
89
|
try:
|
69
90
|
latest_time = StatsDateTime.get_latest_time(
|
70
91
|
self.ticker, self.collection)['last_update_time']
|
71
|
-
latest_date = latest_time['institution_trading'][
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
microsecond=0)
|
92
|
+
latest_date = latest_time['institution_trading']['latest_date']
|
93
|
+
end_date = latest_date.replace(hour=0,
|
94
|
+
minute=0,
|
95
|
+
second=0,
|
96
|
+
microsecond=0)
|
77
97
|
except Exception as e:
|
78
98
|
print(
|
79
99
|
f"No updated time for institution_trading in {self.ticker}, use current time instead"
|
80
100
|
)
|
81
|
-
|
82
|
-
|
101
|
+
end_date = datetime.now(self.timezone)
|
102
|
+
end_date = date.replace(hour=0, minute=0, second=0, microsecond=0)
|
83
103
|
|
84
104
|
if (date.hour < 17): # 拿不到今天的資料
|
85
|
-
|
105
|
+
end_date = end_date - timedelta(days=1)
|
86
106
|
|
87
|
-
start_date =
|
107
|
+
start_date = end_date - timedelta(days=365)
|
88
108
|
|
89
|
-
|
109
|
+
fetched_data = self.collect_data(start_date, end_date)
|
90
110
|
|
91
|
-
daily_data = sorted(
|
92
|
-
|
93
|
-
|
111
|
+
fetched_data['daily_data'] = sorted(fetched_data['daily_data'],
|
112
|
+
key=lambda x: x['date'],
|
113
|
+
reverse=True)
|
114
|
+
fetched_data['institution_trading'] = sorted(
|
115
|
+
fetched_data['institution_trading'],
|
116
|
+
key=lambda x: x['date'],
|
117
|
+
reverse=True)
|
94
118
|
|
95
|
-
table_dict = self.process_data(
|
119
|
+
table_dict = self.process_data(fetched_data)
|
96
120
|
|
97
121
|
return table_dict
|
98
122
|
|
99
|
-
def process_data(self,
|
123
|
+
def process_data(self, fetched_data):
|
100
124
|
table_dict = dict()
|
101
125
|
|
102
|
-
|
103
|
-
|
126
|
+
daily_datas = fetched_data['daily_data']
|
127
|
+
institution_tradings = fetched_data['institution_trading']
|
128
|
+
|
129
|
+
latest_daily_data = daily_datas[0]
|
130
|
+
yesterday_daily_data = daily_datas[1]
|
104
131
|
|
105
132
|
# 交易價格與昨天交易
|
106
133
|
price_dict = {
|
107
|
-
"open":
|
108
|
-
'close':
|
109
|
-
'range':
|
110
|
-
'
|
111
|
-
'
|
112
|
-
'
|
113
|
-
'
|
114
|
-
'
|
134
|
+
"open": latest_daily_data['open'],
|
135
|
+
'close': latest_daily_data['close'],
|
136
|
+
'range':
|
137
|
+
f"{latest_daily_data['low']} - {latest_daily_data['high']}",
|
138
|
+
'volume': latest_daily_data['volume'] / 1000,
|
139
|
+
'last_open': yesterday_daily_data['open'],
|
140
|
+
'last_close': yesterday_daily_data['close'],
|
141
|
+
'last_range':
|
142
|
+
f"{yesterday_daily_data['low']} - {yesterday_daily_data['high']}",
|
143
|
+
'last_volume': yesterday_daily_data['volume'] / 1000
|
115
144
|
}
|
116
145
|
# 一年範圍
|
117
|
-
annual_lows = [data['low'] for data in
|
118
|
-
annual_highs = [data['high'] for data in
|
146
|
+
annual_lows = [data['low'] for data in daily_datas]
|
147
|
+
annual_highs = [data['high'] for data in daily_datas]
|
119
148
|
lowest = np.min(annual_lows).item()
|
120
149
|
highest = np.max(annual_highs).item()
|
121
150
|
|
122
|
-
price_dict['52weeks_range'] = f"{lowest}-{highest}"
|
151
|
+
price_dict['52weeks_range'] = f"{lowest} - {highest}"
|
123
152
|
table_dict['price'] = price_dict
|
124
153
|
|
125
154
|
# 發行股數 & 市值
|
155
|
+
# 沒有實作
|
126
156
|
|
127
157
|
# 今日法人買賣
|
158
|
+
latest_trading = institution_tradings[0]
|
128
159
|
table_dict['latest_trading'] = {
|
129
160
|
"date":
|
130
|
-
|
161
|
+
latest_trading['date'],
|
131
162
|
"table":
|
132
|
-
self.process_latest_trading(
|
163
|
+
self.process_latest_trading(latest_trading,
|
164
|
+
latest_daily_data['volume'])
|
133
165
|
}
|
134
166
|
# 一年內法人
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
167
|
+
annual_dates = [data['date'].strftime("%Y-%m-%d") for data in daily_datas]
|
168
|
+
annual_closes = {
|
169
|
+
data['date'].strftime("%Y-%m-%d") : data['close']
|
170
|
+
for data in daily_datas
|
171
|
+
if (data['date'].strftime("%Y-%m-%d") in annual_dates)
|
172
|
+
}
|
173
|
+
annual_volumes = {
|
174
|
+
data['date'].strftime("%Y-%m-%d") : data['volume']
|
175
|
+
for data in daily_datas
|
176
|
+
if (data['date'].strftime("%Y-%m-%d") in annual_dates)
|
177
|
+
}
|
178
|
+
annual_trading = {
|
179
|
+
data['date'].strftime("%Y-%m-%d") : data
|
180
|
+
for data in institution_tradings
|
181
|
+
}
|
182
|
+
|
183
|
+
annual_trading = {
|
184
|
+
date: {
|
185
|
+
|
186
|
+
"close": annual_closes[date],
|
187
|
+
"volume": annual_volumes[date],
|
188
|
+
**annual_trading[date]
|
139
189
|
}
|
140
|
-
for
|
141
|
-
|
142
|
-
|
190
|
+
for date in annual_dates
|
191
|
+
}
|
192
|
+
|
143
193
|
table_dict['annual_trading'] = self.process_annual_trading(
|
144
194
|
annual_dates, annual_trading)
|
145
|
-
|
195
|
+
|
146
196
|
return table_dict
|
147
197
|
|
148
198
|
def process_latest_trading(self, latest_trading, volume):
|
@@ -150,34 +200,61 @@ class InstitutionFetcher(StatsFetcher):
|
|
150
200
|
"foreign": self.default_institution_chart(),
|
151
201
|
"mutual": self.default_institution_chart(),
|
152
202
|
"prop": self.default_institution_chart(),
|
153
|
-
"institutional_investor":self.default_institution_chart(),
|
203
|
+
"institutional_investor": self.default_institution_chart(),
|
154
204
|
}
|
155
205
|
|
156
206
|
for key in latest_trading.keys():
|
157
207
|
if (key.find("外陸資") >= 0 or key.find("外資") >= 0):
|
158
|
-
self.target_institution(latest_trading,
|
208
|
+
self.target_institution(latest_trading,
|
209
|
+
latest_table['foreign'], key, volume)
|
159
210
|
elif (key.find("自營商") >= 0):
|
160
|
-
self.target_institution(latest_trading,latest_table['prop'],
|
211
|
+
self.target_institution(latest_trading, latest_table['prop'],
|
212
|
+
key, volume)
|
161
213
|
elif (key.find("投信") >= 0):
|
162
|
-
self.target_institution(latest_trading,latest_table['mutual'],
|
214
|
+
self.target_institution(latest_trading, latest_table['mutual'],
|
215
|
+
key, volume)
|
163
216
|
elif (key.find("三大法人") >= 0):
|
164
|
-
self.target_institution(latest_trading,
|
217
|
+
self.target_institution(latest_trading,
|
218
|
+
latest_table['institutional_investor'],
|
219
|
+
key, volume)
|
220
|
+
|
221
|
+
for trade_type in ['buy', 'sell']:
|
222
|
+
for unit in ['stock', 'percentage']:
|
223
|
+
latest_table['institutional_investor'][trade_type][
|
224
|
+
unit] = (latest_table['foreign'][trade_type][unit] +
|
225
|
+
latest_table['prop'][trade_type][unit] +
|
226
|
+
latest_table['mutual'][trade_type][unit])
|
165
227
|
|
166
228
|
frames = []
|
167
229
|
for category, trades in latest_table.items():
|
168
230
|
temp_df = pd.DataFrame(trades).T
|
169
231
|
temp_df['category'] = category
|
170
232
|
frames.append(temp_df)
|
171
|
-
|
233
|
+
|
172
234
|
latest_df = pd.concat(frames)
|
173
235
|
latest_df = latest_df.reset_index().rename(columns={'index': 'type'})
|
174
|
-
latest_df = latest_df[[
|
236
|
+
latest_df = latest_df[[
|
237
|
+
'type', 'category', 'stock', 'price', 'average_price', 'percentage'
|
238
|
+
]]
|
239
|
+
|
240
|
+
latest_df = pd.melt(latest_df,
|
241
|
+
id_vars=['type', 'category'],
|
242
|
+
var_name='variable',
|
243
|
+
value_name='value')
|
244
|
+
|
245
|
+
latest_df = latest_df.pivot_table(index=['category', 'variable'],
|
246
|
+
columns='type',
|
247
|
+
values='value',
|
248
|
+
aggfunc='first')
|
249
|
+
|
250
|
+
# 重設列名,去除多層索引
|
251
|
+
latest_df.columns.name = None # 去除列名稱
|
252
|
+
latest_df = latest_df.reset_index()
|
175
253
|
|
176
254
|
return latest_df
|
177
255
|
|
178
256
|
def process_annual_trading(self, dates, annual_tradings):
|
179
|
-
|
180
|
-
return pd.DataFrame(annual_tradings, index=dates)
|
257
|
+
return pd.DataFrame.from_dict(annual_tradings, orient='index')
|
181
258
|
|
182
259
|
def target_institution(self, old_table, new_table, key, volume):
|
183
260
|
if (key.find("買進") >= 0):
|
@@ -185,12 +262,14 @@ class InstitutionFetcher(StatsFetcher):
|
|
185
262
|
elif (key.find("賣出") >= 0):
|
186
263
|
self.cal_institution(old_table, new_table['sell'], key, volume)
|
187
264
|
elif (key.find("買賣超") >= 0):
|
188
|
-
self.cal_institution(old_table, new_table['over_buy_sell'], key,
|
189
|
-
|
265
|
+
self.cal_institution(old_table, new_table['over_buy_sell'], key,
|
266
|
+
volume)
|
267
|
+
|
190
268
|
def cal_institution(self, old_table, new_table, key, volume):
|
191
269
|
new_table['stock'] = np.round(old_table[key] / 1000, 2).item()
|
192
|
-
new_table['percentage'] = np.round((old_table[key] / volume) * 100,
|
193
|
-
|
270
|
+
new_table['percentage'] = np.round((old_table[key] / volume) * 100,
|
271
|
+
2).item()
|
272
|
+
|
194
273
|
def default_institution_chart(self):
|
195
274
|
return {
|
196
275
|
"buy": {
|
@@ -211,4 +290,4 @@ class InstitutionFetcher(StatsFetcher):
|
|
211
290
|
"average_price": 0,
|
212
291
|
"percentage": 0
|
213
292
|
},
|
214
|
-
}
|
293
|
+
}
|
@@ -0,0 +1,279 @@
|
|
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 MarginTradingFetcher(StatsFetcher):
|
12
|
+
|
13
|
+
def __init__(self, ticker, db_client):
|
14
|
+
"""
|
15
|
+
iFa -> 交易資訊 -> 資券變化
|
16
|
+
|
17
|
+
包括:
|
18
|
+
1. 當日交易
|
19
|
+
2. 一年內交易
|
20
|
+
"""
|
21
|
+
super().__init__(ticker, db_client)
|
22
|
+
|
23
|
+
def prepare_query(self, start_date, end_date):
|
24
|
+
pipeline = super().prepare_query()
|
25
|
+
|
26
|
+
pipeline.append({
|
27
|
+
"$project": {
|
28
|
+
"_id": 0,
|
29
|
+
"ticker": 1,
|
30
|
+
"company_name": 1,
|
31
|
+
"daily_data": {
|
32
|
+
"$map": {
|
33
|
+
"input": {
|
34
|
+
"$filter": {
|
35
|
+
"input": "$daily_data",
|
36
|
+
"as": "daliy",
|
37
|
+
"cond": {
|
38
|
+
"$and": [{
|
39
|
+
"$gte": ["$$daliy.date", start_date]
|
40
|
+
}, {
|
41
|
+
"$lte": ["$$daliy.date", end_date]
|
42
|
+
}]
|
43
|
+
}
|
44
|
+
}
|
45
|
+
},
|
46
|
+
"as": "target_daliy_data",
|
47
|
+
"in": "$$target_daliy_data"
|
48
|
+
}
|
49
|
+
},
|
50
|
+
"margin_trading": {
|
51
|
+
"$map": {
|
52
|
+
"input": {
|
53
|
+
"$filter": {
|
54
|
+
"input": "$margin_trading",
|
55
|
+
"as": "margin",
|
56
|
+
"cond": {
|
57
|
+
"$and": [{
|
58
|
+
"$gte": ["$$margin.date", start_date]
|
59
|
+
}, {
|
60
|
+
"$lte": ["$$margin.date", end_date]
|
61
|
+
}]
|
62
|
+
}
|
63
|
+
}
|
64
|
+
},
|
65
|
+
"as": "target_margin_data",
|
66
|
+
"in": "$$target_margin_data"
|
67
|
+
}
|
68
|
+
},
|
69
|
+
"security_lending": {
|
70
|
+
"$map": {
|
71
|
+
"input": {
|
72
|
+
"$filter": {
|
73
|
+
"input": "$security_lending",
|
74
|
+
"as": "lending",
|
75
|
+
"cond": {
|
76
|
+
"$and": [{
|
77
|
+
"$gte": ["$$lending.date", start_date]
|
78
|
+
}, {
|
79
|
+
"$lte": ["$$lending.date", end_date]
|
80
|
+
}]
|
81
|
+
}
|
82
|
+
}
|
83
|
+
},
|
84
|
+
"as": "target_lending_data",
|
85
|
+
"in": "$$target_lending_data"
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
})
|
90
|
+
|
91
|
+
return pipeline
|
92
|
+
|
93
|
+
def collect_data(self, start_date, end_date):
|
94
|
+
pipeline = self.prepare_query(start_date, end_date)
|
95
|
+
|
96
|
+
fetched_data = self.collection.aggregate(pipeline).to_list()
|
97
|
+
|
98
|
+
return fetched_data[-1]
|
99
|
+
|
100
|
+
def query_data(self):
|
101
|
+
try:
|
102
|
+
latest_time = StatsDateTime.get_latest_time(
|
103
|
+
self.ticker, self.collection)['last_update_time']
|
104
|
+
latest_date = latest_time['margin_trading']['latest_date']
|
105
|
+
end_date = latest_date.replace(hour=0,
|
106
|
+
minute=0,
|
107
|
+
second=0,
|
108
|
+
microsecond=0)
|
109
|
+
except Exception as e:
|
110
|
+
print(
|
111
|
+
f"No updated time for institution_trading in {self.ticker}, use current time instead"
|
112
|
+
)
|
113
|
+
end_date = datetime.now(self.timezone)
|
114
|
+
end_date = end_date.replace(hour=0,
|
115
|
+
minute=0,
|
116
|
+
second=0,
|
117
|
+
microsecond=0)
|
118
|
+
|
119
|
+
if (end_date.hour < 22): # 拿不到今天的資料
|
120
|
+
end_date = end_date - timedelta(days=1)
|
121
|
+
|
122
|
+
start_date = end_date - timedelta(days=365)
|
123
|
+
|
124
|
+
fetched_data = self.collect_data(start_date, end_date)
|
125
|
+
|
126
|
+
fetched_data['daily_data'] = sorted(fetched_data['daily_data'],
|
127
|
+
key=lambda x: x['date'],
|
128
|
+
reverse=True)
|
129
|
+
fetched_data['margin_trading'] = sorted(fetched_data['margin_trading'],
|
130
|
+
key=lambda x: x['date'],
|
131
|
+
reverse=True)
|
132
|
+
fetched_data['security_lending'] = sorted(
|
133
|
+
fetched_data['security_lending'],
|
134
|
+
key=lambda x: x['date'],
|
135
|
+
reverse=True)
|
136
|
+
|
137
|
+
table_dict = self.process_data(fetched_data)
|
138
|
+
|
139
|
+
return table_dict
|
140
|
+
|
141
|
+
def process_data(self, fetched_data):
|
142
|
+
return_dict = dict()
|
143
|
+
|
144
|
+
daily_datas = fetched_data['daily_data']
|
145
|
+
latest_data = fetched_data['daily_data'][0]
|
146
|
+
yesterday_data = fetched_data['daily_data'][1]
|
147
|
+
|
148
|
+
# 交易價格與昨天交易
|
149
|
+
price_dict = {
|
150
|
+
"open": latest_data['open'],
|
151
|
+
'close': latest_data['close'],
|
152
|
+
'range': f"{latest_data['low']} - {latest_data['high']}",
|
153
|
+
'volume': latest_data['volume'] / 1000,
|
154
|
+
'last_open': yesterday_data['open'],
|
155
|
+
'last_close': yesterday_data['close'],
|
156
|
+
'last_range':
|
157
|
+
f"{yesterday_data['low']} - {yesterday_data['high']}",
|
158
|
+
'last_volume': yesterday_data['volume'] / 1000
|
159
|
+
}
|
160
|
+
annual_lows = [data['low'] for data in daily_datas]
|
161
|
+
annual_highs = [data['high'] for data in daily_datas]
|
162
|
+
lowest = np.min(annual_lows).item()
|
163
|
+
highest = np.max(annual_highs).item()
|
164
|
+
price_dict['52weeks_range'] = f"{lowest} - {highest}"
|
165
|
+
|
166
|
+
return_dict['price'] = price_dict
|
167
|
+
|
168
|
+
# 當日交易
|
169
|
+
margin_trading = fetched_data['margin_trading']
|
170
|
+
security_lending = fetched_data['security_lending']
|
171
|
+
|
172
|
+
latest_margin_date = margin_trading[0]['date']
|
173
|
+
latest_lending_date = security_lending[0]['date']
|
174
|
+
## 融資融券
|
175
|
+
### 先將所有現金償還與現券償還改成現償
|
176
|
+
for trading in margin_trading:
|
177
|
+
trading['financing']['現償'] = trading['financing'].pop('現金償還')
|
178
|
+
trading['short_selling']['現償'] = trading['short_selling'].pop(
|
179
|
+
'現券償還')
|
180
|
+
### 轉換
|
181
|
+
latest_margin_trading = margin_trading[0]
|
182
|
+
latest_margin_trading_df = {
|
183
|
+
category: sub_dict
|
184
|
+
for category, sub_dict in latest_margin_trading.items()
|
185
|
+
if (isinstance(sub_dict, dict))
|
186
|
+
}
|
187
|
+
latest_margin_trading_df = pd.DataFrame.from_dict(
|
188
|
+
latest_margin_trading_df)
|
189
|
+
|
190
|
+
## 借券表格
|
191
|
+
latest_stock_lending = security_lending[0]['stock_lending']
|
192
|
+
|
193
|
+
latest_stock_lending = {
|
194
|
+
type_name: StatsProcessor.cal_round_int(value / 1000)
|
195
|
+
for type_name, value in latest_stock_lending.items()
|
196
|
+
}
|
197
|
+
latest_stock_lending.pop("前日餘額")
|
198
|
+
latest_stock_lending_df = pd.DataFrame.from_dict(latest_stock_lending,
|
199
|
+
orient="index",
|
200
|
+
columns=['stock_lending'])
|
201
|
+
|
202
|
+
latest_dict = {
|
203
|
+
"date": latest_margin_date,
|
204
|
+
"margin_trading": latest_margin_trading_df,
|
205
|
+
"stock_lending": latest_stock_lending_df,
|
206
|
+
"security_offset": latest_margin_trading['資券互抵']
|
207
|
+
}
|
208
|
+
|
209
|
+
return_dict['latest_trading'] = latest_dict
|
210
|
+
|
211
|
+
# 一年內
|
212
|
+
annual_dates = [
|
213
|
+
data['date'].strftime('%Y-%m-%d')
|
214
|
+
for data in fetched_data['margin_trading']
|
215
|
+
]
|
216
|
+
close_prices = {
|
217
|
+
data['date'].strftime('%Y-%m-%d'): data['close']
|
218
|
+
for data in fetched_data['daily_data']
|
219
|
+
if data['date'].strftime('%Y-%m-%d') in annual_dates
|
220
|
+
}
|
221
|
+
volumes = {
|
222
|
+
data['date'].strftime('%Y-%m-%d'):
|
223
|
+
StatsProcessor.cal_round_int(data['volume'] / 1000)
|
224
|
+
for data in fetched_data['daily_data']
|
225
|
+
if data['date'].strftime('%Y-%m-%d') in annual_dates
|
226
|
+
}
|
227
|
+
|
228
|
+
## 融資融券
|
229
|
+
financings = {
|
230
|
+
data['date'].strftime("%Y-%m-%d"): {
|
231
|
+
f"融資_{type_name}": num_of_stocks
|
232
|
+
for type_name, num_of_stocks in data['financing'].items()
|
233
|
+
}
|
234
|
+
for data in fetched_data['margin_trading']
|
235
|
+
}
|
236
|
+
|
237
|
+
short_sellings = {
|
238
|
+
data['date'].strftime("%Y-%m-%d"): {
|
239
|
+
f"融券_{type_name}": num_of_stocks
|
240
|
+
for type_name, num_of_stocks in data['short_selling'].items()
|
241
|
+
}
|
242
|
+
for data in fetched_data['margin_trading']
|
243
|
+
}
|
244
|
+
|
245
|
+
### 資券互抵
|
246
|
+
security_offsets = {
|
247
|
+
data['date'].strftime("%Y-%m-%d"): data['資券互抵']
|
248
|
+
for data in fetched_data['margin_trading']
|
249
|
+
}
|
250
|
+
|
251
|
+
## 借券(stock lendings)
|
252
|
+
stock_lendings = {
|
253
|
+
data['date'].strftime('%Y-%m-%d'): {
|
254
|
+
f"借券_{type_name}":
|
255
|
+
(num_of_stocks /
|
256
|
+
1000) if isinstance(num_of_stocks,
|
257
|
+
(int, float)) else num_of_stocks
|
258
|
+
for type_name, num_of_stocks in data['stock_lending'].items()
|
259
|
+
}
|
260
|
+
for data in fetched_data['security_lending']
|
261
|
+
}
|
262
|
+
|
263
|
+
annual_dict = {
|
264
|
+
date: {
|
265
|
+
"close": close_prices[date],
|
266
|
+
"volume": volumes[date],
|
267
|
+
**financings[date],
|
268
|
+
**short_sellings[date],
|
269
|
+
**stock_lendings[date],
|
270
|
+
"資券互抵":security_offsets[date]
|
271
|
+
}
|
272
|
+
for date in annual_dates
|
273
|
+
}
|
274
|
+
|
275
|
+
annual_table = pd.DataFrame.from_dict(annual_dict)
|
276
|
+
|
277
|
+
return_dict['annual_margin'] = annual_table.T
|
278
|
+
|
279
|
+
return return_dict
|
@@ -79,6 +79,78 @@ class ValueFetcher(StatsFetcher):
|
|
79
79
|
)
|
80
80
|
|
81
81
|
return fetched_data
|
82
|
+
|
83
|
+
def query_value_serie(self):
|
84
|
+
"""
|
85
|
+
回傳指定公司的歷來評價
|
86
|
+
return : Dict[pd.DataFrame]
|
87
|
+
Dict中包含以下八個key, 每個key對應DataFrame
|
88
|
+
{
|
89
|
+
P_E,
|
90
|
+
P_FCF,
|
91
|
+
P_S,
|
92
|
+
P_B,
|
93
|
+
EV_OPI,
|
94
|
+
EV_EBIT,
|
95
|
+
EV_EBITDA,
|
96
|
+
EV_S
|
97
|
+
}
|
98
|
+
"""
|
99
|
+
|
100
|
+
pipeline = [
|
101
|
+
{
|
102
|
+
"$match": {
|
103
|
+
"ticker": self.ticker,
|
104
|
+
}
|
105
|
+
},
|
106
|
+
{
|
107
|
+
"$project": {
|
108
|
+
"_id": 0,
|
109
|
+
"ticker": 1,
|
110
|
+
"company_name": 1,
|
111
|
+
"daily_data": {
|
112
|
+
"$map": {
|
113
|
+
"input": "$daily_data", # 正確地指定要處理的陣列
|
114
|
+
"as": "daily", # 每個元素的名稱
|
115
|
+
"in": {
|
116
|
+
"date": "$$daily.date",
|
117
|
+
"P_E": "$$daily.P_E",
|
118
|
+
"P_FCF": "$$daily.P_FCF",
|
119
|
+
"P_B": "$$daily.P_B",
|
120
|
+
"P_S": "$$daily.P_S",
|
121
|
+
"EV_OPI": "$$daily.EV_OPI",
|
122
|
+
"EV_EBIT": "$$daily.EV_EBIT",
|
123
|
+
"EV_EBITDA": "$$daily.EV_EBITDA",
|
124
|
+
"EV_S": "$$daily.EV_S"
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
]
|
131
|
+
|
132
|
+
fetched_data = self.collection.aggregate(pipeline).to_list()
|
133
|
+
fetched_data = fetched_data[0]
|
134
|
+
|
135
|
+
value_keys = ["P_E", "P_FCF", "P_B", "P_S", "EV_OPI", "EV_EBIT", "EV_EVITDA", "EV_S"]
|
136
|
+
return_dict = {
|
137
|
+
value_key: dict() for value_key in value_keys
|
138
|
+
}
|
139
|
+
|
140
|
+
for value_key in value_keys:
|
141
|
+
for data in fetched_data['daily_data']:
|
142
|
+
if (value_key not in data.keys()):
|
143
|
+
continue
|
144
|
+
else:
|
145
|
+
return_dict[value_key].update({
|
146
|
+
data['date']: data[value_key]
|
147
|
+
})
|
148
|
+
|
149
|
+
return_dict = {
|
150
|
+
value_key: pd.DataFrame.from_dict(value_dict, orient = 'index', columns = [value_key])
|
151
|
+
for value_key, value_dict in return_dict.items()
|
152
|
+
}
|
153
|
+
return return_dict
|
82
154
|
|
83
155
|
|
84
156
|
class ValueProcessor(StatsProcessor):
|
@@ -17,6 +17,11 @@ target_metric_dict = {
|
|
17
17
|
|
18
18
|
|
19
19
|
class StatsProcessor:
|
20
|
+
"""
|
21
|
+
1. 讀檔: txt / yaml
|
22
|
+
2. 將巢狀dictionary / DataFrame扁平化
|
23
|
+
|
24
|
+
"""
|
20
25
|
|
21
26
|
@classmethod
|
22
27
|
def load_txt(cls, filename, json_load=True):
|
@@ -173,3 +178,13 @@ class StatsProcessor:
|
|
173
178
|
|
174
179
|
else:
|
175
180
|
return value
|
181
|
+
|
182
|
+
@classmethod
|
183
|
+
def cal_round_int(cls, value):
|
184
|
+
"""
|
185
|
+
將數值取到個位數後轉為int
|
186
|
+
"""
|
187
|
+
if (isinstance(value, (int, float))):
|
188
|
+
return int(np.round(value).item())
|
189
|
+
else:
|
190
|
+
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.13
|
4
4
|
Summary: The service of NeuroStats website
|
5
5
|
Home-page: https://github.com/NeurowattStats/NeuroStats_API.git
|
6
6
|
Author: JasonWang@Neurowatt
|
@@ -14,11 +14,14 @@ Description-Content-Type: text/markdown
|
|
14
14
|
- [使用方法](#使用方法)
|
15
15
|
- [下載](#下載)
|
16
16
|
- [價值投資](#得到最新一期的評價資料與歷年評價)
|
17
|
+
- [歷史評價](#得到指定公司的歷來評價)
|
17
18
|
- [財務分析-重要指標](#財務分析-重要指標)
|
18
19
|
- [月營收表](#回傳月營收表)
|
19
20
|
- [損益表](#損益表)
|
20
21
|
- [資產負債表](#資產負債表)
|
21
22
|
- [現金流量表](#現金流量表)
|
23
|
+
- [法人交易](#法人交易)
|
24
|
+
- [資券餘額](#資券餘額)
|
22
25
|
- [版本紀錄](#版本紀錄)
|
23
26
|
|
24
27
|
|
@@ -80,7 +83,7 @@ pip install neurostats-API
|
|
80
83
|
```Python
|
81
84
|
>>> import neurostats_API
|
82
85
|
>>> print(neurostats_API.__version__)
|
83
|
-
0.0.
|
86
|
+
0.0.13
|
84
87
|
```
|
85
88
|
|
86
89
|
### 得到最新一期的評價資料與歷年評價
|
@@ -89,7 +92,8 @@ from neurostats_API.utils import ValueFetcher, DBClient
|
|
89
92
|
db_client = DBClient("<連接的DB位置>").get_client()
|
90
93
|
ticker = "2330" # 換成tw50內任意ticker
|
91
94
|
fetcher = ValueFetcher(ticker, db_client)
|
92
|
-
|
95
|
+
|
96
|
+
fetcher.query_data()
|
93
97
|
```
|
94
98
|
|
95
99
|
#### 回傳(2330為例)
|
@@ -124,6 +128,69 @@ data = stats_fetcher.query_data()
|
|
124
128
|
```
|
125
129
|
> 這裡有Nan是因為本益比與P/B等資料沒有爬到最新的時間
|
126
130
|
|
131
|
+
### 得到指定公司的歷來評價
|
132
|
+
``` Python
|
133
|
+
from neurostats_API.utils import ValueFetcher, DBClient
|
134
|
+
db_client = DBClient("<連接的DB位置>").get_client()
|
135
|
+
ticker = "2330" # 換成tw50內任意ticker
|
136
|
+
fetcher = ValueFetcher(ticker, db_client)
|
137
|
+
|
138
|
+
fetcher.query_value_serie()
|
139
|
+
```
|
140
|
+
#### 回傳(2330為例)
|
141
|
+
```Python
|
142
|
+
{
|
143
|
+
'EV_EBIT': EV_EBIT
|
144
|
+
2014-01-02 NaN
|
145
|
+
2014-01-03 NaN
|
146
|
+
... ...
|
147
|
+
2024-12-12 15.021431
|
148
|
+
2024-12-13 15.088321
|
149
|
+
,
|
150
|
+
'EV_OPI': EV_OPI
|
151
|
+
2014-01-03 NaN
|
152
|
+
... ...
|
153
|
+
2024-12-12 15.999880
|
154
|
+
2024-12-13 16.071128
|
155
|
+
,
|
156
|
+
'EV_S': EV_S
|
157
|
+
2014-01-02 NaN
|
158
|
+
2014-01-03 NaN
|
159
|
+
... ...
|
160
|
+
2024-12-12 6.945457
|
161
|
+
2024-12-13 6.976385
|
162
|
+
,
|
163
|
+
'P_B': P_B
|
164
|
+
2014-01-02 NaN
|
165
|
+
2014-01-03 NaN
|
166
|
+
... ...
|
167
|
+
2024-12-12 6.79
|
168
|
+
2024-12-13 6.89
|
169
|
+
,
|
170
|
+
'P_E': P_E
|
171
|
+
2014-01-02 NaN
|
172
|
+
2014-01-03 NaN
|
173
|
+
... ...
|
174
|
+
2024-12-12 26.13
|
175
|
+
2024-12-13 26.50
|
176
|
+
,
|
177
|
+
'P_FCF': P_FCF
|
178
|
+
2014-01-02 NaN
|
179
|
+
2014-01-03 NaN
|
180
|
+
... ...
|
181
|
+
2024-12-12 45.302108
|
182
|
+
2024-12-13 45.515797
|
183
|
+
,
|
184
|
+
'P_S': P_S
|
185
|
+
2014-01-02 NaN
|
186
|
+
2014-01-03 NaN
|
187
|
+
... ...
|
188
|
+
2024-12-12 6.556760
|
189
|
+
2024-12-13 6.587688
|
190
|
+
}
|
191
|
+
```
|
192
|
+
|
193
|
+
|
127
194
|
### 回傳月營收表
|
128
195
|
``` Python
|
129
196
|
from neurostats_API.fetchers import MonthRevenueFetcher, DBClient
|
@@ -324,7 +391,7 @@ db_client = DBClient("<連接的DB位置>").get_client()
|
|
324
391
|
ticker = "2330" # 換成tw50內任意ticker
|
325
392
|
fetcher = BalanceSheetFetcher(ticker, db_client)
|
326
393
|
|
327
|
-
|
394
|
+
fetcher.query_data()
|
328
395
|
```
|
329
396
|
|
330
397
|
#### 回傳
|
@@ -386,7 +453,7 @@ db_client = DBClient("<連接的DB位置>").get_client()
|
|
386
453
|
ticker = 2330 # 換成tw50內任意ticker
|
387
454
|
fetcher = StatsFetcher(ticker, db_client)
|
388
455
|
|
389
|
-
|
456
|
+
fetcher.query()
|
390
457
|
```
|
391
458
|
#### 回傳
|
392
459
|
```Python
|
@@ -435,8 +502,186 @@ stats_fetcher.query()
|
|
435
502
|
|
436
503
|
> 大部分資料缺失是因為尚未計算,僅先填上已經有的資料
|
437
504
|
|
505
|
+
## 籌碼面
|
506
|
+
### 法人交易
|
507
|
+
``` Python
|
508
|
+
from neurostats_API.fetchers import InstitutionFetcher
|
509
|
+
db_client = DBClient("<連接的DB位置>").get_client()
|
510
|
+
ticker = 2330 # 換成tw50內任意ticker
|
511
|
+
fetcher = StatsFetcher(ticker, db_client)
|
512
|
+
|
513
|
+
fetcher.query()
|
514
|
+
```
|
515
|
+
### 回傳
|
516
|
+
```Python
|
517
|
+
{ 'annual_trading':
|
518
|
+
close volume ... 自營商買賣超股數(避險) 三大法人買賣超股數
|
519
|
+
2024-12-02 1035.000000 31168404.0 ... -133215.0 11176252.0
|
520
|
+
2024-11-29 996.000000 40094983.0 ... 401044.0 -7880519.0
|
521
|
+
... ... ... ... ... ...
|
522
|
+
2023-12-05 559.731873 22229723.0 ... 33,400 -5,988,621
|
523
|
+
2023-12-04 563.659790 26847171.0 ... -135,991 -5,236,743
|
524
|
+
|
525
|
+
,
|
526
|
+
'latest_trading':
|
527
|
+
{ 'date': datetime.datetime(2024, 12, 2, 0, 0),
|
528
|
+
'table':
|
529
|
+
category variable ... over_buy_sell sell
|
530
|
+
0 foreign average_price ... 0.00 0.0
|
531
|
+
1 foreign percentage ... 0.00 0.0
|
532
|
+
.. ... ... ... ... ...
|
533
|
+
14 prop price ... 0.00 0.0
|
534
|
+
15 prop stock ... -133.22 217.2
|
535
|
+
}
|
536
|
+
,
|
537
|
+
'price':
|
538
|
+
{
|
539
|
+
'52weeks_range': '555.8038940429688-1100.0', # str
|
540
|
+
'close': 1035.0, # float
|
541
|
+
'last_close': 996.0, # float
|
542
|
+
'last_open': 995.0, # float
|
543
|
+
'last_range': '994.0-1010.0', # str
|
544
|
+
'last_volume': 40094.983, # float
|
545
|
+
'open': 1020.0, # float
|
546
|
+
'range': '1015.0-1040.0', # str
|
547
|
+
'volume': 32238.019 # float
|
548
|
+
}
|
549
|
+
}
|
550
|
+
```
|
551
|
+
|
552
|
+
- `annual_trading`: 對應一年內每日的交易量
|
553
|
+
- `latest_trading`: 對應當日交易
|
554
|
+
##### 欄位項目名稱
|
555
|
+
|英文|中文對應|
|
556
|
+
|----|-------|
|
557
|
+
|buy|買進|
|
558
|
+
|sell|賣出|
|
559
|
+
|over_buy_sell|買賣超|
|
560
|
+
|
561
|
+
##### category項目名稱
|
562
|
+
|英文|中文對應|
|
563
|
+
|----|-------|
|
564
|
+
|foreign|外資|
|
565
|
+
|prop|自營商|
|
566
|
+
|mutual|投信|
|
567
|
+
|institutional_investor|三大法人|
|
568
|
+
|
569
|
+
##### variable項目名稱
|
570
|
+
|英文|中文對應|
|
571
|
+
|----|-------|
|
572
|
+
|stock|股票張數|
|
573
|
+
|price|成交金額|
|
574
|
+
|average_price|均價|
|
575
|
+
|percetage|佔成交比重|
|
576
|
+
|
577
|
+
**成交金額以及均價因為資料沒有爬到而無法計算**
|
578
|
+
**仍然先將這項目加入,只是數值都會是0**
|
579
|
+
|
580
|
+
- `price`: 對應法人買賣頁面的今日與昨日交易價
|
581
|
+
請注意`range`, `last_range`, `52week_range`這三個項目型態為字串,其餘為float
|
582
|
+
|
583
|
+
##### 項目名稱
|
584
|
+
|英文|中文對應|
|
585
|
+
|----|-------|
|
586
|
+
|open|開盤價|
|
587
|
+
|close|收盤價|
|
588
|
+
|range|當日範圍|
|
589
|
+
|volume|成交張數|
|
590
|
+
|last_open|開盤價(昨)|
|
591
|
+
|last_close|收盤價(昨)|
|
592
|
+
|last_range|昨日範圍|
|
593
|
+
|last_volume|成交張數(昨)|
|
594
|
+
|52weeks_range|52週範圍|
|
595
|
+
|
596
|
+
## 資券餘額
|
597
|
+
對應iFa.ai -> 交易資訊 -> 資券變化
|
598
|
+
```Python
|
599
|
+
from neurostats_API.fetchers import MarginTradingFetcher
|
600
|
+
db_client = DBClient("<連接的DB位置>").get_client()
|
601
|
+
ticker = 2330 # 換成tw50內任意ticker
|
602
|
+
fetcher = MarginTradingFetcher(ticker, db_client)
|
603
|
+
|
604
|
+
fetcher.query()
|
605
|
+
```
|
606
|
+
|
607
|
+
### 回傳
|
608
|
+
```Python
|
609
|
+
{ 'annual_margin':
|
610
|
+
close volume ... 借券_次一營業日可限額 資券互抵
|
611
|
+
2024-12-03 1060.000000 29637.0 ... 12222.252 0.0
|
612
|
+
2024-12-02 1035.000000 31168.0 ... 12156.872 1.0
|
613
|
+
... ... ... ... ... ...
|
614
|
+
2023-12-05 559.731873 22230.0 ... 7838.665 1.0
|
615
|
+
2023-12-04 563.659790 26847.0 ... 7722.725 2.0
|
616
|
+
|
617
|
+
'latest_trading': {
|
618
|
+
'date': datetime.datetime(2024, 12, 3, 0, 0),
|
619
|
+
'margin_trading':
|
620
|
+
financing short_selling
|
621
|
+
買進 761.0 34.0
|
622
|
+
賣出 1979.0 44.0
|
623
|
+
... ... ...
|
624
|
+
次一營業日限額 6483183.0 6483183.0
|
625
|
+
現償 3.0 12.0
|
626
|
+
|
627
|
+
|
628
|
+
'security_offset': 0.0,
|
629
|
+
'stock_lending': stock_lending
|
630
|
+
當日賣出 10
|
631
|
+
當日還券 0
|
632
|
+
當日調整 0
|
633
|
+
當日餘額 14688
|
634
|
+
次一營業日可限額 12222
|
635
|
+
},
|
636
|
+
'price': { '52weeks_range': '555.8038940429688 - 1100.0',
|
637
|
+
'close': 1060.0,
|
638
|
+
'last_close': 1035.0,
|
639
|
+
'last_open': 1020.0,
|
640
|
+
'last_range': '1015.0 - 1040.0',
|
641
|
+
'last_volume': 31168.404,
|
642
|
+
'open': 1060.0,
|
643
|
+
'range': '1055.0 - 1065.0',
|
644
|
+
'volume': 29636.523}}
|
645
|
+
```
|
646
|
+
- `annual_trading`: 對應一年內每日的資券變化量
|
647
|
+
- `latest_trading`: 對應當日交易
|
648
|
+
##### 欄位項目名稱
|
649
|
+
|英文|中文對應|
|
650
|
+
|----|-------|
|
651
|
+
|financing|融資|
|
652
|
+
|short_selling|融券|
|
653
|
+
|
654
|
+
- `price`: 對應法人買賣頁面的今日與昨日交易價
|
655
|
+
##### 項目名稱
|
656
|
+
|英文|中文對應|
|
657
|
+
|----|-------|
|
658
|
+
|open|開盤價|
|
659
|
+
|close|收盤價|
|
660
|
+
|range|當日範圍|
|
661
|
+
|volume|成交張數|
|
662
|
+
|last_open|開盤價(昨)|
|
663
|
+
|last_close|收盤價(昨)|
|
664
|
+
|last_range|昨日範圍|
|
665
|
+
|last_volume|成交張數(昨)|
|
666
|
+
|52weeks_range|52週範圍|
|
667
|
+
|
668
|
+
請注意`range`, `last_range`, `52week_range`這三個項目型態為字串,其餘為float
|
438
669
|
|
439
670
|
## 版本紀錄
|
671
|
+
### 0.0.13
|
672
|
+
- value_fetcher 新增獲得一序列評價的功能
|
673
|
+
|
674
|
+
### 0.0.12
|
675
|
+
- 新增資券變化(margin trading)
|
676
|
+
|
677
|
+
- 修改法人買賣(institution_trading)的query方式
|
678
|
+
|
679
|
+
### 0.0.11
|
680
|
+
- 修復財務分析的千元計算問題
|
681
|
+
|
682
|
+
- 籌碼面新增法人買賣(institution_trading)
|
683
|
+
|
684
|
+
- 將財報三表與月營收的資料型態與數值做轉換(%轉字串, 千元乘以1000)
|
440
685
|
### 0.0.10
|
441
686
|
- 更新指標的資料型態: 單位為千元乘以1000之後回傳整數
|
442
687
|
|
@@ -1,27 +1,28 @@
|
|
1
|
-
neurostats_API/__init__.py,sha256=
|
1
|
+
neurostats_API/__init__.py,sha256=UDEAcv3wrFvy1-DjCv7qON8202kc3zUGHpfClyTJWhs,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=
|
4
|
+
neurostats_API/fetchers/__init__.py,sha256=ylYEySHQxcAhUUWEOCGZfmaAg7Mir5MfuEhOjk3POJg,406
|
5
5
|
neurostats_API/fetchers/balance_sheet.py,sha256=sQv4Gk5uoKURLEdh57YknOQWiyVwaXJ2Mw75jxNqUS0,5804
|
6
6
|
neurostats_API/fetchers/base.py,sha256=NW2SFzrimyAIrdJx1LVmTazelyZOAtcj54kJKHc4Vaw,1662
|
7
7
|
neurostats_API/fetchers/cash_flow.py,sha256=TY7VAWVXkj5-mzH5Iu0sIE-oV8MvGmmDy0URNotNV1E,7614
|
8
8
|
neurostats_API/fetchers/finance_overview.py,sha256=PxUdWY0x030olYMLcCHDBn068JLmCE2RTOce1dxs5vM,27753
|
9
|
-
neurostats_API/fetchers/institution.py,sha256=
|
9
|
+
neurostats_API/fetchers/institution.py,sha256=rEcs5-JKbWjg8lSjG1V3YdHJQuPSN1GntnxvedESCeo,10984
|
10
|
+
neurostats_API/fetchers/margin_trading.py,sha256=lQImtNdvaBoSlKhJvQ3DkH3HjSSgKRJz4ZZpyR5-Z4I,10433
|
10
11
|
neurostats_API/fetchers/month_revenue.py,sha256=nixX2llzjCFr2m2YVjxrSfkBusnZPrPb2dRDq1XLGhw,4251
|
11
12
|
neurostats_API/fetchers/profit_lose.py,sha256=xlLNsGSy4Azf4HyZyYaX3dFad-ACO-vuQToBooZi1_w,5698
|
12
13
|
neurostats_API/fetchers/tech.py,sha256=wH1kkqiETQhF0HAhk-UIiucnZ3EiL85Q-yMWCcVOiFM,11395
|
13
|
-
neurostats_API/fetchers/value_invest.py,sha256=
|
14
|
+
neurostats_API/fetchers/value_invest.py,sha256=_eQxuEnIYvksb06QHixGK29Gnwr_3xmI6Tu7dv4J__E,5769
|
14
15
|
neurostats_API/tools/balance_sheet.yaml,sha256=yTxrWh7m4K3LnaNunETidfNzl6S4Bf58VIg9U38XShQ,648
|
15
16
|
neurostats_API/tools/cash_flow_percentage.yaml,sha256=fk2Z4eb1JjGFvP134eJatHacB7BgTkBenhDJr83w8RE,1345
|
16
17
|
neurostats_API/tools/finance_overview_dict.yaml,sha256=B9nV75StXkrF3yv2-eezzitlJ38eEK86RD_VY6588gQ,2884
|
17
18
|
neurostats_API/tools/profit_lose.yaml,sha256=dcO-0J0BC4p06XBNuowu8ux0NTbyZiOkGfy6szHF6fw,2402
|
18
19
|
neurostats_API/tools/seasonal_data_field_dict.txt,sha256=X8yc_el6p8BH_3FikTqBVFGsvWdXT6MHXLfKfi44334,8491
|
19
20
|
neurostats_API/utils/__init__.py,sha256=FTYKRFzW2XVXdnSHXnS3mQQaHlKF9xGqrMsgZZ2kroc,142
|
20
|
-
neurostats_API/utils/data_process.py,sha256=
|
21
|
+
neurostats_API/utils/data_process.py,sha256=2yrO0iP1LHhF0uhXZ442PHQBI-Zd2xIqNItkNf5hKIc,6339
|
21
22
|
neurostats_API/utils/datetime.py,sha256=XJya4G8b_-ZOaBbMXgQjWh2MC4wc-o6goQ7EQJQMWrQ,773
|
22
23
|
neurostats_API/utils/db_client.py,sha256=OYe6yazcR4Aa6jYmy47JrryUeh2NnKGqY2K_lSZe6i8,455
|
23
24
|
neurostats_API/utils/fetcher.py,sha256=VbrUhjA-GG5AyjPX2SHtFIbZM4dm3jo0RgZzuCbb_Io,40927
|
24
|
-
neurostats_API-0.0.
|
25
|
-
neurostats_API-0.0.
|
26
|
-
neurostats_API-0.0.
|
27
|
-
neurostats_API-0.0.
|
25
|
+
neurostats_API-0.0.13.dist-info/METADATA,sha256=tj8M4sSgXPprPV472mYHdEY_QOBpcObMXXo5lLGSOic,25744
|
26
|
+
neurostats_API-0.0.13.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
|
27
|
+
neurostats_API-0.0.13.dist-info/top_level.txt,sha256=nSlQPMG0VtXivJyedp4Bkf86EOy2TpW10VGxolXrqnU,15
|
28
|
+
neurostats_API-0.0.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|