neurostats-API 0.0.11__py3-none-any.whl → 0.0.13__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|