openbb-tradingagent 1.0.0__tar.gz

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.
@@ -0,0 +1,125 @@
1
+ Metadata-Version: 2.4
2
+ Name: openbb-tradingagent
3
+ Version: 1.0.0
4
+ Summary: Point-in-time company fundamentals from tradingagentapp.com for the OpenBB Platform (US SEC EDGAR, Taiwan TWSE, Korea OpenDART).
5
+ License: MIT
6
+ Keywords: openbb,fundamentals,point-in-time,edgar,twse,opendart
7
+ Author: Trading Agent
8
+ Author-email: tradingagentapp@gmail.com
9
+ Requires-Python: >=3.10,<4
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Requires-Dist: openbb-core (>=1.6.10,<2.0.0)
18
+ Project-URL: Homepage, https://www.tradingagentapp.com/fundamentals
19
+ Project-URL: Repository, https://github.com/Wei-LienWU/trading-agent
20
+ Description-Content-Type: text/markdown
21
+
22
+ # Trading Agent provider for OpenBB
23
+
24
+ Point-in-time, **as-first-reported** company fundamentals from official regulator
25
+ filings — inside the OpenBB Platform.
26
+
27
+ | Market | Source | Coverage |
28
+ | --- | --- | --- |
29
+ | United States | SEC EDGAR (XBRL) | ~7,000 filers, annual + quarterly, FY2014→ |
30
+ | Taiwan | Taiwan Stock Exchange OpenAPI | every listed company |
31
+ | Korea | FSS OpenDART | loading (full market) |
32
+
33
+ Every value is keyed by the **official filing date it became public on**, and
34
+ queries accept an `as_of` knowledge date — so a backtest at date *T* sees only
35
+ what was public at *T*. No restatement look-ahead.
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ pip install openbb-tradingagent
41
+ openbb-build # regenerate the static assets so the provider appears
42
+ ```
43
+
44
+ ## Use
45
+
46
+ The provider attaches to OpenBB's existing fundamentals commands:
47
+
48
+ ```python
49
+ from openbb import obb
50
+
51
+ # No key needed — the demo tier covers 25 flagship tickers at full fidelity.
52
+ obb.equity.fundamental.latest_attributes(
53
+ symbol="2330.TW", tag="revenue,net_income", provider="tradingagent"
54
+ )
55
+
56
+ # Point-in-time: what did AAPL's reported revenue history look like on 2022-01-01?
57
+ obb.equity.fundamental.historical_attributes(
58
+ symbol="AAPL", tag="revenue", provider="tradingagent", as_of="2022-01-01"
59
+ )
60
+ ```
61
+
62
+ Set a key for the full universe:
63
+
64
+ ```python
65
+ obb.user.credentials.tradingagent_api_key = "ta_live_…"
66
+ ```
67
+
68
+ or in `~/.openbb_platform/user_settings.json`:
69
+
70
+ ```json
71
+ { "credentials": { "tradingagent_api_key": "ta_live_…" } }
72
+ ```
73
+
74
+ Without a key the provider falls back to the public `demo` key: 25 flagship
75
+ tickers (US, Taiwan, Korea), full history, all fields, no signup. Paid plans
76
+ unlock every ticker — your code does not change.
77
+
78
+ ## The `as_of` parameter
79
+
80
+ This is the reason the provider exists. Most fundamentals APIs serve *today's*
81
+ restated figures against *historical* dates, which quietly leaks future
82
+ information into a backtest. Here, `as_of` filters to `filed <= as_of`:
83
+
84
+ ```python
85
+ # FY2021 as it was actually reported, not as later amended
86
+ obb.equity.fundamental.latest_attributes(
87
+ symbol="AAPL", tag="revenue", provider="tradingagent", as_of="2022-01-01"
88
+ )
89
+ ```
90
+
91
+ ## Fields
92
+
93
+ `historical_attributes` returns, per row: `date` (period end), `symbol`, `tag`,
94
+ `value`, `unit`, `fiscal_year`, `fiscal_period`, `filed`, `form`, `market`,
95
+ `issuer_id`.
96
+
97
+ Available tags include `revenue`, `net_income`, `assets`, `liabilities`,
98
+ `equity`, `cash`, `gross_profit`, `operating_income`, `long_term_debt`,
99
+ `rnd_expense`, `eps_diluted`, `shares_diluted`, plus derived ratios
100
+ `net_margin`, `gross_margin`, `operating_margin`, `roe`, `roa`,
101
+ `debt_to_equity`, `asset_turnover`.
102
+
103
+ ## Data notes
104
+
105
+ - **Taiwan income-statement figures are cumulative year-to-date** (Taiwan
106
+ reporting convention): Q2 is the H1 total, Q4 the full year. Difference
107
+ adjacent quarters for single-quarter flows. Balance-sheet items are
108
+ point-in-time as usual.
109
+ - Values are as filed. Filers make mistakes; we do not silently correct them.
110
+
111
+ ## Sources and licences
112
+
113
+ - **US** — SEC EDGAR, public domain.
114
+ - **Taiwan** — Taiwan Stock Exchange, under the Open Government Data License 1.0.
115
+ The attribution is embedded in every API response and must be preserved.
116
+ - **Korea** — FSS OpenDART. Public data; the FSS confirmed in writing that no
117
+ separate approval agreement is required for commercial use.
118
+
119
+ Factual historical data only — not investment advice, not a recommendation.
120
+
121
+ Full API documentation: <https://www.tradingagentapp.com/developers>
122
+ Pricing and licences: <https://www.tradingagentapp.com/fundamentals>
123
+
124
+ MIT licensed. Operated by WU Capital Limited, Auckland, New Zealand.
125
+
@@ -0,0 +1,103 @@
1
+ # Trading Agent provider for OpenBB
2
+
3
+ Point-in-time, **as-first-reported** company fundamentals from official regulator
4
+ filings — inside the OpenBB Platform.
5
+
6
+ | Market | Source | Coverage |
7
+ | --- | --- | --- |
8
+ | United States | SEC EDGAR (XBRL) | ~7,000 filers, annual + quarterly, FY2014→ |
9
+ | Taiwan | Taiwan Stock Exchange OpenAPI | every listed company |
10
+ | Korea | FSS OpenDART | loading (full market) |
11
+
12
+ Every value is keyed by the **official filing date it became public on**, and
13
+ queries accept an `as_of` knowledge date — so a backtest at date *T* sees only
14
+ what was public at *T*. No restatement look-ahead.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pip install openbb-tradingagent
20
+ openbb-build # regenerate the static assets so the provider appears
21
+ ```
22
+
23
+ ## Use
24
+
25
+ The provider attaches to OpenBB's existing fundamentals commands:
26
+
27
+ ```python
28
+ from openbb import obb
29
+
30
+ # No key needed — the demo tier covers 25 flagship tickers at full fidelity.
31
+ obb.equity.fundamental.latest_attributes(
32
+ symbol="2330.TW", tag="revenue,net_income", provider="tradingagent"
33
+ )
34
+
35
+ # Point-in-time: what did AAPL's reported revenue history look like on 2022-01-01?
36
+ obb.equity.fundamental.historical_attributes(
37
+ symbol="AAPL", tag="revenue", provider="tradingagent", as_of="2022-01-01"
38
+ )
39
+ ```
40
+
41
+ Set a key for the full universe:
42
+
43
+ ```python
44
+ obb.user.credentials.tradingagent_api_key = "ta_live_…"
45
+ ```
46
+
47
+ or in `~/.openbb_platform/user_settings.json`:
48
+
49
+ ```json
50
+ { "credentials": { "tradingagent_api_key": "ta_live_…" } }
51
+ ```
52
+
53
+ Without a key the provider falls back to the public `demo` key: 25 flagship
54
+ tickers (US, Taiwan, Korea), full history, all fields, no signup. Paid plans
55
+ unlock every ticker — your code does not change.
56
+
57
+ ## The `as_of` parameter
58
+
59
+ This is the reason the provider exists. Most fundamentals APIs serve *today's*
60
+ restated figures against *historical* dates, which quietly leaks future
61
+ information into a backtest. Here, `as_of` filters to `filed <= as_of`:
62
+
63
+ ```python
64
+ # FY2021 as it was actually reported, not as later amended
65
+ obb.equity.fundamental.latest_attributes(
66
+ symbol="AAPL", tag="revenue", provider="tradingagent", as_of="2022-01-01"
67
+ )
68
+ ```
69
+
70
+ ## Fields
71
+
72
+ `historical_attributes` returns, per row: `date` (period end), `symbol`, `tag`,
73
+ `value`, `unit`, `fiscal_year`, `fiscal_period`, `filed`, `form`, `market`,
74
+ `issuer_id`.
75
+
76
+ Available tags include `revenue`, `net_income`, `assets`, `liabilities`,
77
+ `equity`, `cash`, `gross_profit`, `operating_income`, `long_term_debt`,
78
+ `rnd_expense`, `eps_diluted`, `shares_diluted`, plus derived ratios
79
+ `net_margin`, `gross_margin`, `operating_margin`, `roe`, `roa`,
80
+ `debt_to_equity`, `asset_turnover`.
81
+
82
+ ## Data notes
83
+
84
+ - **Taiwan income-statement figures are cumulative year-to-date** (Taiwan
85
+ reporting convention): Q2 is the H1 total, Q4 the full year. Difference
86
+ adjacent quarters for single-quarter flows. Balance-sheet items are
87
+ point-in-time as usual.
88
+ - Values are as filed. Filers make mistakes; we do not silently correct them.
89
+
90
+ ## Sources and licences
91
+
92
+ - **US** — SEC EDGAR, public domain.
93
+ - **Taiwan** — Taiwan Stock Exchange, under the Open Government Data License 1.0.
94
+ The attribution is embedded in every API response and must be preserved.
95
+ - **Korea** — FSS OpenDART. Public data; the FSS confirmed in writing that no
96
+ separate approval agreement is required for commercial use.
97
+
98
+ Factual historical data only — not investment advice, not a recommendation.
99
+
100
+ Full API documentation: <https://www.tradingagentapp.com/developers>
101
+ Pricing and licences: <https://www.tradingagentapp.com/fundamentals>
102
+
103
+ MIT licensed. Operated by WU Capital Limited, Auckland, New Zealand.
@@ -0,0 +1,34 @@
1
+ """Trading Agent provider for the OpenBB Platform.
2
+
3
+ Point-in-time, as-first-reported company fundamentals from official
4
+ regulator filings (US SEC EDGAR, Taiwan TWSE, Korea FSS OpenDART).
5
+ Every row carries its official filing date; queries can be pinned to an
6
+ `as_of` knowledge date so a backtest at date T sees only what was public
7
+ at T — no restatement look-ahead.
8
+ """
9
+
10
+ from openbb_core.provider.abstract.provider import Provider
11
+
12
+ from openbb_tradingagent.models.historical_attributes import (
13
+ TradingAgentHistoricalAttributesFetcher,
14
+ )
15
+ from openbb_tradingagent.models.latest_attributes import (
16
+ TradingAgentLatestAttributesFetcher,
17
+ )
18
+
19
+ tradingagent_provider = Provider(
20
+ name="tradingagent",
21
+ website="https://www.tradingagentapp.com",
22
+ description=(
23
+ "Point-in-time company fundamentals from official regulator filings "
24
+ "(US SEC EDGAR, Taiwan TWSE, Korea FSS OpenDART). As-first-reported "
25
+ "values keyed by filing date, with an `as_of` parameter for "
26
+ "look-ahead-free backtests. Works without a key on 25 flagship "
27
+ "tickers (demo tier); paid keys unlock the full universe."
28
+ ),
29
+ credentials=["api_key"],
30
+ fetcher_dict={
31
+ "LatestAttributes": TradingAgentLatestAttributesFetcher,
32
+ "HistoricalAttributes": TradingAgentHistoricalAttributesFetcher,
33
+ },
34
+ )
@@ -0,0 +1 @@
1
+ """Trading Agent provider models."""
@@ -0,0 +1,179 @@
1
+ """Trading Agent Historical Attributes Model."""
2
+
3
+ # pylint: disable=unused-argument
4
+
5
+ from datetime import date as dateType
6
+ from typing import Any, Dict, List, Optional
7
+
8
+ from openbb_core.provider.abstract.fetcher import Fetcher
9
+ from openbb_core.provider.standard_models.historical_attributes import (
10
+ HistoricalAttributesData,
11
+ HistoricalAttributesQueryParams,
12
+ )
13
+ from openbb_core.provider.utils.errors import EmptyDataError
14
+ from pydantic import Field, field_validator
15
+
16
+ from openbb_tradingagent.utils.helpers import get_data
17
+
18
+
19
+ class TradingAgentHistoricalAttributesQueryParams(HistoricalAttributesQueryParams):
20
+ """Trading Agent Historical Attributes Query.
21
+
22
+ Source: https://www.tradingagentapp.com/developers#fundamentals
23
+ """
24
+
25
+ as_of: Optional[dateType] = Field(
26
+ default=None,
27
+ description=(
28
+ "Point-in-time knowledge date. Only facts whose official filing date"
29
+ " is on or before this date are returned, so a backtest at date T"
30
+ " sees exactly what was public at T (no restatement look-ahead)."
31
+ ),
32
+ )
33
+
34
+
35
+ class TradingAgentHistoricalAttributesData(HistoricalAttributesData):
36
+ """Trading Agent Historical Attributes Data.
37
+
38
+ One as-first-reported fact: a metric for one fiscal period, keyed by the
39
+ official filing date it became public on.
40
+ """
41
+
42
+ # All source-key mappings live here; do not use Field(alias=...) — the
43
+ # base Data model installs a camelCase alias generator that would win.
44
+ __alias_dict__ = {
45
+ "date": "end",
46
+ "symbol": "t",
47
+ "tag": "m",
48
+ "value": "v",
49
+ "unit": "u",
50
+ "fiscal_year": "fy",
51
+ "fiscal_period": "fp",
52
+ "market": "mkt",
53
+ "issuer_id": "c",
54
+ }
55
+
56
+ unit: Optional[str] = Field(
57
+ default=None,
58
+ description="Unit of measure (USD, shares, USD/shares, ratio, …).",
59
+ )
60
+ fiscal_year: Optional[int] = Field(
61
+ default=None,
62
+ description="Fiscal year of the period end.",
63
+ )
64
+ fiscal_period: Optional[str] = Field(
65
+ default=None,
66
+ description="Fiscal period (FY, Q1, Q2, Q3, Q4).",
67
+ )
68
+ filed: Optional[dateType] = Field(
69
+ default=None,
70
+ description="Official filing date — the point-in-time key.",
71
+ )
72
+ form: Optional[str] = Field(
73
+ default=None,
74
+ description="Source filing form type, where the regulator publishes one.",
75
+ )
76
+ market: Optional[str] = Field(
77
+ default=None,
78
+ description="Market the issuer is listed in (US, TW, KR, …).",
79
+ )
80
+ issuer_id: Optional[str] = Field(
81
+ default=None,
82
+ description="Regulator's own issuer identifier (SEC CIK, TWSE/DART code).",
83
+ )
84
+
85
+ @field_validator("value", mode="before", check_fields=False)
86
+ @classmethod
87
+ def validate_value(cls, v):
88
+ """Coerce numeric strings; drop anything non-numeric."""
89
+ if v is None or isinstance(v, float):
90
+ return v
91
+ try:
92
+ return float(v)
93
+ except (TypeError, ValueError):
94
+ return None
95
+
96
+
97
+ class TradingAgentHistoricalAttributesFetcher(
98
+ Fetcher[
99
+ TradingAgentHistoricalAttributesQueryParams,
100
+ List[TradingAgentHistoricalAttributesData],
101
+ ]
102
+ ):
103
+ """Trading Agent Historical Attributes Fetcher."""
104
+
105
+ # The public `demo` key covers 25 flagship tickers at full fidelity, so the
106
+ # provider is usable before signup. Leaving this True would make OpenBB
107
+ # refuse the call outright when no key is configured.
108
+ require_credentials = False
109
+
110
+ @staticmethod
111
+ def transform_query(
112
+ params: Dict[str, Any]
113
+ ) -> TradingAgentHistoricalAttributesQueryParams:
114
+ """Transform the query params."""
115
+ return TradingAgentHistoricalAttributesQueryParams(**params)
116
+
117
+ @staticmethod
118
+ async def aextract_data(
119
+ query: TradingAgentHistoricalAttributesQueryParams,
120
+ credentials: Optional[Dict[str, str]],
121
+ **kwargs: Any,
122
+ ) -> List[Dict]:
123
+ """Extract the raw rows, one request per symbol."""
124
+ api_key = (credentials or {}).get("tradingagent_api_key")
125
+ symbols = [s.strip().upper() for s in query.symbol.split(",") if s.strip()]
126
+
127
+ results: List[Dict] = []
128
+ for symbol in symbols:
129
+ response = await get_data(
130
+ "/fundamentals",
131
+ {
132
+ "ticker": symbol,
133
+ "as_of": query.as_of.isoformat() if query.as_of else None,
134
+ "from": query.start_date.isoformat() if query.start_date else None,
135
+ },
136
+ api_key,
137
+ **kwargs,
138
+ )
139
+ rows = response.get("data", []) if isinstance(response, dict) else []
140
+ # The API returns the ticker on the envelope, not on every row.
141
+ for row in rows:
142
+ row.setdefault("t", response.get("ticker", symbol))
143
+ results.extend(rows)
144
+
145
+ if not results:
146
+ raise EmptyDataError(
147
+ f"No fundamentals returned for {query.symbol}"
148
+ + (f" as of {query.as_of}" if query.as_of else "")
149
+ + ". Either the ticker is outside the covered universe, or no"
150
+ " filing was public by that date — each market's history depth"
151
+ " is listed at https://www.tradingagentapp.com/api/v1/fundamentals"
152
+ )
153
+ return results
154
+
155
+ @staticmethod
156
+ def transform_data(
157
+ query: TradingAgentHistoricalAttributesQueryParams,
158
+ data: List[Dict],
159
+ **kwargs: Any,
160
+ ) -> List[TradingAgentHistoricalAttributesData]:
161
+ """Filter to the requested tags and sort."""
162
+ tags = {t.strip().lower() for t in query.tag.split(",") if t.strip()}
163
+ rows = [r for r in data if not tags or str(r.get("m", "")).lower() in tags]
164
+
165
+ if query.end_date:
166
+ rows = [r for r in rows if str(r.get("end", "")) <= query.end_date.isoformat()]
167
+
168
+ rows.sort(key=lambda r: str(r.get("end", "")), reverse=query.sort == "desc")
169
+ if query.limit:
170
+ rows = rows[: query.limit]
171
+
172
+ if not rows:
173
+ raise EmptyDataError(
174
+ f"No rows for tag(s) '{query.tag}'. Discover the available metric"
175
+ " names from the API index at /api/v1/fundamentals."
176
+ )
177
+ return [
178
+ TradingAgentHistoricalAttributesData.model_validate(r) for r in rows
179
+ ]
@@ -0,0 +1,140 @@
1
+ """Trading Agent Latest Attributes Model."""
2
+
3
+ # pylint: disable=unused-argument
4
+
5
+ from datetime import date as dateType
6
+ from typing import Any, Dict, List, Optional
7
+
8
+ from openbb_core.provider.abstract.fetcher import Fetcher
9
+ from openbb_core.provider.standard_models.latest_attributes import (
10
+ LatestAttributesData,
11
+ LatestAttributesQueryParams,
12
+ )
13
+ from openbb_core.provider.utils.errors import EmptyDataError
14
+ from pydantic import Field
15
+
16
+ from openbb_tradingagent.utils.helpers import get_data
17
+
18
+
19
+ class TradingAgentLatestAttributesQueryParams(LatestAttributesQueryParams):
20
+ """Trading Agent Latest Attributes Query.
21
+
22
+ Source: https://www.tradingagentapp.com/developers#fundamentals
23
+ """
24
+
25
+ as_of: Optional[dateType] = Field(
26
+ default=None,
27
+ description=(
28
+ "Point-in-time knowledge date. Returns the latest value per metric"
29
+ " that was already public on this date — 'latest' as of then, not"
30
+ " today's restated figure. Defaults to today."
31
+ ),
32
+ )
33
+
34
+
35
+ class TradingAgentLatestAttributesData(LatestAttributesData):
36
+ """Trading Agent Latest Attributes Data.
37
+
38
+ The most recent as-first-reported value per metric, with the fiscal period
39
+ and filing date that produced it.
40
+ """
41
+
42
+ unit: Optional[str] = Field(
43
+ default=None,
44
+ description="Unit of measure (USD, shares, USD/shares, ratio, …).",
45
+ )
46
+ fiscal_year: Optional[int] = Field(
47
+ default=None, description="Fiscal year of the period end."
48
+ )
49
+ period_ending: Optional[dateType] = Field(
50
+ default=None, description="Period end date of the reported value."
51
+ )
52
+ filed: Optional[dateType] = Field(
53
+ default=None,
54
+ description="Official filing date — the point-in-time key.",
55
+ )
56
+
57
+
58
+ class TradingAgentLatestAttributesFetcher(
59
+ Fetcher[
60
+ TradingAgentLatestAttributesQueryParams,
61
+ List[TradingAgentLatestAttributesData],
62
+ ]
63
+ ):
64
+ """Trading Agent Latest Attributes Fetcher."""
65
+
66
+ # The public `demo` key covers 25 flagship tickers at full fidelity, so the
67
+ # provider is usable before signup. Leaving this True would make OpenBB
68
+ # refuse the call outright when no key is configured.
69
+ require_credentials = False
70
+
71
+ @staticmethod
72
+ def transform_query(
73
+ params: Dict[str, Any]
74
+ ) -> TradingAgentLatestAttributesQueryParams:
75
+ """Transform the query params."""
76
+ return TradingAgentLatestAttributesQueryParams(**params)
77
+
78
+ @staticmethod
79
+ async def aextract_data(
80
+ query: TradingAgentLatestAttributesQueryParams,
81
+ credentials: Optional[Dict[str, str]],
82
+ **kwargs: Any,
83
+ ) -> List[Dict]:
84
+ """Extract the as-of snapshot and flatten it to one row per metric."""
85
+ api_key = (credentials or {}).get("tradingagent_api_key")
86
+ symbols = [s.strip().upper() for s in query.symbol.split(",") if s.strip()]
87
+
88
+ results: List[Dict] = []
89
+ for symbol in symbols:
90
+ response = await get_data(
91
+ "/fundamentals",
92
+ {
93
+ "ticker": symbol,
94
+ "view": "latest",
95
+ "as_of": query.as_of.isoformat() if query.as_of else None,
96
+ },
97
+ api_key,
98
+ **kwargs,
99
+ )
100
+ snapshot = response.get("data", {}) if isinstance(response, dict) else {}
101
+ for metric, fact in snapshot.items():
102
+ results.append(
103
+ {
104
+ "symbol": response.get("ticker", symbol),
105
+ "tag": metric,
106
+ "value": fact.get("value"),
107
+ "unit": fact.get("unit"),
108
+ "fiscal_year": fact.get("fy"),
109
+ "period_ending": fact.get("end"),
110
+ "filed": fact.get("filed"),
111
+ }
112
+ )
113
+
114
+ if not results:
115
+ raise EmptyDataError(
116
+ f"No fundamentals returned for {query.symbol}"
117
+ + (f" as of {query.as_of}" if query.as_of else "")
118
+ + ". Either the ticker is outside the covered universe, or no"
119
+ " filing was public by that date — each market's history depth"
120
+ " is listed at https://www.tradingagentapp.com/api/v1/fundamentals"
121
+ )
122
+ return results
123
+
124
+ @staticmethod
125
+ def transform_data(
126
+ query: TradingAgentLatestAttributesQueryParams,
127
+ data: List[Dict],
128
+ **kwargs: Any,
129
+ ) -> List[TradingAgentLatestAttributesData]:
130
+ """Filter to the requested tags."""
131
+ tags = {t.strip().lower() for t in query.tag.split(",") if t.strip()}
132
+ rows = [r for r in data if not tags or str(r["tag"]).lower() in tags]
133
+
134
+ if not rows:
135
+ available = sorted({str(r["tag"]) for r in data})
136
+ raise EmptyDataError(
137
+ f"No values for tag(s) '{query.tag}'. Available for this ticker: "
138
+ + ", ".join(available)
139
+ )
140
+ return [TradingAgentLatestAttributesData.model_validate(r) for r in rows]
@@ -0,0 +1 @@
1
+ """Trading Agent provider utilities."""
@@ -0,0 +1,33 @@
1
+ """Trading Agent provider helpers."""
2
+
3
+ import os
4
+ from typing import Any, Dict, Optional
5
+
6
+ from openbb_core.provider.utils.helpers import amake_request
7
+
8
+ BASE_URL = os.environ.get(
9
+ "TRADINGAGENT_BASE_URL", "https://www.tradingagentapp.com/api/v1"
10
+ )
11
+
12
+
13
+ async def get_data(
14
+ path: str,
15
+ params: Dict[str, Any],
16
+ api_key: Optional[str],
17
+ **kwargs: Any,
18
+ ) -> Any:
19
+ """GET a Trading Agent API path with Bearer auth; None params are dropped.
20
+
21
+ Falls back to the public `demo` key (25 flagship tickers, full history)
22
+ when no key is configured.
23
+ """
24
+ query = "&".join(f"{k}={v}" for k, v in params.items() if v is not None)
25
+ url = f"{BASE_URL}{path}" + (f"?{query}" if query else "")
26
+ headers = {"Authorization": f"Bearer {api_key or 'demo'}"}
27
+ response = await amake_request(url, headers=headers, **kwargs)
28
+ if isinstance(response, dict) and response.get("error"):
29
+ raise RuntimeError(
30
+ f"Trading Agent API error '{response['error']}': "
31
+ f"{response.get('message', '')}"
32
+ )
33
+ return response
@@ -0,0 +1,27 @@
1
+ [tool.poetry]
2
+ name = "openbb-tradingagent"
3
+ version = "1.0.0"
4
+ description = "Point-in-time company fundamentals from tradingagentapp.com for the OpenBB Platform (US SEC EDGAR, Taiwan TWSE, Korea OpenDART)."
5
+ authors = ["Trading Agent <tradingagentapp@gmail.com>"]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+ homepage = "https://www.tradingagentapp.com/fundamentals"
9
+ repository = "https://github.com/Wei-LienWU/trading-agent"
10
+ keywords = ["openbb", "fundamentals", "point-in-time", "edgar", "twse", "opendart"]
11
+ packages = [{ include = "openbb_tradingagent" }]
12
+
13
+ [tool.poetry.dependencies]
14
+ python = ">=3.10,<4"
15
+ openbb-core = "^1.6.10"
16
+
17
+ [build-system]
18
+ requires = ["poetry-core"]
19
+ build-backend = "poetry.core.masonry.api"
20
+
21
+ [tool.poetry.plugins."openbb_provider_extension"]
22
+ tradingagent = "openbb_tradingagent:tradingagent_provider"
23
+
24
+ [tool.pytest.ini_options]
25
+ markers = [
26
+ "record_http: OpenBB's VCR marker — replays cassettes inside the OpenBB repo, hits the live API standalone.",
27
+ ]