reportify-sdk 0.2.7__py3-none-any.whl → 0.2.9__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 +257 -57
- reportify_sdk/docs.py +351 -8
- reportify_sdk/kb.py +15 -0
- reportify_sdk/stock.py +231 -126
- reportify_sdk/timeline.py +34 -0
- reportify_sdk/user.py +44 -0
- {reportify_sdk-0.2.7.dist-info → reportify_sdk-0.2.9.dist-info}/METADATA +1 -1
- reportify_sdk-0.2.9.dist-info/RECORD +18 -0
- reportify_sdk-0.2.7.dist-info/RECORD +0 -14
- {reportify_sdk-0.2.7.dist-info → reportify_sdk-0.2.9.dist-info}/WHEEL +0 -0
- {reportify_sdk-0.2.7.dist-info → reportify_sdk-0.2.9.dist-info}/licenses/LICENSE +0 -0
- {reportify_sdk-0.2.7.dist-info → reportify_sdk-0.2.9.dist-info}/top_level.txt +0 -0
reportify_sdk/stock.py
CHANGED
|
@@ -32,34 +32,70 @@ class StockModule:
|
|
|
32
32
|
# Company Information
|
|
33
33
|
# -------------------------------------------------------------------------
|
|
34
34
|
|
|
35
|
-
def overview(
|
|
35
|
+
def overview(
|
|
36
|
+
self, symbols: str | None = None, names: str | None = None
|
|
37
|
+
) -> dict[str, Any] | list[dict[str, Any]]:
|
|
36
38
|
"""
|
|
37
39
|
Get company overview including business description, sector, and key metrics
|
|
38
40
|
|
|
39
41
|
Args:
|
|
40
|
-
|
|
42
|
+
symbols: Stock symbols. You can enter multiple items, separated by commas(,)
|
|
43
|
+
Example: "US:AAPL,US:MSFT"
|
|
44
|
+
names: Stock names. You can enter multiple items, separated by commas(,)
|
|
45
|
+
Example: "Apple Inc.,Microsoft"
|
|
41
46
|
|
|
42
47
|
Returns:
|
|
43
|
-
|
|
48
|
+
Dictionary or list of dictionaries with company overview data
|
|
44
49
|
|
|
45
50
|
Example:
|
|
46
|
-
>>>
|
|
51
|
+
>>> # Single stock by symbol
|
|
52
|
+
>>> info = client.stock.overview(symbols="US:AAPL")
|
|
47
53
|
>>> print(info["name"], info["sector"])
|
|
54
|
+
|
|
55
|
+
>>> # Multiple stocks by symbols
|
|
56
|
+
>>> infos = client.stock.overview(symbols="US:AAPL,US:MSFT")
|
|
57
|
+
>>> for info in infos:
|
|
58
|
+
... print(info["name"])
|
|
59
|
+
|
|
60
|
+
>>> # Search by name
|
|
61
|
+
>>> info = client.stock.overview(names="Apple Inc.")
|
|
48
62
|
"""
|
|
49
|
-
|
|
63
|
+
if not symbols and not names:
|
|
64
|
+
raise ValueError("Either symbols or names must be provided")
|
|
65
|
+
|
|
66
|
+
data = {}
|
|
67
|
+
if symbols:
|
|
68
|
+
data["symbols"] = symbols
|
|
69
|
+
if names:
|
|
70
|
+
data["names"] = names
|
|
71
|
+
|
|
72
|
+
response = self._post("/v1/stock/company-overview", json=data)
|
|
50
73
|
return response
|
|
51
74
|
|
|
52
|
-
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]]:
|
|
53
82
|
"""
|
|
54
83
|
Get list of major shareholders
|
|
55
84
|
|
|
56
85
|
Args:
|
|
57
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)
|
|
58
91
|
|
|
59
92
|
Returns:
|
|
60
93
|
List of shareholders with ownership details
|
|
61
94
|
"""
|
|
62
|
-
response = self._post(
|
|
95
|
+
response = self._post(
|
|
96
|
+
"/v1/stock/company-shareholders",
|
|
97
|
+
json={"symbol": symbol, "type": type, "limit": limit},
|
|
98
|
+
)
|
|
63
99
|
return response if isinstance(response, list) else response.get("shareholders", [])
|
|
64
100
|
|
|
65
101
|
# -------------------------------------------------------------------------
|
|
@@ -70,16 +106,26 @@ class StockModule:
|
|
|
70
106
|
self,
|
|
71
107
|
symbol: str,
|
|
72
108
|
*,
|
|
73
|
-
period: Literal["annual", "quarterly"] = "annual",
|
|
74
|
-
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,
|
|
75
116
|
) -> pd.DataFrame:
|
|
76
117
|
"""
|
|
77
118
|
Get income statement data
|
|
78
119
|
|
|
79
120
|
Args:
|
|
80
121
|
symbol: Stock symbol (e.g., "US:AAPL")
|
|
81
|
-
period: "annual"
|
|
82
|
-
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)")
|
|
83
129
|
|
|
84
130
|
Returns:
|
|
85
131
|
DataFrame with income statement data, indexed by date
|
|
@@ -88,10 +134,22 @@ class StockModule:
|
|
|
88
134
|
>>> income = client.stock.income_statement("US:AAPL", period="quarterly")
|
|
89
135
|
>>> print(income[["revenue", "net_income"]].head())
|
|
90
136
|
"""
|
|
91
|
-
|
|
92
|
-
"
|
|
93
|
-
|
|
94
|
-
|
|
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)
|
|
95
153
|
return self._to_dataframe(response)
|
|
96
154
|
|
|
97
155
|
def balance_sheet(
|
|
@@ -99,15 +157,25 @@ class StockModule:
|
|
|
99
157
|
symbol: str,
|
|
100
158
|
*,
|
|
101
159
|
period: Literal["annual", "quarterly"] = "annual",
|
|
102
|
-
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,
|
|
103
166
|
) -> pd.DataFrame:
|
|
104
167
|
"""
|
|
105
168
|
Get balance sheet data
|
|
106
169
|
|
|
107
170
|
Args:
|
|
108
171
|
symbol: Stock symbol
|
|
109
|
-
period: "annual"
|
|
110
|
-
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)
|
|
111
179
|
|
|
112
180
|
Returns:
|
|
113
181
|
DataFrame with balance sheet data, indexed by date
|
|
@@ -116,26 +184,48 @@ class StockModule:
|
|
|
116
184
|
>>> balance = client.stock.balance_sheet("US:AAPL")
|
|
117
185
|
>>> print(balance[["total_assets", "total_liabilities"]].head())
|
|
118
186
|
"""
|
|
119
|
-
|
|
120
|
-
"
|
|
121
|
-
|
|
122
|
-
|
|
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)
|
|
123
203
|
return self._to_dataframe(response)
|
|
124
204
|
|
|
125
205
|
def cashflow_statement(
|
|
126
206
|
self,
|
|
127
207
|
symbol: str,
|
|
128
208
|
*,
|
|
129
|
-
period: Literal["annual", "quarterly"] = "annual",
|
|
130
|
-
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,
|
|
131
216
|
) -> pd.DataFrame:
|
|
132
217
|
"""
|
|
133
218
|
Get cash flow statement data
|
|
134
219
|
|
|
135
220
|
Args:
|
|
136
221
|
symbol: Stock symbol
|
|
137
|
-
period: "annual"
|
|
138
|
-
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)")
|
|
139
229
|
|
|
140
230
|
Returns:
|
|
141
231
|
DataFrame with cash flow data, indexed by date
|
|
@@ -144,134 +234,111 @@ class StockModule:
|
|
|
144
234
|
>>> cashflow = client.stock.cashflow_statement("US:AAPL")
|
|
145
235
|
>>> print(cashflow[["operating_cashflow", "free_cashflow"]].head())
|
|
146
236
|
"""
|
|
147
|
-
|
|
148
|
-
"
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
Args:
|
|
163
|
-
symbol: Stock symbol
|
|
164
|
-
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
|
|
165
251
|
|
|
166
|
-
|
|
167
|
-
DataFrame with revenue breakdown data
|
|
168
|
-
"""
|
|
169
|
-
response = self._post(
|
|
170
|
-
"/v1/stock/company-revenue-breakdown",
|
|
171
|
-
json={"symbol": symbol, "breakdown_type": breakdown_type},
|
|
172
|
-
)
|
|
252
|
+
response = self._post("/v1/stock/company-cashflow-statement", json=data)
|
|
173
253
|
return self._to_dataframe(response)
|
|
174
254
|
|
|
175
|
-
|
|
176
|
-
# Price Data (returns DataFrame)
|
|
177
|
-
# -------------------------------------------------------------------------
|
|
178
|
-
|
|
179
|
-
def prices(
|
|
255
|
+
def revenue_breakdown(
|
|
180
256
|
self,
|
|
181
257
|
symbol: str,
|
|
182
258
|
*,
|
|
259
|
+
period: str | None = None,
|
|
260
|
+
limit: int = 6,
|
|
183
261
|
start_date: str | None = None,
|
|
184
262
|
end_date: str | None = None,
|
|
185
|
-
|
|
263
|
+
fiscal_year: str | None = None,
|
|
186
264
|
) -> pd.DataFrame:
|
|
187
265
|
"""
|
|
188
|
-
Get
|
|
266
|
+
Get revenue breakdown
|
|
189
267
|
|
|
190
268
|
Args:
|
|
191
269
|
symbol: Stock symbol
|
|
270
|
+
period: Report cycle (e.g., "FY", "Q2")
|
|
271
|
+
limit: Return latest N records (default: 6)
|
|
192
272
|
start_date: Start date (YYYY-MM-DD)
|
|
193
273
|
end_date: End date (YYYY-MM-DD)
|
|
194
|
-
|
|
274
|
+
fiscal_year: Specific fiscal year (e.g., "2023")
|
|
195
275
|
|
|
196
276
|
Returns:
|
|
197
|
-
DataFrame with
|
|
198
|
-
|
|
199
|
-
Example:
|
|
200
|
-
>>> prices = client.stock.prices("US:AAPL", limit=30)
|
|
201
|
-
>>> print(prices[["close", "volume"]].tail())
|
|
277
|
+
DataFrame with revenue breakdown data
|
|
202
278
|
"""
|
|
203
279
|
data: dict[str, Any] = {"symbol": symbol, "limit": limit}
|
|
280
|
+
if period:
|
|
281
|
+
data["period"] = period
|
|
204
282
|
if start_date:
|
|
205
283
|
data["start_date"] = start_date
|
|
206
284
|
if end_date:
|
|
207
285
|
data["end_date"] = end_date
|
|
286
|
+
if fiscal_year:
|
|
287
|
+
data["fiscal_year"] = fiscal_year
|
|
208
288
|
|
|
209
|
-
response = self._post("/v1/stock/company-
|
|
289
|
+
response = self._post("/v1/stock/company-revenue-breakdown", json=data)
|
|
210
290
|
return self._to_dataframe(response)
|
|
211
291
|
|
|
212
|
-
|
|
292
|
+
# -------------------------------------------------------------------------
|
|
293
|
+
# Price Data (returns DataFrame)
|
|
294
|
+
# -------------------------------------------------------------------------
|
|
295
|
+
|
|
296
|
+
def prices(
|
|
213
297
|
self,
|
|
214
298
|
symbol: str,
|
|
215
299
|
*,
|
|
216
|
-
interval: Literal["1d", "1w", "1m"] = "1d",
|
|
217
|
-
adjust: Literal["forward", "backward", "none"] = "forward",
|
|
218
300
|
start_date: str | None = None,
|
|
219
301
|
end_date: str | None = None,
|
|
220
|
-
limit: int = 100,
|
|
221
302
|
) -> pd.DataFrame:
|
|
222
303
|
"""
|
|
223
|
-
Get
|
|
304
|
+
Get historical stock prices with market data
|
|
224
305
|
|
|
225
306
|
Args:
|
|
226
307
|
symbol: Stock symbol
|
|
227
|
-
interval: Time interval ("1d" daily, "1w" weekly, "1m" monthly)
|
|
228
|
-
adjust: Price adjustment type
|
|
229
|
-
- "forward": Forward adjusted (前复权)
|
|
230
|
-
- "backward": Backward adjusted (后复权)
|
|
231
|
-
- "none": Unadjusted (不复权)
|
|
232
308
|
start_date: Start date (YYYY-MM-DD)
|
|
233
309
|
end_date: End date (YYYY-MM-DD)
|
|
234
|
-
limit: Maximum number of records
|
|
235
310
|
|
|
236
311
|
Returns:
|
|
237
|
-
DataFrame with
|
|
312
|
+
DataFrame with price data (date, close, volume, market_cap, pe, ps)
|
|
238
313
|
|
|
239
314
|
Example:
|
|
240
|
-
>>>
|
|
241
|
-
>>> print(
|
|
315
|
+
>>> prices = client.stock.prices("US:AAPL")
|
|
316
|
+
>>> print(prices[["close", "volume"]].tail())
|
|
242
317
|
"""
|
|
243
|
-
data: dict[str, Any] = {
|
|
244
|
-
"symbol": symbol,
|
|
245
|
-
"interval": interval,
|
|
246
|
-
"adjust": adjust,
|
|
247
|
-
"limit": limit,
|
|
248
|
-
}
|
|
318
|
+
data: dict[str, Any] = {"symbol": symbol}
|
|
249
319
|
if start_date:
|
|
250
320
|
data["start_date"] = start_date
|
|
251
321
|
if end_date:
|
|
252
322
|
data["end_date"] = end_date
|
|
253
323
|
|
|
254
|
-
response = self._post("/v1/stock/
|
|
324
|
+
response = self._post("/v1/stock/company-prices", json=data)
|
|
255
325
|
return self._to_dataframe(response)
|
|
256
326
|
|
|
257
|
-
def quote(self,
|
|
327
|
+
def quote(self, symbol: str) -> pd.DataFrame:
|
|
258
328
|
"""
|
|
259
|
-
Get real-time stock
|
|
329
|
+
Get real-time stock quote
|
|
260
330
|
|
|
261
331
|
Args:
|
|
262
|
-
|
|
332
|
+
symbol: Stock symbol (e.g., "US:AAPL", "688001", "00700")
|
|
263
333
|
|
|
264
334
|
Returns:
|
|
265
335
|
DataFrame with real-time quote data
|
|
266
336
|
|
|
267
337
|
Example:
|
|
268
|
-
>>>
|
|
269
|
-
>>> print(
|
|
338
|
+
>>> quote = client.stock.quote("US:AAPL")
|
|
339
|
+
>>> print(quote[["symbol", "price", "change_percent"]])
|
|
270
340
|
"""
|
|
271
|
-
|
|
272
|
-
symbols = [symbols]
|
|
273
|
-
|
|
274
|
-
response = self._post("/v1/stock/quote-realtime", json={"symbols": symbols})
|
|
341
|
+
response = self._post("/v1/stock/quote-realtime", json={"symbol": symbol})
|
|
275
342
|
return self._to_dataframe(response)
|
|
276
343
|
|
|
277
344
|
def index_prices(
|
|
@@ -280,21 +347,19 @@ class StockModule:
|
|
|
280
347
|
*,
|
|
281
348
|
start_date: str | None = None,
|
|
282
349
|
end_date: str | None = None,
|
|
283
|
-
limit: int = 100,
|
|
284
350
|
) -> pd.DataFrame:
|
|
285
351
|
"""
|
|
286
|
-
Get stock index prices (e.g.,
|
|
352
|
+
Get stock index prices (e.g., HSI, SPX, DJI)
|
|
287
353
|
|
|
288
354
|
Args:
|
|
289
|
-
symbol: Index symbol
|
|
355
|
+
symbol: Index symbol (e.g., "HSI", "SPX", "DJI")
|
|
290
356
|
start_date: Start date (YYYY-MM-DD)
|
|
291
357
|
end_date: End date (YYYY-MM-DD)
|
|
292
|
-
limit: Maximum number of records
|
|
293
358
|
|
|
294
359
|
Returns:
|
|
295
360
|
DataFrame with index price data
|
|
296
361
|
"""
|
|
297
|
-
data: dict[str, Any] = {"symbol": symbol
|
|
362
|
+
data: dict[str, Any] = {"symbol": symbol}
|
|
298
363
|
if start_date:
|
|
299
364
|
data["start_date"] = start_date
|
|
300
365
|
if end_date:
|
|
@@ -310,42 +375,82 @@ class StockModule:
|
|
|
310
375
|
def screener(
|
|
311
376
|
self,
|
|
312
377
|
*,
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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,
|
|
320
393
|
) -> pd.DataFrame:
|
|
321
394
|
"""
|
|
322
395
|
Screen stocks based on various criteria
|
|
323
396
|
|
|
324
397
|
Args:
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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)
|
|
332
413
|
|
|
333
414
|
Returns:
|
|
334
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
|
+
... )
|
|
335
424
|
"""
|
|
336
425
|
data: dict[str, Any] = {"limit": limit}
|
|
337
|
-
if
|
|
338
|
-
data["
|
|
339
|
-
if
|
|
340
|
-
data["
|
|
341
|
-
if
|
|
342
|
-
data["
|
|
343
|
-
if
|
|
344
|
-
data["
|
|
345
|
-
if
|
|
346
|
-
data["
|
|
347
|
-
if
|
|
348
|
-
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
|
|
349
454
|
|
|
350
455
|
response = self._post("/v1/stock/screener", json=data)
|
|
351
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", [])
|