reportify-sdk 0.2.8__py3-none-any.whl → 0.2.10__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.
- reportify_sdk/__init__.py +1 -1
- reportify_sdk/agent.py +213 -0
- reportify_sdk/channels.py +126 -0
- reportify_sdk/chat.py +107 -0
- reportify_sdk/client.py +62 -180
- reportify_sdk/docs.py +351 -8
- reportify_sdk/kb.py +15 -0
- reportify_sdk/search.py +357 -0
- reportify_sdk/stock.py +203 -121
- reportify_sdk/timeline.py +34 -0
- reportify_sdk/user.py +44 -0
- {reportify_sdk-0.2.8.dist-info → reportify_sdk-0.2.10.dist-info}/METADATA +1 -1
- reportify_sdk-0.2.10.dist-info/RECORD +19 -0
- {reportify_sdk-0.2.8.dist-info → reportify_sdk-0.2.10.dist-info}/WHEEL +1 -1
- reportify_sdk-0.2.8.dist-info/RECORD +0 -14
- {reportify_sdk-0.2.8.dist-info → reportify_sdk-0.2.10.dist-info}/licenses/LICENSE +0 -0
- {reportify_sdk-0.2.8.dist-info → reportify_sdk-0.2.10.dist-info}/top_level.txt +0 -0
reportify_sdk/stock.py
CHANGED
|
@@ -72,17 +72,30 @@ class StockModule:
|
|
|
72
72
|
response = self._post("/v1/stock/company-overview", json=data)
|
|
73
73
|
return response
|
|
74
74
|
|
|
75
|
-
def shareholders(
|
|
75
|
+
def shareholders(
|
|
76
|
+
self,
|
|
77
|
+
symbol: str,
|
|
78
|
+
*,
|
|
79
|
+
type: Literal["shareholders", "outstanding_shareholders"] = "shareholders",
|
|
80
|
+
limit: int = 10,
|
|
81
|
+
) -> list[dict[str, Any]]:
|
|
76
82
|
"""
|
|
77
83
|
Get list of major shareholders
|
|
78
84
|
|
|
79
85
|
Args:
|
|
80
86
|
symbol: Stock symbol
|
|
87
|
+
type: Type of shareholders to return
|
|
88
|
+
- "shareholders": All shareholders
|
|
89
|
+
- "outstanding_shareholders": Outstanding shareholders only
|
|
90
|
+
limit: Number of shareholders to return (default: 10)
|
|
81
91
|
|
|
82
92
|
Returns:
|
|
83
93
|
List of shareholders with ownership details
|
|
84
94
|
"""
|
|
85
|
-
response = self._post(
|
|
95
|
+
response = self._post(
|
|
96
|
+
"/v1/stock/company-shareholders",
|
|
97
|
+
json={"symbol": symbol, "type": type, "limit": limit},
|
|
98
|
+
)
|
|
86
99
|
return response if isinstance(response, list) else response.get("shareholders", [])
|
|
87
100
|
|
|
88
101
|
# -------------------------------------------------------------------------
|
|
@@ -93,16 +106,26 @@ class StockModule:
|
|
|
93
106
|
self,
|
|
94
107
|
symbol: str,
|
|
95
108
|
*,
|
|
96
|
-
period: Literal["annual", "quarterly"] = "annual",
|
|
97
|
-
limit: int =
|
|
109
|
+
period: Literal["annual", "quarterly", "cumulative quarterly"] = "annual",
|
|
110
|
+
limit: int = 8,
|
|
111
|
+
start_date: str | None = None,
|
|
112
|
+
end_date: str | None = None,
|
|
113
|
+
calendar: Literal["calendar", "fiscal"] = "fiscal",
|
|
114
|
+
fiscal_year: str | None = None,
|
|
115
|
+
fiscal_quarter: str | None = None,
|
|
98
116
|
) -> pd.DataFrame:
|
|
99
117
|
"""
|
|
100
118
|
Get income statement data
|
|
101
119
|
|
|
102
120
|
Args:
|
|
103
121
|
symbol: Stock symbol (e.g., "US:AAPL")
|
|
104
|
-
period: "annual"
|
|
105
|
-
limit:
|
|
122
|
+
period: Report cycle ("annual", "quarterly", "cumulative quarterly")
|
|
123
|
+
limit: Return latest N records (default: 8)
|
|
124
|
+
start_date: Start date (YYYY-MM-DD)
|
|
125
|
+
end_date: End date (YYYY-MM-DD)
|
|
126
|
+
calendar: "calendar" or "fiscal" (default: "fiscal")
|
|
127
|
+
fiscal_year: Specific fiscal year (e.g., "2023")
|
|
128
|
+
fiscal_quarter: Specific fiscal quarter (Q1, Q2, Q3, Q4, FY, H1, "Q3 (9 months)")
|
|
106
129
|
|
|
107
130
|
Returns:
|
|
108
131
|
DataFrame with income statement data, indexed by date
|
|
@@ -111,10 +134,22 @@ class StockModule:
|
|
|
111
134
|
>>> income = client.stock.income_statement("US:AAPL", period="quarterly")
|
|
112
135
|
>>> print(income[["revenue", "net_income"]].head())
|
|
113
136
|
"""
|
|
114
|
-
|
|
115
|
-
"
|
|
116
|
-
|
|
117
|
-
|
|
137
|
+
data: dict[str, Any] = {
|
|
138
|
+
"symbol": symbol,
|
|
139
|
+
"period": period,
|
|
140
|
+
"limit": limit,
|
|
141
|
+
"calendar": calendar,
|
|
142
|
+
}
|
|
143
|
+
if start_date:
|
|
144
|
+
data["start_date"] = start_date
|
|
145
|
+
if end_date:
|
|
146
|
+
data["end_date"] = end_date
|
|
147
|
+
if fiscal_year:
|
|
148
|
+
data["fiscal_year"] = fiscal_year
|
|
149
|
+
if fiscal_quarter:
|
|
150
|
+
data["fiscal_quarter"] = fiscal_quarter
|
|
151
|
+
|
|
152
|
+
response = self._post("/v1/stock/company-income-statement", json=data)
|
|
118
153
|
return self._to_dataframe(response)
|
|
119
154
|
|
|
120
155
|
def balance_sheet(
|
|
@@ -122,15 +157,25 @@ class StockModule:
|
|
|
122
157
|
symbol: str,
|
|
123
158
|
*,
|
|
124
159
|
period: Literal["annual", "quarterly"] = "annual",
|
|
125
|
-
limit: int =
|
|
160
|
+
limit: int = 8,
|
|
161
|
+
start_date: str | None = None,
|
|
162
|
+
end_date: str | None = None,
|
|
163
|
+
calendar: Literal["calendar", "fiscal"] = "fiscal",
|
|
164
|
+
fiscal_year: str | None = None,
|
|
165
|
+
fiscal_quarter: str | None = None,
|
|
126
166
|
) -> pd.DataFrame:
|
|
127
167
|
"""
|
|
128
168
|
Get balance sheet data
|
|
129
169
|
|
|
130
170
|
Args:
|
|
131
171
|
symbol: Stock symbol
|
|
132
|
-
period: "annual"
|
|
133
|
-
limit:
|
|
172
|
+
period: Report cycle ("annual", "quarterly")
|
|
173
|
+
limit: Return latest N records (default: 8)
|
|
174
|
+
start_date: Start date (YYYY-MM-DD)
|
|
175
|
+
end_date: End date (YYYY-MM-DD)
|
|
176
|
+
calendar: "calendar" or "fiscal" (default: "fiscal")
|
|
177
|
+
fiscal_year: Specific fiscal year (e.g., "2023")
|
|
178
|
+
fiscal_quarter: Specific fiscal quarter (Q1, Q2, Q3, Q4, FY)
|
|
134
179
|
|
|
135
180
|
Returns:
|
|
136
181
|
DataFrame with balance sheet data, indexed by date
|
|
@@ -139,26 +184,48 @@ class StockModule:
|
|
|
139
184
|
>>> balance = client.stock.balance_sheet("US:AAPL")
|
|
140
185
|
>>> print(balance[["total_assets", "total_liabilities"]].head())
|
|
141
186
|
"""
|
|
142
|
-
|
|
143
|
-
"
|
|
144
|
-
|
|
145
|
-
|
|
187
|
+
data: dict[str, Any] = {
|
|
188
|
+
"symbol": symbol,
|
|
189
|
+
"period": period,
|
|
190
|
+
"limit": limit,
|
|
191
|
+
"calendar": calendar,
|
|
192
|
+
}
|
|
193
|
+
if start_date:
|
|
194
|
+
data["start_date"] = start_date
|
|
195
|
+
if end_date:
|
|
196
|
+
data["end_date"] = end_date
|
|
197
|
+
if fiscal_year:
|
|
198
|
+
data["fiscal_year"] = fiscal_year
|
|
199
|
+
if fiscal_quarter:
|
|
200
|
+
data["fiscal_quarter"] = fiscal_quarter
|
|
201
|
+
|
|
202
|
+
response = self._post("/v1/stock/company-balance-sheet", json=data)
|
|
146
203
|
return self._to_dataframe(response)
|
|
147
204
|
|
|
148
205
|
def cashflow_statement(
|
|
149
206
|
self,
|
|
150
207
|
symbol: str,
|
|
151
208
|
*,
|
|
152
|
-
period: Literal["annual", "quarterly"] = "annual",
|
|
153
|
-
limit: int =
|
|
209
|
+
period: Literal["annual", "quarterly", "cumulative quarterly"] = "annual",
|
|
210
|
+
limit: int = 8,
|
|
211
|
+
start_date: str | None = None,
|
|
212
|
+
end_date: str | None = None,
|
|
213
|
+
calendar: Literal["calendar", "fiscal"] = "fiscal",
|
|
214
|
+
fiscal_year: str | None = None,
|
|
215
|
+
fiscal_quarter: str | None = None,
|
|
154
216
|
) -> pd.DataFrame:
|
|
155
217
|
"""
|
|
156
218
|
Get cash flow statement data
|
|
157
219
|
|
|
158
220
|
Args:
|
|
159
221
|
symbol: Stock symbol
|
|
160
|
-
period: "annual"
|
|
161
|
-
limit:
|
|
222
|
+
period: Report cycle ("annual", "quarterly", "cumulative quarterly")
|
|
223
|
+
limit: Return latest N records (default: 8)
|
|
224
|
+
start_date: Start date (YYYY-MM-DD)
|
|
225
|
+
end_date: End date (YYYY-MM-DD)
|
|
226
|
+
calendar: "calendar" or "fiscal" (default: "fiscal")
|
|
227
|
+
fiscal_year: Specific fiscal year (e.g., "2023")
|
|
228
|
+
fiscal_quarter: Specific fiscal quarter (Q1, Q2, Q3, Q4, FY, H1, "Q3 (9 months)")
|
|
162
229
|
|
|
163
230
|
Returns:
|
|
164
231
|
DataFrame with cash flow data, indexed by date
|
|
@@ -167,134 +234,111 @@ class StockModule:
|
|
|
167
234
|
>>> cashflow = client.stock.cashflow_statement("US:AAPL")
|
|
168
235
|
>>> print(cashflow[["operating_cashflow", "free_cashflow"]].head())
|
|
169
236
|
"""
|
|
170
|
-
|
|
171
|
-
"
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
Args:
|
|
186
|
-
symbol: Stock symbol
|
|
187
|
-
breakdown_type: Type of breakdown ("segment", "product", or "region")
|
|
237
|
+
data: dict[str, Any] = {
|
|
238
|
+
"symbol": symbol,
|
|
239
|
+
"period": period,
|
|
240
|
+
"limit": limit,
|
|
241
|
+
"calendar": calendar,
|
|
242
|
+
}
|
|
243
|
+
if start_date:
|
|
244
|
+
data["start_date"] = start_date
|
|
245
|
+
if end_date:
|
|
246
|
+
data["end_date"] = end_date
|
|
247
|
+
if fiscal_year:
|
|
248
|
+
data["fiscal_year"] = fiscal_year
|
|
249
|
+
if fiscal_quarter:
|
|
250
|
+
data["fiscal_quarter"] = fiscal_quarter
|
|
188
251
|
|
|
189
|
-
|
|
190
|
-
DataFrame with revenue breakdown data
|
|
191
|
-
"""
|
|
192
|
-
response = self._post(
|
|
193
|
-
"/v1/stock/company-revenue-breakdown",
|
|
194
|
-
json={"symbol": symbol, "breakdown_type": breakdown_type},
|
|
195
|
-
)
|
|
252
|
+
response = self._post("/v1/stock/company-cashflow-statement", json=data)
|
|
196
253
|
return self._to_dataframe(response)
|
|
197
254
|
|
|
198
|
-
|
|
199
|
-
# Price Data (returns DataFrame)
|
|
200
|
-
# -------------------------------------------------------------------------
|
|
201
|
-
|
|
202
|
-
def prices(
|
|
255
|
+
def revenue_breakdown(
|
|
203
256
|
self,
|
|
204
257
|
symbol: str,
|
|
205
258
|
*,
|
|
259
|
+
period: str | None = None,
|
|
260
|
+
limit: int = 6,
|
|
206
261
|
start_date: str | None = None,
|
|
207
262
|
end_date: str | None = None,
|
|
208
|
-
|
|
263
|
+
fiscal_year: str | None = None,
|
|
209
264
|
) -> pd.DataFrame:
|
|
210
265
|
"""
|
|
211
|
-
Get
|
|
266
|
+
Get revenue breakdown
|
|
212
267
|
|
|
213
268
|
Args:
|
|
214
269
|
symbol: Stock symbol
|
|
270
|
+
period: Report cycle (e.g., "FY", "Q2")
|
|
271
|
+
limit: Return latest N records (default: 6)
|
|
215
272
|
start_date: Start date (YYYY-MM-DD)
|
|
216
273
|
end_date: End date (YYYY-MM-DD)
|
|
217
|
-
|
|
274
|
+
fiscal_year: Specific fiscal year (e.g., "2023")
|
|
218
275
|
|
|
219
276
|
Returns:
|
|
220
|
-
DataFrame with
|
|
221
|
-
|
|
222
|
-
Example:
|
|
223
|
-
>>> prices = client.stock.prices("US:AAPL", limit=30)
|
|
224
|
-
>>> print(prices[["close", "volume"]].tail())
|
|
277
|
+
DataFrame with revenue breakdown data
|
|
225
278
|
"""
|
|
226
279
|
data: dict[str, Any] = {"symbol": symbol, "limit": limit}
|
|
280
|
+
if period:
|
|
281
|
+
data["period"] = period
|
|
227
282
|
if start_date:
|
|
228
283
|
data["start_date"] = start_date
|
|
229
284
|
if end_date:
|
|
230
285
|
data["end_date"] = end_date
|
|
286
|
+
if fiscal_year:
|
|
287
|
+
data["fiscal_year"] = fiscal_year
|
|
231
288
|
|
|
232
|
-
response = self._post("/v1/stock/company-
|
|
289
|
+
response = self._post("/v1/stock/company-revenue-breakdown", json=data)
|
|
233
290
|
return self._to_dataframe(response)
|
|
234
291
|
|
|
235
|
-
|
|
292
|
+
# -------------------------------------------------------------------------
|
|
293
|
+
# Price Data (returns DataFrame)
|
|
294
|
+
# -------------------------------------------------------------------------
|
|
295
|
+
|
|
296
|
+
def prices(
|
|
236
297
|
self,
|
|
237
298
|
symbol: str,
|
|
238
299
|
*,
|
|
239
|
-
interval: Literal["1d", "1w", "1m"] = "1d",
|
|
240
|
-
adjust: Literal["forward", "backward", "none"] = "forward",
|
|
241
300
|
start_date: str | None = None,
|
|
242
301
|
end_date: str | None = None,
|
|
243
|
-
limit: int = 100,
|
|
244
302
|
) -> pd.DataFrame:
|
|
245
303
|
"""
|
|
246
|
-
Get
|
|
304
|
+
Get historical stock prices with market data
|
|
247
305
|
|
|
248
306
|
Args:
|
|
249
307
|
symbol: Stock symbol
|
|
250
|
-
interval: Time interval ("1d" daily, "1w" weekly, "1m" monthly)
|
|
251
|
-
adjust: Price adjustment type
|
|
252
|
-
- "forward": Forward adjusted (前复权)
|
|
253
|
-
- "backward": Backward adjusted (后复权)
|
|
254
|
-
- "none": Unadjusted (不复权)
|
|
255
308
|
start_date: Start date (YYYY-MM-DD)
|
|
256
309
|
end_date: End date (YYYY-MM-DD)
|
|
257
|
-
limit: Maximum number of records
|
|
258
310
|
|
|
259
311
|
Returns:
|
|
260
|
-
DataFrame with
|
|
312
|
+
DataFrame with price data (date, close, volume, market_cap, pe, ps)
|
|
261
313
|
|
|
262
314
|
Example:
|
|
263
|
-
>>>
|
|
264
|
-
>>> print(
|
|
315
|
+
>>> prices = client.stock.prices("US:AAPL")
|
|
316
|
+
>>> print(prices[["close", "volume"]].tail())
|
|
265
317
|
"""
|
|
266
|
-
data: dict[str, Any] = {
|
|
267
|
-
"symbol": symbol,
|
|
268
|
-
"interval": interval,
|
|
269
|
-
"adjust": adjust,
|
|
270
|
-
"limit": limit,
|
|
271
|
-
}
|
|
318
|
+
data: dict[str, Any] = {"symbol": symbol}
|
|
272
319
|
if start_date:
|
|
273
320
|
data["start_date"] = start_date
|
|
274
321
|
if end_date:
|
|
275
322
|
data["end_date"] = end_date
|
|
276
323
|
|
|
277
|
-
response = self._post("/v1/stock/
|
|
324
|
+
response = self._post("/v1/stock/company-prices", json=data)
|
|
278
325
|
return self._to_dataframe(response)
|
|
279
326
|
|
|
280
|
-
def quote(self,
|
|
327
|
+
def quote(self, symbol: str) -> pd.DataFrame:
|
|
281
328
|
"""
|
|
282
|
-
Get real-time stock
|
|
329
|
+
Get real-time stock quote
|
|
283
330
|
|
|
284
331
|
Args:
|
|
285
|
-
|
|
332
|
+
symbol: Stock symbol (e.g., "US:AAPL", "688001", "00700")
|
|
286
333
|
|
|
287
334
|
Returns:
|
|
288
335
|
DataFrame with real-time quote data
|
|
289
336
|
|
|
290
337
|
Example:
|
|
291
|
-
>>>
|
|
292
|
-
>>> print(
|
|
338
|
+
>>> quote = client.stock.quote("US:AAPL")
|
|
339
|
+
>>> print(quote[["symbol", "price", "change_percent"]])
|
|
293
340
|
"""
|
|
294
|
-
|
|
295
|
-
symbols = [symbols]
|
|
296
|
-
|
|
297
|
-
response = self._post("/v1/stock/quote-realtime", json={"symbols": symbols})
|
|
341
|
+
response = self._post("/v1/stock/quote-realtime", json={"symbol": symbol})
|
|
298
342
|
return self._to_dataframe(response)
|
|
299
343
|
|
|
300
344
|
def index_prices(
|
|
@@ -303,21 +347,19 @@ class StockModule:
|
|
|
303
347
|
*,
|
|
304
348
|
start_date: str | None = None,
|
|
305
349
|
end_date: str | None = None,
|
|
306
|
-
limit: int = 100,
|
|
307
350
|
) -> pd.DataFrame:
|
|
308
351
|
"""
|
|
309
|
-
Get stock index prices (e.g.,
|
|
352
|
+
Get stock index prices (e.g., HSI, SPX, DJI)
|
|
310
353
|
|
|
311
354
|
Args:
|
|
312
|
-
symbol: Index symbol
|
|
355
|
+
symbol: Index symbol (e.g., "HSI", "SPX", "DJI")
|
|
313
356
|
start_date: Start date (YYYY-MM-DD)
|
|
314
357
|
end_date: End date (YYYY-MM-DD)
|
|
315
|
-
limit: Maximum number of records
|
|
316
358
|
|
|
317
359
|
Returns:
|
|
318
360
|
DataFrame with index price data
|
|
319
361
|
"""
|
|
320
|
-
data: dict[str, Any] = {"symbol": symbol
|
|
362
|
+
data: dict[str, Any] = {"symbol": symbol}
|
|
321
363
|
if start_date:
|
|
322
364
|
data["start_date"] = start_date
|
|
323
365
|
if end_date:
|
|
@@ -333,42 +375,82 @@ class StockModule:
|
|
|
333
375
|
def screener(
|
|
334
376
|
self,
|
|
335
377
|
*,
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
378
|
+
market_cap_more_than: float | None = None,
|
|
379
|
+
market_cap_lower_than: float | None = None,
|
|
380
|
+
price_more_than: float | None = None,
|
|
381
|
+
price_lower_than: float | None = None,
|
|
382
|
+
change_percentage_more_than: float | None = None,
|
|
383
|
+
change_percentage_lower_than: float | None = None,
|
|
384
|
+
volume_more_than: int | None = None,
|
|
385
|
+
volume_lower_than: int | None = None,
|
|
386
|
+
country: str | None = None,
|
|
387
|
+
exchange: str | None = None,
|
|
388
|
+
dividend_yield_more_than: float | None = None,
|
|
389
|
+
dividend_yield_lower_than: float | None = None,
|
|
390
|
+
pe_ttm_more_than: float | None = None,
|
|
391
|
+
pe_ttm_lower_than: float | None = None,
|
|
392
|
+
limit: int = 100,
|
|
343
393
|
) -> pd.DataFrame:
|
|
344
394
|
"""
|
|
345
395
|
Screen stocks based on various criteria
|
|
346
396
|
|
|
347
397
|
Args:
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
398
|
+
market_cap_more_than: Market cap greater than
|
|
399
|
+
market_cap_lower_than: Market cap less than
|
|
400
|
+
price_more_than: Stock price greater than
|
|
401
|
+
price_lower_than: Stock price less than
|
|
402
|
+
change_percentage_more_than: Change percentage greater than (e.g., 0.02 for 2%)
|
|
403
|
+
change_percentage_lower_than: Change percentage less than (e.g., 0.04 for 4%)
|
|
404
|
+
volume_more_than: Trading volume greater than
|
|
405
|
+
volume_lower_than: Trading volume less than
|
|
406
|
+
country: Country code (e.g., "US", "CN", "HK")
|
|
407
|
+
exchange: Exchange code (e.g., "NASDAQ", "NYSE", "HKEX")
|
|
408
|
+
dividend_yield_more_than: Dividend yield greater than
|
|
409
|
+
dividend_yield_lower_than: Dividend yield less than
|
|
410
|
+
pe_ttm_more_than: PE TTM greater than
|
|
411
|
+
pe_ttm_lower_than: PE TTM less than
|
|
412
|
+
limit: Maximum number of results (default: 100)
|
|
355
413
|
|
|
356
414
|
Returns:
|
|
357
415
|
DataFrame with screened stocks
|
|
416
|
+
|
|
417
|
+
Example:
|
|
418
|
+
>>> # Find US stocks with PE < 15 and market cap > 1B
|
|
419
|
+
>>> stocks = client.stock.screener(
|
|
420
|
+
... country="US",
|
|
421
|
+
... pe_ttm_lower_than=15,
|
|
422
|
+
... market_cap_more_than=1000000000
|
|
423
|
+
... )
|
|
358
424
|
"""
|
|
359
425
|
data: dict[str, Any] = {"limit": limit}
|
|
360
|
-
if
|
|
361
|
-
data["
|
|
362
|
-
if
|
|
363
|
-
data["
|
|
364
|
-
if
|
|
365
|
-
data["
|
|
366
|
-
if
|
|
367
|
-
data["
|
|
368
|
-
if
|
|
369
|
-
data["
|
|
370
|
-
if
|
|
371
|
-
data["
|
|
426
|
+
if market_cap_more_than is not None:
|
|
427
|
+
data["market_cap_more_than"] = market_cap_more_than
|
|
428
|
+
if market_cap_lower_than is not None:
|
|
429
|
+
data["market_cap_lower_than"] = market_cap_lower_than
|
|
430
|
+
if price_more_than is not None:
|
|
431
|
+
data["price_more_than"] = price_more_than
|
|
432
|
+
if price_lower_than is not None:
|
|
433
|
+
data["price_lower_than"] = price_lower_than
|
|
434
|
+
if change_percentage_more_than is not None:
|
|
435
|
+
data["change_percentage_more_than"] = change_percentage_more_than
|
|
436
|
+
if change_percentage_lower_than is not None:
|
|
437
|
+
data["change_percentage_lower_than"] = change_percentage_lower_than
|
|
438
|
+
if volume_more_than is not None:
|
|
439
|
+
data["volume_more_than"] = volume_more_than
|
|
440
|
+
if volume_lower_than is not None:
|
|
441
|
+
data["volume_lower_than"] = volume_lower_than
|
|
442
|
+
if country:
|
|
443
|
+
data["country"] = country
|
|
444
|
+
if exchange:
|
|
445
|
+
data["exchange"] = exchange
|
|
446
|
+
if dividend_yield_more_than is not None:
|
|
447
|
+
data["dividend_yield_more_than"] = dividend_yield_more_than
|
|
448
|
+
if dividend_yield_lower_than is not None:
|
|
449
|
+
data["dividend_yield_lower_than"] = dividend_yield_lower_than
|
|
450
|
+
if pe_ttm_more_than is not None:
|
|
451
|
+
data["pe_ttm_more_than"] = pe_ttm_more_than
|
|
452
|
+
if pe_ttm_lower_than is not None:
|
|
453
|
+
data["pe_ttm_lower_than"] = pe_ttm_lower_than
|
|
372
454
|
|
|
373
455
|
response = self._post("/v1/stock/screener", json=data)
|
|
374
456
|
return self._to_dataframe(response)
|
reportify_sdk/timeline.py
CHANGED
|
@@ -3,14 +3,28 @@ Timeline Module
|
|
|
3
3
|
|
|
4
4
|
Provides access to timeline feeds based on user's followed entities
|
|
5
5
|
(companies, topics, institutes, media).
|
|
6
|
+
|
|
7
|
+
NOTE: This module uses internal APIs that are not documented in the public OpenAPI spec.
|
|
8
|
+
These endpoints may change without notice.
|
|
6
9
|
"""
|
|
7
10
|
|
|
11
|
+
import warnings
|
|
8
12
|
from typing import TYPE_CHECKING, Any
|
|
9
13
|
|
|
10
14
|
if TYPE_CHECKING:
|
|
11
15
|
from reportify_sdk.client import Reportify
|
|
12
16
|
|
|
13
17
|
|
|
18
|
+
def _timeline_deprecation_warning(method_name: str) -> None:
|
|
19
|
+
"""Emit deprecation warning for timeline methods."""
|
|
20
|
+
warnings.warn(
|
|
21
|
+
f"timeline.{method_name}() uses an internal API not documented in the public OpenAPI spec. "
|
|
22
|
+
"This endpoint may change without notice.",
|
|
23
|
+
DeprecationWarning,
|
|
24
|
+
stacklevel=3,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
14
28
|
class TimelineModule:
|
|
15
29
|
"""
|
|
16
30
|
Timeline module for following-based content feeds
|
|
@@ -30,6 +44,9 @@ class TimelineModule:
|
|
|
30
44
|
"""
|
|
31
45
|
Get timeline for followed companies
|
|
32
46
|
|
|
47
|
+
.. deprecated::
|
|
48
|
+
This method uses an internal API not documented in the public OpenAPI spec.
|
|
49
|
+
|
|
33
50
|
Returns recent content related to companies the user is following,
|
|
34
51
|
including financial reports, news, research reports, and announcements.
|
|
35
52
|
|
|
@@ -44,6 +61,7 @@ class TimelineModule:
|
|
|
44
61
|
>>> for item in timeline:
|
|
45
62
|
... print(item["title"], item["published_at"])
|
|
46
63
|
"""
|
|
64
|
+
_timeline_deprecation_warning("companies")
|
|
47
65
|
response = self._post("/v1/tools/timeline/companies", json={"num": num})
|
|
48
66
|
return response.get("docs", [])
|
|
49
67
|
|
|
@@ -51,6 +69,9 @@ class TimelineModule:
|
|
|
51
69
|
"""
|
|
52
70
|
Get timeline for followed topics
|
|
53
71
|
|
|
72
|
+
.. deprecated::
|
|
73
|
+
This method uses an internal API not documented in the public OpenAPI spec.
|
|
74
|
+
|
|
54
75
|
Returns recent content related to custom topics the user is following.
|
|
55
76
|
|
|
56
77
|
Args:
|
|
@@ -64,6 +85,7 @@ class TimelineModule:
|
|
|
64
85
|
>>> for item in timeline:
|
|
65
86
|
... print(item["title"])
|
|
66
87
|
"""
|
|
88
|
+
_timeline_deprecation_warning("topics")
|
|
67
89
|
response = self._post("/v1/tools/timeline/topics", json={"num": num})
|
|
68
90
|
return response.get("docs", [])
|
|
69
91
|
|
|
@@ -71,6 +93,9 @@ class TimelineModule:
|
|
|
71
93
|
"""
|
|
72
94
|
Get timeline for followed professional institutes
|
|
73
95
|
|
|
96
|
+
.. deprecated::
|
|
97
|
+
This method uses an internal API not documented in the public OpenAPI spec.
|
|
98
|
+
|
|
74
99
|
Returns recent content from research institutions, banks,
|
|
75
100
|
and other professional organizations the user is following.
|
|
76
101
|
|
|
@@ -85,6 +110,7 @@ class TimelineModule:
|
|
|
85
110
|
>>> for item in timeline:
|
|
86
111
|
... print(item["channel_name"], item["title"])
|
|
87
112
|
"""
|
|
113
|
+
_timeline_deprecation_warning("institutes")
|
|
88
114
|
response = self._post("/v1/tools/timeline/institutes", json={"num": num})
|
|
89
115
|
return response.get("docs", [])
|
|
90
116
|
|
|
@@ -92,6 +118,9 @@ class TimelineModule:
|
|
|
92
118
|
"""
|
|
93
119
|
Get timeline for followed public media
|
|
94
120
|
|
|
121
|
+
.. deprecated::
|
|
122
|
+
This method uses an internal API not documented in the public OpenAPI spec.
|
|
123
|
+
|
|
95
124
|
Returns recent content from public media accounts (WeChat, etc.)
|
|
96
125
|
the user is following.
|
|
97
126
|
|
|
@@ -104,6 +133,7 @@ class TimelineModule:
|
|
|
104
133
|
Example:
|
|
105
134
|
>>> timeline = client.timeline.public_media(num=20)
|
|
106
135
|
"""
|
|
136
|
+
_timeline_deprecation_warning("public_media")
|
|
107
137
|
response = self._post("/v1/tools/timeline/public-media", json={"num": num})
|
|
108
138
|
return response.get("docs", [])
|
|
109
139
|
|
|
@@ -111,6 +141,9 @@ class TimelineModule:
|
|
|
111
141
|
"""
|
|
112
142
|
Get timeline for followed social media
|
|
113
143
|
|
|
144
|
+
.. deprecated::
|
|
145
|
+
This method uses an internal API not documented in the public OpenAPI spec.
|
|
146
|
+
|
|
114
147
|
Returns recent content from social media accounts (Twitter, etc.)
|
|
115
148
|
the user is following.
|
|
116
149
|
|
|
@@ -123,5 +156,6 @@ class TimelineModule:
|
|
|
123
156
|
Example:
|
|
124
157
|
>>> timeline = client.timeline.social_media(num=20)
|
|
125
158
|
"""
|
|
159
|
+
_timeline_deprecation_warning("social_media")
|
|
126
160
|
response = self._post("/v1/tools/timeline/social-media", json={"num": num})
|
|
127
161
|
return response.get("docs", [])
|
reportify_sdk/user.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""
|
|
2
|
+
User Module
|
|
3
|
+
|
|
4
|
+
Provides access to user-related tools and data.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from reportify_sdk.client import Reportify
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class UserModule:
|
|
14
|
+
"""
|
|
15
|
+
User module for accessing user-related tools
|
|
16
|
+
|
|
17
|
+
Access through the main client:
|
|
18
|
+
>>> client = Reportify(api_key="xxx")
|
|
19
|
+
>>> companies = client.user.followed_companies()
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, client: "Reportify"):
|
|
23
|
+
self._client = client
|
|
24
|
+
|
|
25
|
+
def _get(self, path: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
26
|
+
return self._client._get(path, params=params)
|
|
27
|
+
|
|
28
|
+
def followed_companies(self) -> list[dict[str, Any]]:
|
|
29
|
+
"""
|
|
30
|
+
Get all companies followed by the user
|
|
31
|
+
|
|
32
|
+
Returns a list of companies that the user is following,
|
|
33
|
+
including company details like symbol, name, logo, and follow timestamp.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
List of followed company information
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
>>> companies = client.user.followed_companies()
|
|
40
|
+
>>> for company in companies:
|
|
41
|
+
... print(f"{company['symbol']}: {company['name']}")
|
|
42
|
+
"""
|
|
43
|
+
response = self._get("/v1/tools/user/followed-companies")
|
|
44
|
+
return response.get("companies", [])
|