tradingagents-finzdata 0.1.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.
- tradingagents_finzdata-0.1.0/LICENSE +21 -0
- tradingagents_finzdata-0.1.0/PKG-INFO +83 -0
- tradingagents_finzdata-0.1.0/README.md +60 -0
- tradingagents_finzdata-0.1.0/pyproject.toml +31 -0
- tradingagents_finzdata-0.1.0/setup.cfg +4 -0
- tradingagents_finzdata-0.1.0/tradingagents_finzdata/__init__.py +460 -0
- tradingagents_finzdata-0.1.0/tradingagents_finzdata.egg-info/PKG-INFO +83 -0
- tradingagents_finzdata-0.1.0/tradingagents_finzdata.egg-info/SOURCES.txt +9 -0
- tradingagents_finzdata-0.1.0/tradingagents_finzdata.egg-info/dependency_links.txt +1 -0
- tradingagents_finzdata-0.1.0/tradingagents_finzdata.egg-info/requires.txt +5 -0
- tradingagents_finzdata-0.1.0/tradingagents_finzdata.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FinzData
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tradingagents-finzdata
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: FinzData as a data vendor for TradingAgents: point-in-time, survivorship-free prices, SEC statements as filed and macro without look-ahead.
|
|
5
|
+
Author-email: FinzData <info@finzdata.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://finzdata.com/tradingagents
|
|
8
|
+
Project-URL: Documentation, https://finzdata.com/docs
|
|
9
|
+
Project-URL: Source, https://github.com/FinzData/tradingagents-finzdata
|
|
10
|
+
Keywords: tradingagents,finzdata,market-data,backtesting,llm,agents,point-in-time,survivorship-bias
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
14
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: finzdata>=0.1.14
|
|
19
|
+
Requires-Dist: pandas>=2.0
|
|
20
|
+
Provides-Extra: tradingagents
|
|
21
|
+
Requires-Dist: tradingagents; extra == "tradingagents"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# tradingagents-finzdata
|
|
25
|
+
|
|
26
|
+
FinzData as a data vendor for TradingAgents (https://github.com/TauricResearch/TradingAgents): point-in-time, survivorship-free data so your agents' backtests hold up.
|
|
27
|
+
|
|
28
|
+
## Why FinzData
|
|
29
|
+
|
|
30
|
+
TradingAgents' default price vendor only knows stocks that still trade, so backtests silently drop the failures (survivorship bias). FinzData includes delisted stocks, point in time. Macro values are served as known on the analysis date (no look-ahead from later revisions). Statements as filed with the SEC.
|
|
31
|
+
|
|
32
|
+
## Coverage
|
|
33
|
+
|
|
34
|
+
16,000+ US stocks that have traded on NYSE and Nasdaq since January 2000, delisted included, point in time; 231 ETFs; 139 futures markets with every contract since 2007; GEX for single stocks, ETFs and the major indexes; COT since 1986; 13F; SEC fundamentals as filed; 18,000+ macro series with every vintage kept; crypto since 2015.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
`pip install tradingagents-finzdata` and set `FINZDATA_API_KEY` (free key, email only, 12 months of data: https://finzdata.com/account?ref=tradingagents ; full history from $19 per ticker or $195 for 5 years of the whole US market, yours to keep: https://finzdata.com/shop?ref=tradingagents).
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
|
44
|
+
from tradingagents_finzdata import register, finzdata_config
|
|
45
|
+
register() # adds "finzdata" as a vendor
|
|
46
|
+
config = finzdata_config() # prices, indicators, fundamentals and macro from FinzData
|
|
47
|
+
ta = TradingAgentsGraph(debug=True, config=config)
|
|
48
|
+
_, decision = ta.propagate("NVDA", "2024-05-10")
|
|
49
|
+
print(decision)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Mix and match
|
|
53
|
+
|
|
54
|
+
Use FinzData as primary with fallback:
|
|
55
|
+
|
|
56
|
+
config["data_vendors"]["core_stock_apis"] = "finzdata,yfinance"
|
|
57
|
+
|
|
58
|
+
Tool-level override:
|
|
59
|
+
|
|
60
|
+
config["tool_vendors"]["get_macro_indicators"] = "finzdata"
|
|
61
|
+
|
|
62
|
+
## Tool mapping
|
|
63
|
+
|
|
64
|
+
| TradingAgents tool | FinzData source |
|
|
65
|
+
|---|---|
|
|
66
|
+
| get_stock_data | daily bars |
|
|
67
|
+
| get_indicators | computed from FinzData bars: close_50_sma, close_200_sma, close_10_ema, macd, macds, macdh, rsi, boll, boll_ub, boll_lb, atr, vwma |
|
|
68
|
+
| get_balance_sheet / get_cashflow / get_income_statement | SEC statements as filed, as of the analysis date |
|
|
69
|
+
| get_fundamentals | profile + point-in-time valuation |
|
|
70
|
+
| get_insider_transactions | SEC Form 4 |
|
|
71
|
+
| get_macro_indicators | 18,000+ series, point in time, aliases cpi, core_cpi, pce, unemployment, payrolls, gdp, fed_funds, 10y_treasury, 2y_treasury, yield_curve, m2, initial_claims |
|
|
72
|
+
|
|
73
|
+
## Errors
|
|
74
|
+
|
|
75
|
+
missing key -> vendor not configured (next vendor in your chain is used); history beyond your plan -> vendor unavailable with a link, never a fake "no data".
|
|
76
|
+
|
|
77
|
+
## Also
|
|
78
|
+
|
|
79
|
+
The FinzData MCP server https://api.finzdata.com/mcp for Claude, ChatGPT and Cursor; docs https://finzdata.com/docs.
|
|
80
|
+
|
|
81
|
+
MIT licence. "FinzData is not affiliated with TauricResearch or the TradingAgents project." Support info@finzdata.com.
|
|
82
|
+
|
|
83
|
+
FinzData: built for AI, quants, data scientists and financial analysts who backtest. Clean data. Real insights. Real alpha.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# tradingagents-finzdata
|
|
2
|
+
|
|
3
|
+
FinzData as a data vendor for TradingAgents (https://github.com/TauricResearch/TradingAgents): point-in-time, survivorship-free data so your agents' backtests hold up.
|
|
4
|
+
|
|
5
|
+
## Why FinzData
|
|
6
|
+
|
|
7
|
+
TradingAgents' default price vendor only knows stocks that still trade, so backtests silently drop the failures (survivorship bias). FinzData includes delisted stocks, point in time. Macro values are served as known on the analysis date (no look-ahead from later revisions). Statements as filed with the SEC.
|
|
8
|
+
|
|
9
|
+
## Coverage
|
|
10
|
+
|
|
11
|
+
16,000+ US stocks that have traded on NYSE and Nasdaq since January 2000, delisted included, point in time; 231 ETFs; 139 futures markets with every contract since 2007; GEX for single stocks, ETFs and the major indexes; COT since 1986; 13F; SEC fundamentals as filed; 18,000+ macro series with every vintage kept; crypto since 2015.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
`pip install tradingagents-finzdata` and set `FINZDATA_API_KEY` (free key, email only, 12 months of data: https://finzdata.com/account?ref=tradingagents ; full history from $19 per ticker or $195 for 5 years of the whole US market, yours to keep: https://finzdata.com/shop?ref=tradingagents).
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
|
21
|
+
from tradingagents_finzdata import register, finzdata_config
|
|
22
|
+
register() # adds "finzdata" as a vendor
|
|
23
|
+
config = finzdata_config() # prices, indicators, fundamentals and macro from FinzData
|
|
24
|
+
ta = TradingAgentsGraph(debug=True, config=config)
|
|
25
|
+
_, decision = ta.propagate("NVDA", "2024-05-10")
|
|
26
|
+
print(decision)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Mix and match
|
|
30
|
+
|
|
31
|
+
Use FinzData as primary with fallback:
|
|
32
|
+
|
|
33
|
+
config["data_vendors"]["core_stock_apis"] = "finzdata,yfinance"
|
|
34
|
+
|
|
35
|
+
Tool-level override:
|
|
36
|
+
|
|
37
|
+
config["tool_vendors"]["get_macro_indicators"] = "finzdata"
|
|
38
|
+
|
|
39
|
+
## Tool mapping
|
|
40
|
+
|
|
41
|
+
| TradingAgents tool | FinzData source |
|
|
42
|
+
|---|---|
|
|
43
|
+
| get_stock_data | daily bars |
|
|
44
|
+
| get_indicators | computed from FinzData bars: close_50_sma, close_200_sma, close_10_ema, macd, macds, macdh, rsi, boll, boll_ub, boll_lb, atr, vwma |
|
|
45
|
+
| get_balance_sheet / get_cashflow / get_income_statement | SEC statements as filed, as of the analysis date |
|
|
46
|
+
| get_fundamentals | profile + point-in-time valuation |
|
|
47
|
+
| get_insider_transactions | SEC Form 4 |
|
|
48
|
+
| get_macro_indicators | 18,000+ series, point in time, aliases cpi, core_cpi, pce, unemployment, payrolls, gdp, fed_funds, 10y_treasury, 2y_treasury, yield_curve, m2, initial_claims |
|
|
49
|
+
|
|
50
|
+
## Errors
|
|
51
|
+
|
|
52
|
+
missing key -> vendor not configured (next vendor in your chain is used); history beyond your plan -> vendor unavailable with a link, never a fake "no data".
|
|
53
|
+
|
|
54
|
+
## Also
|
|
55
|
+
|
|
56
|
+
The FinzData MCP server https://api.finzdata.com/mcp for Claude, ChatGPT and Cursor; docs https://finzdata.com/docs.
|
|
57
|
+
|
|
58
|
+
MIT licence. "FinzData is not affiliated with TauricResearch or the TradingAgents project." Support info@finzdata.com.
|
|
59
|
+
|
|
60
|
+
FinzData: built for AI, quants, data scientists and financial analysts who backtest. Clean data. Real insights. Real alpha.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tradingagents-finzdata"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "FinzData as a data vendor for TradingAgents: point-in-time, survivorship-free prices, SEC statements as filed and macro without look-ahead."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
authors = [{ name = "FinzData", email = "info@finzdata.com" }]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
dependencies = ["finzdata>=0.1.14", "pandas>=2.0"]
|
|
14
|
+
keywords = ["tradingagents", "finzdata", "market-data", "backtesting", "llm", "agents", "point-in-time", "survivorship-bias"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
19
|
+
"Topic :: Office/Business :: Financial :: Investment",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
tradingagents = ["tradingagents"]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://finzdata.com/tradingagents"
|
|
27
|
+
Documentation = "https://finzdata.com/docs"
|
|
28
|
+
Source = "https://github.com/FinzData/tradingagents-finzdata"
|
|
29
|
+
|
|
30
|
+
[tool.setuptools]
|
|
31
|
+
packages = ["tradingagents_finzdata"]
|
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FinzData vendor for TradingAgents.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
from finzdata.integrations.tradingagents.tradingagents_finzdata import register, finzdata_config
|
|
6
|
+
register()
|
|
7
|
+
config = finzdata_config()
|
|
8
|
+
from tradingagents.graph import TradingAgentsGraph
|
|
9
|
+
graph = TradingAgentsGraph(config=config)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import copy
|
|
15
|
+
import os
|
|
16
|
+
from datetime import date, datetime, timedelta
|
|
17
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
18
|
+
|
|
19
|
+
import pandas as pd
|
|
20
|
+
|
|
21
|
+
VENDOR = "finzdata"
|
|
22
|
+
__version__ = "0.1.0"
|
|
23
|
+
|
|
24
|
+
_CLIENT: Optional[Any] = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def set_client(client: Any) -> None:
|
|
28
|
+
"""Set a custom FinzData client instance."""
|
|
29
|
+
global _CLIENT
|
|
30
|
+
_CLIENT = client
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _client() -> Any:
|
|
34
|
+
"""Get or create the FinzData client."""
|
|
35
|
+
global _CLIENT
|
|
36
|
+
if _CLIENT is not None:
|
|
37
|
+
return _CLIENT
|
|
38
|
+
# Lazy import to avoid network at import time
|
|
39
|
+
import finzdata
|
|
40
|
+
_CLIENT = finzdata.Client()
|
|
41
|
+
return _CLIENT
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _call(fn: Callable[..., Any], *args: Any, **kwargs: Any) -> Any:
|
|
45
|
+
"""Call a client method with exception mapping."""
|
|
46
|
+
try:
|
|
47
|
+
return fn(*args, **kwargs)
|
|
48
|
+
except ValueError:
|
|
49
|
+
raise # bad arguments (e.g. unknown indicator); VendorNotConfiguredError is also a ValueError
|
|
50
|
+
except Exception as e:
|
|
51
|
+
try:
|
|
52
|
+
from tradingagents.dataflows.errors import VendorError
|
|
53
|
+
if isinstance(e, VendorError):
|
|
54
|
+
raise # already a TradingAgents verdict (no data / unavailable / not configured)
|
|
55
|
+
except ImportError:
|
|
56
|
+
pass
|
|
57
|
+
# Map FinzError with status attribute
|
|
58
|
+
status = getattr(e, "status", None)
|
|
59
|
+
if status in (401, 403):
|
|
60
|
+
from tradingagents.dataflows.errors import VendorNotConfiguredError
|
|
61
|
+
raise VendorNotConfiguredError(
|
|
62
|
+
"FinzData needs an API key: set FINZDATA_API_KEY. Free key (email only, 12 months "
|
|
63
|
+
"of data): https://finzdata.com/account?ref=tradingagents"
|
|
64
|
+
) from e
|
|
65
|
+
if status == 402:
|
|
66
|
+
from tradingagents.dataflows.errors import VendorUnavailableError
|
|
67
|
+
raise VendorUnavailableError(
|
|
68
|
+
"FinzData returned no rows for this range. Free accounts cover the last 12 months; "
|
|
69
|
+
"every US stock since 2000 (delisted included) is at "
|
|
70
|
+
"https://finzdata.com/shop?ref=tradingagents . This says nothing about the symbol."
|
|
71
|
+
) from e
|
|
72
|
+
if status == 429 or (status is not None and status >= 500):
|
|
73
|
+
from tradingagents.dataflows.errors import VendorUnavailableError
|
|
74
|
+
raise VendorUnavailableError(f"FinzData unavailable: {e}") from e
|
|
75
|
+
# Network errors or other exceptions
|
|
76
|
+
from tradingagents.dataflows.errors import VendorUnavailableError
|
|
77
|
+
raise VendorUnavailableError(f"FinzData unavailable: {e}") from e
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_stock_data(symbol: str, start_date: str, end_date: str) -> str:
|
|
81
|
+
"""Get stock price data from FinzData."""
|
|
82
|
+
from tradingagents.dataflows.errors import NoMarketDataError, VendorUnavailableError
|
|
83
|
+
|
|
84
|
+
client = _client()
|
|
85
|
+
df = _call(client.prices, symbol, start=start_date, end=end_date)
|
|
86
|
+
|
|
87
|
+
if df is None or df.empty:
|
|
88
|
+
# Check if start_date is more than 365 days before today
|
|
89
|
+
try:
|
|
90
|
+
start_dt = datetime.strptime(start_date, "%Y-%m-%d").date()
|
|
91
|
+
if (date.today() - start_dt).days > 365:
|
|
92
|
+
raise VendorUnavailableError(
|
|
93
|
+
"FinzData returned no rows for this range. Free accounts cover the last 12 months; "
|
|
94
|
+
"every US stock since 2000 (delisted included) is at "
|
|
95
|
+
"https://finzdata.com/shop?ref=tradingagents . This says nothing about the symbol."
|
|
96
|
+
)
|
|
97
|
+
except ValueError:
|
|
98
|
+
pass
|
|
99
|
+
raise NoMarketDataError(symbol, symbol, f"no FinzData rows between {start_date} and {end_date}")
|
|
100
|
+
|
|
101
|
+
# Ensure date column is string YYYY-MM-DD
|
|
102
|
+
df = df.copy()
|
|
103
|
+
if "date" in df.columns:
|
|
104
|
+
df["date"] = pd.to_datetime(df["date"]).dt.strftime("%Y-%m-%d")
|
|
105
|
+
# Filter date <= end_date
|
|
106
|
+
df = df[df["date"] <= end_date]
|
|
107
|
+
# Round prices to 2 decimals
|
|
108
|
+
for col in ["open", "high", "low", "close"]:
|
|
109
|
+
if col in df.columns:
|
|
110
|
+
df[col] = df[col].round(2)
|
|
111
|
+
# Select and order columns
|
|
112
|
+
if "volume" in df.columns:
|
|
113
|
+
df["volume"] = pd.to_numeric(df["volume"], errors="coerce").round().astype("Int64")
|
|
114
|
+
cols = ["date", "open", "high", "low", "close", "volume"]
|
|
115
|
+
df = df[cols]
|
|
116
|
+
# Rename columns to match expected CSV header: Date,Open,High,Low,Close,Volume
|
|
117
|
+
df.columns = ["Date", "Open", "High", "Low", "Close", "Volume"]
|
|
118
|
+
# Header
|
|
119
|
+
header = (
|
|
120
|
+
f"# Stock data for {symbol.upper()} from {start_date} to {end_date} "
|
|
121
|
+
f"(FinzData: point in time, delisted included)\n"
|
|
122
|
+
f"# Total records: {len(df)}\n\n"
|
|
123
|
+
)
|
|
124
|
+
csv_data = df.to_csv(index=False, header=True)
|
|
125
|
+
return header + csv_data
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def get_indicators(symbol: str, indicator: str, as_of_date: str, look_back_days: int) -> str:
|
|
129
|
+
"""Get technical indicator values from FinzData."""
|
|
130
|
+
from tradingagents.dataflows.errors import NoMarketDataError, VendorUnavailableError
|
|
131
|
+
|
|
132
|
+
supported = {
|
|
133
|
+
"close_50_sma": "50-day Simple Moving Average of close",
|
|
134
|
+
"close_200_sma": "200-day Simple Moving Average of close",
|
|
135
|
+
"close_10_ema": "10-day Exponential Moving Average of close",
|
|
136
|
+
"macd": "MACD line (EMA 12 - EMA 26)",
|
|
137
|
+
"macds": "MACD signal line (9-day EMA of MACD)",
|
|
138
|
+
"macdh": "MACD histogram (MACD - signal)",
|
|
139
|
+
"rsi": "Relative Strength Index (14-day Wilder)",
|
|
140
|
+
"boll": "Bollinger Bands middle (20-day SMA)",
|
|
141
|
+
"boll_ub": "Bollinger Bands upper (20-day SMA + 2 std)",
|
|
142
|
+
"boll_lb": "Bollinger Bands lower (20-day SMA - 2 std)",
|
|
143
|
+
"atr": "Average True Range (14-day)",
|
|
144
|
+
"vwma": "Volume Weighted Moving Average (20-day)",
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if indicator not in supported:
|
|
148
|
+
raise ValueError(
|
|
149
|
+
f"Unsupported indicator: {indicator}. Supported: {', '.join(sorted(supported.keys()))}"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
client = _client()
|
|
153
|
+
as_of_dt = datetime.strptime(as_of_date, "%Y-%m-%d").date()
|
|
154
|
+
start_dt = as_of_dt - timedelta(days=look_back_days + 400)
|
|
155
|
+
start_str = start_dt.strftime("%Y-%m-%d")
|
|
156
|
+
|
|
157
|
+
df = _call(client.prices, symbol, start=start_str, end=as_of_date)
|
|
158
|
+
|
|
159
|
+
if df is None or df.empty:
|
|
160
|
+
raise NoMarketDataError(symbol, symbol, f"no FinzData rows for indicator calculation")
|
|
161
|
+
|
|
162
|
+
df = df.copy()
|
|
163
|
+
df["date"] = pd.to_datetime(df["date"])
|
|
164
|
+
df = df.sort_values("date")
|
|
165
|
+
|
|
166
|
+
close = df["close"]
|
|
167
|
+
high = df["high"]
|
|
168
|
+
low = df["low"]
|
|
169
|
+
volume = df["volume"]
|
|
170
|
+
|
|
171
|
+
# Compute indicators
|
|
172
|
+
if indicator == "close_50_sma":
|
|
173
|
+
values = close.rolling(50).mean()
|
|
174
|
+
elif indicator == "close_200_sma":
|
|
175
|
+
values = close.rolling(200).mean()
|
|
176
|
+
elif indicator == "close_10_ema":
|
|
177
|
+
values = close.ewm(span=10, adjust=False).mean()
|
|
178
|
+
elif indicator == "macd":
|
|
179
|
+
ema12 = close.ewm(span=12, adjust=False).mean()
|
|
180
|
+
ema26 = close.ewm(span=26, adjust=False).mean()
|
|
181
|
+
values = ema12 - ema26
|
|
182
|
+
elif indicator == "macds":
|
|
183
|
+
ema12 = close.ewm(span=12, adjust=False).mean()
|
|
184
|
+
ema26 = close.ewm(span=26, adjust=False).mean()
|
|
185
|
+
macd_line = ema12 - ema26
|
|
186
|
+
values = macd_line.ewm(span=9, adjust=False).mean()
|
|
187
|
+
elif indicator == "macdh":
|
|
188
|
+
ema12 = close.ewm(span=12, adjust=False).mean()
|
|
189
|
+
ema26 = close.ewm(span=26, adjust=False).mean()
|
|
190
|
+
macd_line = ema12 - ema26
|
|
191
|
+
signal = macd_line.ewm(span=9, adjust=False).mean()
|
|
192
|
+
values = macd_line - signal
|
|
193
|
+
elif indicator == "rsi":
|
|
194
|
+
delta = close.diff()
|
|
195
|
+
gain = delta.where(delta > 0, 0.0)
|
|
196
|
+
loss = -delta.where(delta < 0, 0.0)
|
|
197
|
+
avg_gain = gain.ewm(alpha=1/14, adjust=False).mean()
|
|
198
|
+
avg_loss = loss.ewm(alpha=1/14, adjust=False).mean()
|
|
199
|
+
rs = avg_gain / avg_loss
|
|
200
|
+
values = 100 - (100 / (1 + rs))
|
|
201
|
+
elif indicator == "boll":
|
|
202
|
+
values = close.rolling(20).mean()
|
|
203
|
+
elif indicator == "boll_ub":
|
|
204
|
+
sma20 = close.rolling(20).mean()
|
|
205
|
+
std20 = close.rolling(20).std()
|
|
206
|
+
values = sma20 + 2 * std20
|
|
207
|
+
elif indicator == "boll_lb":
|
|
208
|
+
sma20 = close.rolling(20).mean()
|
|
209
|
+
std20 = close.rolling(20).std()
|
|
210
|
+
values = sma20 - 2 * std20
|
|
211
|
+
elif indicator == "atr":
|
|
212
|
+
prev_close = close.shift(1)
|
|
213
|
+
tr1 = high - low
|
|
214
|
+
tr2 = (high - prev_close).abs()
|
|
215
|
+
tr3 = (low - prev_close).abs()
|
|
216
|
+
tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
|
|
217
|
+
values = tr.ewm(alpha=1/14, adjust=False).mean()
|
|
218
|
+
elif indicator == "vwma":
|
|
219
|
+
pv = close * volume
|
|
220
|
+
values = pv.rolling(20).sum() / volume.rolling(20).sum()
|
|
221
|
+
else:
|
|
222
|
+
raise ValueError(f"Unsupported indicator: {indicator}")
|
|
223
|
+
|
|
224
|
+
# Filter to look-back window (trading days only, newest first)
|
|
225
|
+
df["value"] = values
|
|
226
|
+
window_start = as_of_dt - timedelta(days=look_back_days) # warm-up rows above feed the calculation only
|
|
227
|
+
df = df[df["date"] >= pd.Timestamp(window_start)]
|
|
228
|
+
df = df[df["date"] <= pd.Timestamp(as_of_dt)]
|
|
229
|
+
df = df.dropna(subset=["value"])
|
|
230
|
+
df = df.sort_values("date", ascending=False)
|
|
231
|
+
|
|
232
|
+
lines = [f"{row['date'].strftime('%Y-%m-%d')}: {row['value']:.4f}" for _, row in df.iterrows()]
|
|
233
|
+
|
|
234
|
+
header = f"## {indicator} values from {window_start} to {as_of_date} (FinzData):\n\n"
|
|
235
|
+
body = "\n".join(lines)
|
|
236
|
+
footer = f"\n\n{supported[indicator]}"
|
|
237
|
+
return header + body + footer
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def get_balance_sheet(ticker: str, freq: str = "quarterly", as_of_date: Optional[str] = None) -> str:
|
|
241
|
+
"""Get balance sheet from FinzData."""
|
|
242
|
+
from tradingagents.dataflows.errors import NoMarketDataError
|
|
243
|
+
|
|
244
|
+
client = _client()
|
|
245
|
+
df = _call(client.statements, ticker, statement="balance", freq=freq, as_of=as_of_date)
|
|
246
|
+
|
|
247
|
+
if df is None or df.empty:
|
|
248
|
+
raise NoMarketDataError(ticker, ticker, f"no balance sheet data for {ticker}")
|
|
249
|
+
|
|
250
|
+
as_of_str = as_of_date or "today"
|
|
251
|
+
header = (
|
|
252
|
+
f"# Balance sheet for {ticker.upper()} ({freq}), as filed with the SEC, "
|
|
253
|
+
f"known as of {as_of_str} (FinzData)\n\n"
|
|
254
|
+
)
|
|
255
|
+
return header + df.to_csv(index=False)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def get_cashflow(ticker: str, freq: str = "quarterly", as_of_date: Optional[str] = None) -> str:
|
|
259
|
+
"""Get cash flow statement from FinzData."""
|
|
260
|
+
from tradingagents.dataflows.errors import NoMarketDataError
|
|
261
|
+
|
|
262
|
+
client = _client()
|
|
263
|
+
df = _call(client.statements, ticker, statement="cashflow", freq=freq, as_of=as_of_date)
|
|
264
|
+
|
|
265
|
+
if df is None or df.empty:
|
|
266
|
+
raise NoMarketDataError(ticker, ticker, f"no cash flow data for {ticker}")
|
|
267
|
+
|
|
268
|
+
as_of_str = as_of_date or "today"
|
|
269
|
+
header = (
|
|
270
|
+
f"# Cash flow for {ticker.upper()} ({freq}), as filed with the SEC, "
|
|
271
|
+
f"known as of {as_of_str} (FinzData)\n\n"
|
|
272
|
+
)
|
|
273
|
+
return header + df.to_csv(index=False)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def get_income_statement(ticker: str, freq: str = "quarterly", as_of_date: Optional[str] = None) -> str:
|
|
277
|
+
"""Get income statement from FinzData."""
|
|
278
|
+
from tradingagents.dataflows.errors import NoMarketDataError
|
|
279
|
+
|
|
280
|
+
client = _client()
|
|
281
|
+
df = _call(client.statements, ticker, statement="income", freq=freq, as_of=as_of_date)
|
|
282
|
+
|
|
283
|
+
if df is None or df.empty:
|
|
284
|
+
raise NoMarketDataError(ticker, ticker, f"no income statement data for {ticker}")
|
|
285
|
+
|
|
286
|
+
as_of_str = as_of_date or "today"
|
|
287
|
+
header = (
|
|
288
|
+
f"# Income statement for {ticker.upper()} ({freq}), as filed with the SEC, "
|
|
289
|
+
f"known as of {as_of_str} (FinzData)\n\n"
|
|
290
|
+
)
|
|
291
|
+
return header + df.to_csv(index=False)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def get_fundamentals(ticker: str, as_of_date: Optional[str] = None) -> str:
|
|
295
|
+
"""Get company fundamentals from FinzData."""
|
|
296
|
+
from tradingagents.dataflows.errors import NoMarketDataError
|
|
297
|
+
|
|
298
|
+
client = _client()
|
|
299
|
+
profile_df = _call(client.profile, symbol=ticker)
|
|
300
|
+
valuation_df = _call(client.valuation, ticker, end=as_of_date)
|
|
301
|
+
|
|
302
|
+
if (profile_df is None or profile_df.empty) and (valuation_df is None or valuation_df.empty):
|
|
303
|
+
raise NoMarketDataError(ticker, ticker, f"no fundamentals data for {ticker}")
|
|
304
|
+
|
|
305
|
+
as_of_str = as_of_date or "today"
|
|
306
|
+
header = f"# Company fundamentals for {ticker.upper()} as of {as_of_str} (FinzData)\n\n"
|
|
307
|
+
|
|
308
|
+
lines = []
|
|
309
|
+
if profile_df is not None and not profile_df.empty:
|
|
310
|
+
row = profile_df.iloc[0]
|
|
311
|
+
for col in ["name", "sector", "industry"]:
|
|
312
|
+
if col in row and pd.notna(row[col]):
|
|
313
|
+
lines.append(f"{col}: {row[col]}")
|
|
314
|
+
|
|
315
|
+
if valuation_df is not None and not valuation_df.empty:
|
|
316
|
+
row = valuation_df.iloc[-1] # latest row
|
|
317
|
+
for col in valuation_df.columns:
|
|
318
|
+
if pd.notna(row[col]):
|
|
319
|
+
lines.append(f"{col}: {row[col]}")
|
|
320
|
+
|
|
321
|
+
return header + "\n".join(lines) + "\n"
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def get_insider_transactions(ticker: str, as_of_date: Optional[str] = None) -> str:
|
|
325
|
+
"""Get insider transactions from FinzData."""
|
|
326
|
+
from tradingagents.dataflows.errors import NoMarketDataError
|
|
327
|
+
|
|
328
|
+
client = _client()
|
|
329
|
+
df = _call(client.insider_transactions, ticker=ticker, end=as_of_date, limit=200)
|
|
330
|
+
|
|
331
|
+
if df is None or df.empty:
|
|
332
|
+
raise NoMarketDataError(ticker, ticker, f"no insider transactions for {ticker}")
|
|
333
|
+
|
|
334
|
+
if as_of_date and "filed" in df.columns: # point in time: only Form 4s already public on the analysis date
|
|
335
|
+
df = df[pd.to_datetime(df["filed"]) <= pd.Timestamp(as_of_date)]
|
|
336
|
+
if df.empty:
|
|
337
|
+
raise NoMarketDataError(ticker, ticker, f"no Form 4 filings for {ticker} public by {as_of_date}")
|
|
338
|
+
if "filed" in df.columns:
|
|
339
|
+
df = df.sort_values("filed", ascending=False)
|
|
340
|
+
df = df.head(50) # newest 50 rows
|
|
341
|
+
header = (f"# Insider transactions for {ticker.upper()} (FinzData, SEC Form 4)\n"
|
|
342
|
+
f"# Point in time: only filings public by {as_of_date or 'today'} (column 'filed')\n\n")
|
|
343
|
+
return header + df.to_csv(index=False)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def get_macro_indicators(
|
|
347
|
+
indicator: str,
|
|
348
|
+
as_of_date: str,
|
|
349
|
+
look_back_days: Optional[int] = None
|
|
350
|
+
) -> str:
|
|
351
|
+
"""Get macro indicators from FinzData."""
|
|
352
|
+
from tradingagents.dataflows.errors import NoMarketDataError, VendorUnavailableError
|
|
353
|
+
|
|
354
|
+
aliases = {
|
|
355
|
+
"cpi": "CPIAUCSL",
|
|
356
|
+
"core_cpi": "CPILFESL",
|
|
357
|
+
"pce": "PCEPI",
|
|
358
|
+
"unemployment": "UNRATE",
|
|
359
|
+
"payrolls": "PAYEMS",
|
|
360
|
+
"gdp": "GDP",
|
|
361
|
+
"fed_funds": "FEDFUNDS",
|
|
362
|
+
"10y_treasury": "DGS10",
|
|
363
|
+
"2y_treasury": "DGS2",
|
|
364
|
+
"yield_curve": "T10Y2Y",
|
|
365
|
+
"m2": "M2SL",
|
|
366
|
+
"initial_claims": "ICSA",
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
indicator_lower = indicator.lower()
|
|
370
|
+
series = aliases.get(indicator_lower, indicator.upper())
|
|
371
|
+
|
|
372
|
+
client = _client()
|
|
373
|
+
as_of_dt = datetime.strptime(as_of_date, "%Y-%m-%d").date()
|
|
374
|
+
lb = look_back_days if look_back_days is not None else 365
|
|
375
|
+
start_dt = as_of_dt - timedelta(days=lb)
|
|
376
|
+
start_str = start_dt.strftime("%Y-%m-%d")
|
|
377
|
+
|
|
378
|
+
df = _call(
|
|
379
|
+
client.macro,
|
|
380
|
+
series,
|
|
381
|
+
start=start_str,
|
|
382
|
+
end=as_of_date,
|
|
383
|
+
vintage="latest",
|
|
384
|
+
as_of=as_of_date,
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
if df is None or df.empty:
|
|
388
|
+
raise NoMarketDataError(series, series, f"no macro data for {series}")
|
|
389
|
+
|
|
390
|
+
df = df.copy()
|
|
391
|
+
if "date" in df.columns:
|
|
392
|
+
df["date"] = pd.to_datetime(df["date"])
|
|
393
|
+
df = df.sort_values("date", ascending=False)
|
|
394
|
+
df = df.head(24) # newest 24 rows
|
|
395
|
+
|
|
396
|
+
latest_row = df.iloc[0]
|
|
397
|
+
oldest_row = df.iloc[-1]
|
|
398
|
+
latest_val = latest_row.get("value", latest_row.iloc[-1])
|
|
399
|
+
latest_date = latest_row.get("date", latest_row.iloc[0])
|
|
400
|
+
oldest_val = oldest_row.get("value", oldest_row.iloc[-1])
|
|
401
|
+
change = latest_val - oldest_val
|
|
402
|
+
|
|
403
|
+
header = f"## {series} as known on {as_of_date} (FinzData, point in time)\n\n"
|
|
404
|
+
header += f"- Latest: {latest_val} ({latest_date.strftime('%Y-%m-%d') if hasattr(latest_date, 'strftime') else latest_date})\n"
|
|
405
|
+
header += f"- Change over window: {change}\n\n"
|
|
406
|
+
header += "| Date | Value |\n|---|---|\n"
|
|
407
|
+
|
|
408
|
+
rows = []
|
|
409
|
+
for _, row in df.iterrows():
|
|
410
|
+
d = row.get("date", row.iloc[0])
|
|
411
|
+
v = row.get("value", row.iloc[-1])
|
|
412
|
+
date_str = d.strftime("%Y-%m-%d") if hasattr(d, "strftime") else str(d)
|
|
413
|
+
rows.append(f"| {date_str} | {v} |")
|
|
414
|
+
|
|
415
|
+
return header + "\n".join(rows) + "\n"
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def register() -> List[str]:
|
|
419
|
+
"""Register FinzData vendor functions with TradingAgents router."""
|
|
420
|
+
from tradingagents.dataflows import router
|
|
421
|
+
|
|
422
|
+
methods = [
|
|
423
|
+
"get_stock_data",
|
|
424
|
+
"get_indicators",
|
|
425
|
+
"get_balance_sheet",
|
|
426
|
+
"get_cashflow",
|
|
427
|
+
"get_income_statement",
|
|
428
|
+
"get_fundamentals",
|
|
429
|
+
"get_insider_transactions",
|
|
430
|
+
"get_macro_indicators",
|
|
431
|
+
]
|
|
432
|
+
|
|
433
|
+
for method in methods:
|
|
434
|
+
fn = globals()[method]
|
|
435
|
+
router.VENDOR_METHODS.setdefault(method, {})[VENDOR] = fn
|
|
436
|
+
|
|
437
|
+
return methods
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def finzdata_config(base: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
441
|
+
"""Create a TradingAgents config with FinzData as the data vendor."""
|
|
442
|
+
if base is not None:
|
|
443
|
+
config = copy.deepcopy(base)
|
|
444
|
+
else:
|
|
445
|
+
try:
|
|
446
|
+
from tradingagents.default_config import DEFAULT_CONFIG
|
|
447
|
+
config = copy.deepcopy(DEFAULT_CONFIG)
|
|
448
|
+
except Exception:
|
|
449
|
+
config = {}
|
|
450
|
+
|
|
451
|
+
config.setdefault("data_vendors", {})
|
|
452
|
+
config["data_vendors"]["core_stock_apis"] = "finzdata"
|
|
453
|
+
config["data_vendors"]["technical_indicators"] = "finzdata"
|
|
454
|
+
config["data_vendors"]["fundamental_data"] = "finzdata,sec_edgar"
|
|
455
|
+
config["data_vendors"]["macro_data"] = "finzdata"
|
|
456
|
+
# Insider trades route through the news category; FinzData's Form 4 rows carry the filing date, so they can be
|
|
457
|
+
# served point in time (TradingAgents withholds vendors that cannot).
|
|
458
|
+
config.setdefault("tool_vendors", {})["get_insider_transactions"] = "finzdata"
|
|
459
|
+
|
|
460
|
+
return config
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tradingagents-finzdata
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: FinzData as a data vendor for TradingAgents: point-in-time, survivorship-free prices, SEC statements as filed and macro without look-ahead.
|
|
5
|
+
Author-email: FinzData <info@finzdata.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://finzdata.com/tradingagents
|
|
8
|
+
Project-URL: Documentation, https://finzdata.com/docs
|
|
9
|
+
Project-URL: Source, https://github.com/FinzData/tradingagents-finzdata
|
|
10
|
+
Keywords: tradingagents,finzdata,market-data,backtesting,llm,agents,point-in-time,survivorship-bias
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
14
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: finzdata>=0.1.14
|
|
19
|
+
Requires-Dist: pandas>=2.0
|
|
20
|
+
Provides-Extra: tradingagents
|
|
21
|
+
Requires-Dist: tradingagents; extra == "tradingagents"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# tradingagents-finzdata
|
|
25
|
+
|
|
26
|
+
FinzData as a data vendor for TradingAgents (https://github.com/TauricResearch/TradingAgents): point-in-time, survivorship-free data so your agents' backtests hold up.
|
|
27
|
+
|
|
28
|
+
## Why FinzData
|
|
29
|
+
|
|
30
|
+
TradingAgents' default price vendor only knows stocks that still trade, so backtests silently drop the failures (survivorship bias). FinzData includes delisted stocks, point in time. Macro values are served as known on the analysis date (no look-ahead from later revisions). Statements as filed with the SEC.
|
|
31
|
+
|
|
32
|
+
## Coverage
|
|
33
|
+
|
|
34
|
+
16,000+ US stocks that have traded on NYSE and Nasdaq since January 2000, delisted included, point in time; 231 ETFs; 139 futures markets with every contract since 2007; GEX for single stocks, ETFs and the major indexes; COT since 1986; 13F; SEC fundamentals as filed; 18,000+ macro series with every vintage kept; crypto since 2015.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
`pip install tradingagents-finzdata` and set `FINZDATA_API_KEY` (free key, email only, 12 months of data: https://finzdata.com/account?ref=tradingagents ; full history from $19 per ticker or $195 for 5 years of the whole US market, yours to keep: https://finzdata.com/shop?ref=tradingagents).
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
|
44
|
+
from tradingagents_finzdata import register, finzdata_config
|
|
45
|
+
register() # adds "finzdata" as a vendor
|
|
46
|
+
config = finzdata_config() # prices, indicators, fundamentals and macro from FinzData
|
|
47
|
+
ta = TradingAgentsGraph(debug=True, config=config)
|
|
48
|
+
_, decision = ta.propagate("NVDA", "2024-05-10")
|
|
49
|
+
print(decision)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Mix and match
|
|
53
|
+
|
|
54
|
+
Use FinzData as primary with fallback:
|
|
55
|
+
|
|
56
|
+
config["data_vendors"]["core_stock_apis"] = "finzdata,yfinance"
|
|
57
|
+
|
|
58
|
+
Tool-level override:
|
|
59
|
+
|
|
60
|
+
config["tool_vendors"]["get_macro_indicators"] = "finzdata"
|
|
61
|
+
|
|
62
|
+
## Tool mapping
|
|
63
|
+
|
|
64
|
+
| TradingAgents tool | FinzData source |
|
|
65
|
+
|---|---|
|
|
66
|
+
| get_stock_data | daily bars |
|
|
67
|
+
| get_indicators | computed from FinzData bars: close_50_sma, close_200_sma, close_10_ema, macd, macds, macdh, rsi, boll, boll_ub, boll_lb, atr, vwma |
|
|
68
|
+
| get_balance_sheet / get_cashflow / get_income_statement | SEC statements as filed, as of the analysis date |
|
|
69
|
+
| get_fundamentals | profile + point-in-time valuation |
|
|
70
|
+
| get_insider_transactions | SEC Form 4 |
|
|
71
|
+
| get_macro_indicators | 18,000+ series, point in time, aliases cpi, core_cpi, pce, unemployment, payrolls, gdp, fed_funds, 10y_treasury, 2y_treasury, yield_curve, m2, initial_claims |
|
|
72
|
+
|
|
73
|
+
## Errors
|
|
74
|
+
|
|
75
|
+
missing key -> vendor not configured (next vendor in your chain is used); history beyond your plan -> vendor unavailable with a link, never a fake "no data".
|
|
76
|
+
|
|
77
|
+
## Also
|
|
78
|
+
|
|
79
|
+
The FinzData MCP server https://api.finzdata.com/mcp for Claude, ChatGPT and Cursor; docs https://finzdata.com/docs.
|
|
80
|
+
|
|
81
|
+
MIT licence. "FinzData is not affiliated with TauricResearch or the TradingAgents project." Support info@finzdata.com.
|
|
82
|
+
|
|
83
|
+
FinzData: built for AI, quants, data scientists and financial analysts who backtest. Clean data. Real insights. Real alpha.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
tradingagents_finzdata/__init__.py
|
|
5
|
+
tradingagents_finzdata.egg-info/PKG-INFO
|
|
6
|
+
tradingagents_finzdata.egg-info/SOURCES.txt
|
|
7
|
+
tradingagents_finzdata.egg-info/dependency_links.txt
|
|
8
|
+
tradingagents_finzdata.egg-info/requires.txt
|
|
9
|
+
tradingagents_finzdata.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tradingagents_finzdata
|