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/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(self, symbol: str) -> list[dict[str, Any]]:
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("/v1/stock/company-shareholders", json={"symbol": symbol})
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 = 10,
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" or "quarterly"
105
- limit: Number of periods to return
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
- response = self._post(
115
- "/v1/stock/company-income-statement",
116
- json={"symbol": symbol, "period": period, "limit": limit},
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 = 10,
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" or "quarterly"
133
- limit: Number of periods to return
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
- response = self._post(
143
- "/v1/stock/company-balance-sheet",
144
- json={"symbol": symbol, "period": period, "limit": limit},
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 = 10,
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" or "quarterly"
161
- limit: Number of periods to return
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
- response = self._post(
171
- "/v1/stock/company-cashflow-statement",
172
- json={"symbol": symbol, "period": period, "limit": limit},
173
- )
174
- return self._to_dataframe(response)
175
-
176
- def revenue_breakdown(
177
- self,
178
- symbol: str,
179
- *,
180
- breakdown_type: Literal["segment", "product", "region"] = "segment",
181
- ) -> pd.DataFrame:
182
- """
183
- Get revenue breakdown by segment, product, or region
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
- Returns:
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
- limit: int = 100,
263
+ fiscal_year: str | None = None,
209
264
  ) -> pd.DataFrame:
210
265
  """
211
- Get historical stock prices with market data
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
- limit: Maximum number of records
274
+ fiscal_year: Specific fiscal year (e.g., "2023")
218
275
 
219
276
  Returns:
220
- DataFrame with price data (date, close, volume, market_cap, pe, ps)
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-prices", json=data)
289
+ response = self._post("/v1/stock/company-revenue-breakdown", json=data)
233
290
  return self._to_dataframe(response)
234
291
 
235
- def kline(
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 K-line (candlestick) data
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 OHLCV data (date, open, high, low, close, volume)
312
+ DataFrame with price data (date, close, volume, market_cap, pe, ps)
261
313
 
262
314
  Example:
263
- >>> kline = client.stock.kline("US:TSLA", interval="1d", limit=100)
264
- >>> print(kline.tail())
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/kline", json=data)
324
+ response = self._post("/v1/stock/company-prices", json=data)
278
325
  return self._to_dataframe(response)
279
326
 
280
- def quote(self, symbols: str | list[str]) -> pd.DataFrame:
327
+ def quote(self, symbol: str) -> pd.DataFrame:
281
328
  """
282
- Get real-time stock quotes
329
+ Get real-time stock quote
283
330
 
284
331
  Args:
285
- symbols: Single symbol or list of symbols
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
- >>> quotes = client.stock.quote(["US:AAPL", "US:MSFT"])
292
- >>> print(quotes[["symbol", "price", "change_percent"]])
338
+ >>> quote = client.stock.quote("US:AAPL")
339
+ >>> print(quote[["symbol", "price", "change_percent"]])
293
340
  """
294
- if isinstance(symbols, str):
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., S&P 500, NASDAQ)
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, "limit": limit}
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
- market: str | None = None,
337
- sector: str | None = None,
338
- min_market_cap: float | None = None,
339
- max_market_cap: float | None = None,
340
- min_pe: float | None = None,
341
- max_pe: float | None = None,
342
- limit: int = 50,
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
- market: Filter by market (US, HK, CN)
349
- sector: Filter by sector
350
- min_market_cap: Minimum market cap
351
- max_market_cap: Maximum market cap
352
- min_pe: Minimum P/E ratio
353
- max_pe: Maximum P/E ratio
354
- limit: Maximum number of results
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 market:
361
- data["market"] = market
362
- if sector:
363
- data["sector"] = sector
364
- if min_market_cap is not None:
365
- data["min_market_cap"] = min_market_cap
366
- if max_market_cap is not None:
367
- data["max_market_cap"] = max_market_cap
368
- if min_pe is not None:
369
- data["min_pe"] = min_pe
370
- if max_pe is not None:
371
- data["max_pe"] = max_pe
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", [])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reportify-sdk
3
- Version: 0.2.8
3
+ Version: 0.2.10
4
4
  Summary: Python SDK for Reportify API - Financial data and document search
5
5
  Author-email: Reportify <support@reportify.cn>
6
6
  License-Expression: MIT