Alpaca Integration**: Added `tradingagents/dataflows/alpaca.py` to support `get_stock_data` via Alpaca Data API v2.
This commit is contained in:
parent
3644e82f4e
commit
66c9807ed8
|
|
@ -21,6 +21,9 @@ All notable changes to the **TradingAgents** project will be documented in this
|
|||
- **Import Errors**: Fixed `NameError: name 'tool' is not defined` by restoring `langchain_core` imports in data tools that were accidentally removed during Blindfire integration.
|
||||
- **Payload Size Error**: Implemented input truncation (max 9000 chars) in `memory.py`.
|
||||
- **Display Layer De-Anonymization**: Added `deanonymize_text` to `TickerAnonymizer` and patched `cli/main.py` to reverse-map "ASSET_XXX" to real company names in the final report, effectively resolving "[Company Name]" placeholders for the user while keeping the internal system blind.
|
||||
- **Alpaca Integration**: Added `tradingagents/dataflows/alpaca.py` to support `get_stock_data` via Alpaca Data API v2. Registered as a vendor option in `interface.py` and `default_config.py`. Requires `ALPACA_API_KEY` and `ALPACA_API_SECRET` in `.env`.
|
||||
|
||||
|
||||
|
||||
### Changed
|
||||
- **LLM Configuration**: Updated `tradingagents/default_config.py` and `cli/utils.py` to use valid Gemini model names (e.g., `gemini-1.5-flash`, `gemini-1.5-pro`) and `gemini-pro`.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
import os
|
||||
import requests
|
||||
import pandas as pd
|
||||
from typing import Optional
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
def get_stock_data(symbol: str, start_date: str = None, end_date: str = None) -> str:
|
||||
"""
|
||||
Fetch historical stock data (OHLCV) from Alpaca Data API v2.
|
||||
|
||||
Args:
|
||||
symbol: Ticker symbol (e.g., "AAPL")
|
||||
start_date: Start date (YYYY-MM-DD), defaults to 1 year ago
|
||||
end_date: End date (YYYY-MM-DD), defaults to today
|
||||
|
||||
Returns:
|
||||
String representation of the dataframe
|
||||
"""
|
||||
api_key = os.getenv("ALPACA_API_KEY")
|
||||
secret_key = os.getenv("ALPACA_API_SECRET")
|
||||
|
||||
if not api_key or not secret_key:
|
||||
raise ValueError("Error: ALPACA_API_KEY and ALPACA_API_SECRET environment variables must be set.")
|
||||
|
||||
# Default dates
|
||||
if not end_date:
|
||||
end_date = datetime.now().strftime("%Y-%m-%d")
|
||||
if not start_date:
|
||||
start_date = (datetime.now() - timedelta(days=365)).strftime("%Y-%m-%d")
|
||||
|
||||
# Alpaca API URL (Data API v2)
|
||||
url = f"https://data.alpaca.markets/v2/stocks/{symbol}/bars"
|
||||
|
||||
headers = {
|
||||
"APCA-API-KEY-ID": api_key,
|
||||
"APCA-API-SECRET-KEY": secret_key
|
||||
}
|
||||
|
||||
params = {
|
||||
"start": start_date,
|
||||
"end": end_date,
|
||||
"timeframe": "1Day",
|
||||
"limit": 10000,
|
||||
"adjustment": "all", # Split and dividend adjusted
|
||||
"feed": "sip" # Use SIP feed if available, or 'iex' for free tier
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.get(url, headers=headers, params=params)
|
||||
|
||||
if response.status_code != 200:
|
||||
# Check for free tier specific error regarding feed (422 or 403)
|
||||
# 422: Invalid value (explicit feed req)
|
||||
# 403: Forbidden (subscription level)
|
||||
if (response.status_code in [403, 422]) and ("feed" in response.text or "subscription" in response.text):
|
||||
# Retry with IEX feed (Free tier)
|
||||
print(f"INFO: Retrying {symbol} with IEX feed (Free Tier)...")
|
||||
params["feed"] = "iex"
|
||||
response = requests.get(url, headers=headers, params=params)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise ValueError(f"Alpaca API Error: {response.status_code} - {response.text}")
|
||||
|
||||
data = response.json()
|
||||
|
||||
if "bars" not in data or not data["bars"]:
|
||||
return f"No data found for {symbol} on Alpaca between {start_date} and {end_date}."
|
||||
|
||||
# Parse data
|
||||
# Alpaca returns: t (time), o, h, l, c, v, nw, n
|
||||
bars = data["bars"]
|
||||
|
||||
df_data = []
|
||||
for bar in bars:
|
||||
df_data.append({
|
||||
"Date": bar["t"].split("T")[0],
|
||||
"Open": bar["o"],
|
||||
"High": bar["h"],
|
||||
"Low": bar["l"],
|
||||
"Close": bar["c"],
|
||||
"Volume": bar["v"]
|
||||
})
|
||||
|
||||
df = pd.DataFrame(df_data)
|
||||
|
||||
# Format output string similar to yfinance output for consistency
|
||||
result_str = f"Stock Data for {symbol} from {start_date} to {end_date}\n"
|
||||
result_str += df.to_string(index=False)
|
||||
|
||||
return result_str
|
||||
|
||||
except Exception as e:
|
||||
return f"Error fetching data from Alpaca for {symbol}: {str(e)}"
|
||||
|
|
@ -16,6 +16,7 @@ from .alpha_vantage import (
|
|||
get_news as get_alpha_vantage_news
|
||||
)
|
||||
from .alpha_vantage_common import AlphaVantageRateLimitError
|
||||
from .alpaca import get_stock_data as get_stock_alpaca
|
||||
|
||||
# Configuration and routing logic
|
||||
from .config import get_config
|
||||
|
|
@ -58,7 +59,8 @@ VENDOR_LIST = [
|
|||
"local",
|
||||
"yfinance",
|
||||
"openai",
|
||||
"google"
|
||||
"google",
|
||||
"alpaca"
|
||||
]
|
||||
|
||||
# Mapping of methods to their vendor-specific implementations
|
||||
|
|
@ -68,6 +70,7 @@ VENDOR_METHODS = {
|
|||
"alpha_vantage": get_alpha_vantage_stock,
|
||||
"yfinance": get_YFin_data_online,
|
||||
"local": get_YFin_data,
|
||||
"alpaca": get_stock_alpaca,
|
||||
},
|
||||
# technical_indicators
|
||||
"get_indicators": {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ DEFAULT_CONFIG = {
|
|||
# Data vendor configuration
|
||||
# Category-level configuration (default for all tools in category)
|
||||
"data_vendors": {
|
||||
"core_stock_apis": "yfinance", # Options: yfinance, alpha_vantage, local
|
||||
"core_stock_apis": "yfinance", # Options: yfinance, alpha_vantage, local, alpaca
|
||||
"technical_indicators": "yfinance", # Options: yfinance, alpha_vantage, local
|
||||
"fundamental_data": "alpha_vantage", # Options: openai, alpha_vantage, local
|
||||
"news_data": "alpha_vantage", # Options: openai, alpha_vantage, google, local
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
import os
|
||||
from dotenv import load_dotenv
|
||||
from tradingagents.dataflows.alpaca import get_stock_data
|
||||
|
||||
# Load environment variables
|
||||
load_dotenv()
|
||||
|
||||
def verify_alpaca():
|
||||
print("Locked & Loaded: Verifying Alpaca Data Connection...")
|
||||
|
||||
api_key = os.getenv("ALPACA_API_KEY")
|
||||
secret_key = os.getenv("ALPACA_API_SECRET")
|
||||
|
||||
if not api_key or not secret_key:
|
||||
print("❌ SKIPPING: ALPACA_API_KEY or ALPACA_API_SECRET not found in environment.")
|
||||
print("Please add them to your .env file to enable Alpaca.")
|
||||
return
|
||||
|
||||
try:
|
||||
# Test with a known ticker
|
||||
symbol = "AAPL"
|
||||
print(f"Fetching data for {symbol}...")
|
||||
data = get_stock_data(symbol)
|
||||
|
||||
if "Error" in data and not "No data found" in data:
|
||||
print(f"❌ FAIL: {data}")
|
||||
else:
|
||||
print("✅ SUCCESS: Data retrieved successfully!")
|
||||
rows = data.splitlines()[:5]
|
||||
print(f"Preview:\n" + "\n".join(rows) + "...")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ FAIL: Exception occurred: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
verify_alpaca()
|
||||
Loading…
Reference in New Issue