fix(dataflows): let the next vendor serve what Alpha Vantage cannot

- an indicator it does not carry raises instead of returning prose the router counts as an answer
- ticker news asks for the configured article limit
This commit is contained in:
Yijia-Xiao
2026-09-18 00:04:53 +00:00
parent bbcd6661af
commit aef4af90e3
3 changed files with 49 additions and 13 deletions
@@ -1,6 +1,7 @@
import logging
from .alpha_vantage_common import AlphaVantageNotConfiguredError, _make_api_request
from .alpha_vantage_common import _make_api_request
from .errors import NoMarketDataError, VendorError
logger = logging.getLogger(__name__)
@@ -64,8 +65,11 @@ def get_indicator(
}
if indicator not in supported_indicators:
raise ValueError(
f"Indicator {indicator} is not supported. Please choose from: {list(supported_indicators.keys())}"
# A vendor error, not a caller error: another vendor may compute it, and
# the router decides. yfinance rejects a name nobody serves.
raise NoMarketDataError(
symbol, symbol,
f"Alpha Vantage does not serve {indicator}; it serves {list(supported_indicators)}"
)
curr_date_dt = datetime.strptime(curr_date, "%Y-%m-%d")
@@ -134,12 +138,13 @@ def get_indicator(
"time_period": str(time_period),
"datatype": "csv"
})
elif indicator == "vwma":
# Alpha Vantage doesn't have direct VWMA, so we'll return an informative message
# In a real implementation, this would need to be calculated from OHLCV data
return f"## VWMA (Volume Weighted Moving Average) for {symbol}:\n\nVWMA calculation requires OHLCV data and is not directly available from Alpha Vantage API.\nThis indicator would need to be calculated from the raw stock data using volume-weighted price averaging.\n\n{indicator_descriptions.get('vwma', 'No description available.')}"
else:
return f"Error: Indicator {indicator} not implemented yet."
# This vendor has no endpoint for the indicator. Raising lets the
# router try the next vendor, which computes it; returning prose
# counted as a successful answer and ended the chain here.
raise NoMarketDataError(
symbol, symbol, f"Alpha Vantage does not serve the {indicator} indicator"
)
# Parse CSV data and extract values for the date range
lines = data.strip().split('\n')
@@ -209,11 +214,11 @@ def get_indicator(
return result_str
except AlphaVantageNotConfiguredError:
# Vendor unavailable (no API key). Let it propagate so the router can
# fall back / emit the no-data sentinel instead of returning this as a
# successful-looking error string.
except VendorError:
# Unavailable vendor, throttle, or an indicator this vendor does not
# serve. Let it propagate so the router falls back to a vendor that can,
# instead of returning the failure as a successful-looking string.
raise
except Exception as e:
logger.warning("Alpha Vantage indicator %s failed: %s", indicator, e)
return f"Error retrieving {indicator} data: {str(e)}"
raise NoMarketDataError(symbol, symbol, f"{indicator} unavailable: {e}") from e
@@ -18,10 +18,13 @@ def get_news(ticker, start_date, end_date) -> dict[str, str] | str:
Dictionary containing news sentiment data or JSON string.
"""
# Without a limit the endpoint returns 50 articles, each with per-ticker
# sentiment arrays, and all of it reaches the prompt.
params = {
"tickers": ticker,
"time_from": format_datetime_for_api(start_date),
"time_to": format_datetime_for_api(end_date, end_of_day=True),
"limit": str(get_config()["news_article_limit"]),
}
return _make_api_request("NEWS_SENTIMENT", params)