Building trading systems or research tools that incorporate price predictions requires reliable API access to forecast data. This guide covers what to look for in a stock prediction API, how to evaluate providers, and practical integration patterns.
What to Look for in a Prediction API
Not all prediction APIs are equal. Before integrating, evaluate these criteria:
Data Quality
| Criterion | Questions to Ask |
|---|---|
| Coverage | How many assets? Which markets? |
| Forecast horizon | Days ahead? Months ahead? |
| Update frequency | Real-time? Daily? Weekly? |
| Uncertainty quantification | Point estimate only or confidence intervals? |
| Track record | How long has the model been running? |
A prediction without uncertainty is incomplete. APIs that only provide single-point estimates hide crucial information about model confidence.
Technical Requirements
| Criterion | What to Check |
|---|---|
| Authentication | API key? OAuth? Rate limits? |
| Response format | JSON? CSV? Consistent schemas? |
| Latency | Response time for single/bulk requests |
| Reliability | Uptime SLA? Error handling? |
| Documentation | Complete? Accurate? Code examples? |
Integration Options
| Option | Best For |
|---|---|
| REST API | Most applications, flexibility |
| Python SDK | Data science workflows, rapid prototyping |
| Webhooks | Event-driven systems, alerts |
| Bulk exports | Batch processing, data warehouses |
Common Prediction API Architectures
Point Estimate APIs
The simplest APIs return a single predicted price:
{ "ticker": "AAPL", "predicted_price": 200.50, "date": "2025-03-15"}Limitation: No uncertainty information. You don’t know if this is a high-confidence or low-confidence prediction.
Directional Signal APIs
Some APIs return buy/sell/hold signals:
{ "ticker": "AAPL", "signal": "BUY", "confidence": 0.75}Limitation: Loses price target information. A “buy” at $100 means something different than a “buy” at $200.
Full Distribution APIs
The most complete APIs provide the full prediction distribution:
{ "success": true, "data": { "symbol": "AAPL", "predictions": [ { "date": "2025-03-10", "mid": 201.33, "lower": 197.21, "upper": 205.45 }, { "date": "2025-03-11", "mid": 202.77, "lower": 196.92, "upper": 208.61 } ], "metadata": { "expectedShortTerm": "0.22", "expectedMidTerm": "0.58", "expectedLongTerm": "0.25" } }, "meta": {}}This format includes:
- Point estimate (
mid— mean prediction) - Confidence interval (
lowerandupperbounds) - Movement probabilities (expected magnitude)
This is what you should look for—prediction APIs that quantify uncertainty.
Integrating a Prediction API
Basic Integration Pattern
The standard pattern for prediction API integration:
from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
# Fetch prediction for a single tickerdf = fb.predictions.ticker("AAPL", prediction_type="daily", as_dataframe=True)
# Fetch predictions for multiple tickersresults = {}for ticker in ["AAPL", "MSFT", "GOOGL"]: try: results[ticker] = fb.predictions.ticker(ticker, prediction_type="daily", as_dataframe=True) except Exception as e: results[ticker] = {"error": str(e)}Error Handling
Robust integrations handle common API errors:
import timefrom finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
def fetch_with_retry(ticker, max_retries=3, backoff=1.0): """Fetch prediction with exponential backoff retry.""" for attempt in range(max_retries): try: return fb.predictions.ticker(ticker, prediction_type="daily", as_dataframe=True) except Exception as e: if attempt == max_retries - 1: raise wait_time = backoff * (2 ** attempt) print(f"Retry {attempt + 1}/{max_retries} after {wait_time}s: {e}") time.sleep(wait_time)Caching Strategy
Predictions don’t change intraday—cache appropriately:
from functools import lru_cachefrom datetime import date
@lru_cache(maxsize=1000)def get_cached_prediction(ticker: str, cache_date: str): """ Cache predictions by date. Cache invalidates when date changes. """ return fb.predictions.ticker(ticker, prediction_type="daily", as_dataframe=True)
# Usage - cache_date ensures daily refreshprediction = get_cached_prediction("AAPL", str(date.today()))Using the FinBrain Prediction API
FinBrain provides AI-powered price predictions with confidence intervals for 25,000+ assets across 20+ global markets.
Quick Start
Basic usage with the v2 API:
from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
# Get daily predictions as a DataFramedf = fb.predictions.ticker("AAPL", prediction_type="daily", as_dataframe=True)print(df)# date mid lower upper# 0 2025-03-10 201.33 197.21 205.45# 1 2025-03-11 202.77 196.92 208.61# ...What the API Returns
Daily predictions: 10 trading days forward, each with:
- Predicted price (
mid) - Lower bound (
lower) - Upper bound (
upper)
Monthly predictions: 12 months forward, same structure.
Movement probabilities (in metadata):
expectedShortTerm— probability of short-term moveexpectedMidTerm— probability of medium-term moveexpectedLongTerm— probability of longer-term move
Important: Predictions are forward-looking only. You cannot retrieve historical predictions—what the model predicted last week for today. Forecasts are generated fresh each day.
Getting Raw JSON
For custom processing:
from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
# Get raw JSON response (without as_dataframe)result = fb.predictions.ticker("AAPL", prediction_type="daily")
# Access prediction dataprediction = result["prediction"]print(f"Last updated: {prediction['lastUpdate']}")print(f"Expected short-term move: {prediction['expectedShort']}%")
# Access individual date forecastsfor date_key, values in prediction.items(): if date_key.startswith("2025"): mid, lower, upper = values.split(",") print(f"{date_key}: ${mid} (range: ${lower} - ${upper})")Monthly Predictions
For longer-term forecasting:
from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
# Get 12-month predictionsdf = fb.predictions.ticker("AAPL", prediction_type="monthly", as_dataframe=True)print(df)Practical Integration Examples
Building a Screener
Screen for high-conviction bullish predictions:
from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
def screen_bullish_predictions(tickers: list, min_upside: float = 0.05): """ Find tickers where predictions show strong upside potential. """ bullish = []
for ticker in tickers: try: df = fb.predictions.ticker(ticker, prediction_type="daily", as_dataframe=True) first_day = df.iloc[0]
# Check if predicted move is positive if first_day['mid'] > first_day['lower'] * 1.02: upside = (first_day['upper'] - first_day['mid']) / first_day['mid'] if upside >= min_upside: bullish.append({ 'ticker': ticker, 'predicted': first_day['mid'], 'lower': first_day['lower'], 'upper': first_day['upper'], 'upside_potential': upside }) except Exception as e: print(f"Error fetching {ticker}: {e}")
return sorted(bullish, key=lambda x: x['upside_potential'], reverse=True)
# Find bullish opportunitieswatchlist = ["AAPL", "NVDA", "TSLA", "META", "AMZN", "GOOGL", "MSFT"]opportunities = screen_bullish_predictions(watchlist, min_upside=0.10)for opp in opportunities[:10]: print(f"{opp['ticker']}: {opp['upside_potential']:.1%} upside potential")Alert System
Send alerts when predictions show significant moves:
from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
def check_prediction_alerts(watchlist: list, threshold: float = 0.05): """ Check predictions and generate alerts for significant moves. """ alerts = []
for ticker in watchlist: result = fb.predictions.ticker(ticker, prediction_type="daily") prediction = result["prediction"]
# Get expected moves expected_short = float(prediction.get("expectedShort", 0)) expected_mid = float(prediction.get("expectedMid", 0)) expected_long = float(prediction.get("expectedLong", 0))
# Alert if any expected move exceeds threshold max_expected = max(expected_short, expected_mid, expected_long) if max_expected > threshold: alerts.append({ 'ticker': ticker, 'expected_short': expected_short, 'expected_mid': expected_mid, 'expected_long': expected_long, 'max_move': max_expected })
return alerts
# Check watchlistwatchlist = ["AAPL", "NVDA", "TSLA", "META", "AMZN"]alerts = check_prediction_alerts(watchlist, threshold=0.10)
for alert in alerts: print(f"ALERT: {alert['ticker']} - Expected move: {alert['max_move']:.1%}")Portfolio Overlay
Add prediction data to existing portfolio positions:
import pandas as pdfrom finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
def overlay_predictions(portfolio: pd.DataFrame) -> pd.DataFrame: """ Add prediction data to portfolio DataFrame. Expects portfolio to have 'ticker' and 'current_price' columns. """ predictions = []
for _, row in portfolio.iterrows(): ticker = row['ticker'] current_price = row['current_price']
try: df = fb.predictions.ticker(ticker, prediction_type="daily", as_dataframe=True)
# Get first day's prediction first_pred = df.iloc[0] mid = first_pred["mid"] lower = first_pred["lower"] upper = first_pred["upper"]
predictions.append({ 'ticker': ticker, 'predicted': mid, 'lower': lower, 'upper': upper, 'expected_return': (mid - current_price) / current_price, 'downside_risk': (current_price - lower) / current_price, 'upside_potential': (upper - current_price) / current_price }) except Exception as e: predictions.append({ 'ticker': ticker, 'error': str(e) })
pred_df = pd.DataFrame(predictions) return portfolio.merge(pred_df, on='ticker', how='left')
# Example usageportfolio = pd.DataFrame({ 'ticker': ['AAPL', 'MSFT', 'GOOGL'], 'current_price': [198.50, 420.00, 175.25], 'shares': [100, 50, 75]})
enriched = overlay_predictions(portfolio)print(enriched[['ticker', 'expected_return', 'downside_risk', 'upside_potential']])Combining with Sentiment
Merge predictions with sentiment data for richer signals:
from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
def get_combined_signal(ticker: str) -> dict: """ Combine price prediction with sentiment for a composite signal. """ # Get prediction as DataFrame pred_df = fb.predictions.ticker(ticker, prediction_type="daily", as_dataframe=True)
# Get raw prediction data for expected moves pred_result = fb.predictions.ticker(ticker, prediction_type="daily") prediction = pred_result["prediction"] expected_short = float(prediction.get("expectedShort", 0))
# Get sentiment sent_df = fb.sentiments.ticker(ticker, as_dataframe=True) latest_sentiment = sent_df.iloc[0]['score'] if len(sent_df) > 0 else 0
# Get first prediction first_pred = pred_df.iloc[0] mid = first_pred["mid"] lower = first_pred["lower"] upper = first_pred["upper"]
# Composite signal # Positive sentiment + positive expected move = strong bullish # Negative sentiment + negative expected move = strong bearish # Divergence = uncertain
sentiment_signal = 1 if latest_sentiment > 0.3 else (-1 if latest_sentiment < -0.3 else 0) prediction_signal = 1 if expected_short > 0.02 else (-1 if expected_short < -0.02 else 0)
if sentiment_signal == prediction_signal == 1: composite = "STRONG_BULLISH" elif sentiment_signal == prediction_signal == -1: composite = "STRONG_BEARISH" elif sentiment_signal != prediction_signal and sentiment_signal != 0 and prediction_signal != 0: composite = "DIVERGENCE" else: composite = "NEUTRAL"
return { 'ticker': ticker, 'predicted_price': mid, 'prediction_range': f"${lower:.2f} - ${upper:.2f}", 'expected_move': f"{expected_short:.1%}", 'sentiment': latest_sentiment, 'composite_signal': composite }
# Check a tickersignal = get_combined_signal("NVDA")print(f"{signal['ticker']}: {signal['composite_signal']}")print(f" Predicted: ${signal['predicted_price']:.2f} ({signal['prediction_range']})")print(f" Expected move: {signal['expected_move']}")print(f" Sentiment: {signal['sentiment']:.3f}")API Best Practices
Rate Limiting
Respect API limits to avoid throttling:
import timefrom collections import deque
class RateLimiter: def __init__(self, max_calls: int, period: float): self.max_calls = max_calls self.period = period self.calls = deque()
def wait_if_needed(self): now = time.time() # Remove calls outside the window while self.calls and self.calls[0] < now - self.period: self.calls.popleft() # Wait if at limit if len(self.calls) >= self.max_calls: sleep_time = self.calls[0] - (now - self.period) if sleep_time > 0: time.sleep(sleep_time) self.calls.append(time.time())
# Usagelimiter = RateLimiter(max_calls=100, period=60) # 100 calls per minute
for ticker in large_ticker_list: limiter.wait_if_needed() prediction = fb.predictions.ticker(ticker, prediction_type="daily", as_dataframe=True)Error Handling
Handle API errors gracefully:
from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
def safe_get_prediction(ticker: str): """Safely fetch prediction with error handling.""" try: return fb.predictions.ticker(ticker, prediction_type="daily", as_dataframe=True) except Exception as e: error_msg = str(e) if "404" in error_msg: print(f"{ticker}: Not found") elif "401" in error_msg: print("Authentication failed - check API key") elif "429" in error_msg: print("Rate limited - slow down requests") else: print(f"{ticker}: Unexpected error - {error_msg}") return NoneData Validation
Validate API responses before using:
def validate_prediction(data: dict) -> bool: """Validate prediction response structure.""" if "ticker" not in data or "prediction" not in data: return False
prediction = data["prediction"] if "lastUpdate" not in prediction or "type" not in prediction: return False
# Check for at least one date-keyed forecast entry date_entries = [k for k in prediction if k.startswith("2025")] return len(date_entries) > 0Coverage and Availability
FinBrain predictions cover:
| Market | Examples |
|---|---|
| US Equities | S&P 500, NASDAQ, NYSE, DOW 30 |
| International | FTSE 100, DAX, TSX, ASX, Hang Seng |
| ETFs | Major US ETFs |
| Commodities | Gold, Oil, Natural Gas |
| Currencies | Major forex pairs |
| Crypto | Bitcoin, Ethereum, major altcoins |
| Futures | Index futures |
Total coverage: 25,000+ assets across 20+ markets.
Check available tickers:
from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")tickers = fb.available.tickers("daily", as_dataframe=True)print(f"Available for daily predictions: {len(tickers)} tickers")Key Takeaways
- Look for prediction APIs that provide uncertainty quantification, not just point estimates
- Use SDKs when available—they handle authentication, parsing, and common patterns
- Cache predictions appropriately since they typically update daily, not intraday
- Combine predictions with other signals (sentiment, fundamentals) for robust strategies
- Implement proper error handling and rate limiting for production systems
- Validate API responses before using in trading logic
Related Resources
- Ticker Predictions API Reference — Complete endpoint documentation
- AI Price Forecasts Dataset — Dataset overview and use cases
- Understanding Prediction Confidence Intervals — How to interpret prediction ranges
- Python SDK Documentation — Full SDK reference
A prediction API is only as useful as your ability to integrate it reliably. Choose providers with clear documentation, consistent schemas, and proper uncertainty quantification—then build robust error handling around them.