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": "2024-11-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:
{ "ticker": "AAPL", "prediction": { "2024-11-04": "201.33,197.21,205.45", "2024-11-05": "202.77,196.92,208.61", "expectedShort": "0.22", "expectedMid": "0.58", "expectedLong": "0.25" }}This format includes:
- Point estimate (mean prediction)
- Confidence interval (lower and upper bounds)
- 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:
import requests
class PredictionClient: def __init__(self, api_key: str, base_url: str): self.api_key = api_key self.base_url = base_url
def get_prediction(self, ticker: str) -> dict: """Fetch prediction for a single ticker.""" response = requests.get( f"{self.base_url}/predictions/{ticker}", params={"token": self.api_key} ) response.raise_for_status() return response.json()
def get_bulk_predictions(self, tickers: list) -> dict: """Fetch predictions for multiple tickers.""" results = {} for ticker in tickers: try: results[ticker] = self.get_prediction(ticker) except Exception as e: results[ticker] = {"error": str(e)} return resultsError Handling
Robust integrations handle common API errors:
import timefrom requests.exceptions import RequestException
def fetch_with_retry(client, ticker, max_retries=3, backoff=1.0): """Fetch prediction with exponential backoff retry.""" for attempt in range(max_retries): try: return client.get_prediction(ticker) except RequestException 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) -> dict: """ Cache predictions by date. Cache invalidates when date changes. """ return client.get_prediction(ticker)
# 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
Install the Python SDK:
pip install finbrain-pythonBasic usage:
from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
# Get predictions as DataFrame (daily is default)df = fb.predictions.ticker("AAPL", as_dataframe=True)print(df)# main lower upper# date# 2024-11-04 201.33 197.21 205.45# 2024-11-05 202.77 196.92 208.61# ...What the API Returns
Daily predictions: 10 trading days forward, each with:
- Predicted price (
main) - Lower bound (
lower) - Upper bound (
upper)
Monthly predictions: 12 months forward, same structure.
Movement probabilities:
expectedShort— probability of short-term moveexpectedMid— probability of medium-term moveexpectedLong— 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:
# Get raw JSON responsedata = fb.predictions.ticker("AAPL")
# Access prediction objectpred = data["prediction"]print(f"Last updated: {pred['lastUpdate']}")print(f"Expected short-term move: {pred['expectedShort']}%")
# Parse individual date forecastsfor date_key, value in pred.items(): if ',' in str(value): # Date entries contain comma-separated values main, lower, upper = value.split(',') print(f"{date_key}: ${main} (range: ${lower} - ${upper})")Monthly Predictions
For longer-term forecasting:
# Get 12-month predictionsmonthly = fb.predictions.ticker("AAPL", prediction_type="monthly", as_dataframe=True)print(monthly)Market-Wide Predictions
Get predictions for all tickers in a market:
# All S&P 500 predictionssp500 = fb.predictions.market("S&P 500", as_dataframe=True)print(f"Predictions for {len(sp500)} tickers")Built-in Visualization
The SDK includes plotting functionality:
# Plot prediction conefb.plot.predictions("AAPL")
# Monthly viewfb.plot.predictions("AAPL", prediction_type="monthly")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(market: str, min_upside: float = 0.05): """ Find tickers where the lower bound is above current price. This indicates high conviction in upward movement. """ df = fb.predictions.market(market, as_dataframe=True)
bullish = [] for ticker in df.index.get_level_values('ticker').unique(): ticker_data = df.loc[ticker] first_day = ticker_data.iloc[0]
# If lower bound > current implies strong conviction # (We'd need current price from another source) # For now, check if predicted move is positive if first_day['main'] > first_day['lower'] * 1.02: upside = (first_day['upper'] - first_day['main']) / first_day['main'] if upside >= min_upside: bullish.append({ 'ticker': ticker, 'predicted': first_day['main'], 'lower': first_day['lower'], 'upper': first_day['upper'], 'upside_potential': upside })
return sorted(bullish, key=lambda x: x['upside_potential'], reverse=True)
# Find bullish opportunities in S&P 500opportunities = screen_bullish_predictions("S&P 500", 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: data = fb.predictions.ticker(ticker) pred = data["prediction"]
# Get expected moves expected_short = float(pred.get("expectedShort", 0)) expected_mid = float(pred.get("expectedMid", 0)) expected_long = float(pred.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:
from finbrain import FinBrainClientimport pandas as pd
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: data = fb.predictions.ticker(ticker) pred = data["prediction"]
# Get first day's prediction for key, value in pred.items(): if ',' in str(value): main, lower, upper = map(float, value.split(',')) predictions.append({ 'ticker': ticker, 'predicted': main, 'lower': lower, 'upper': upper, 'expected_return': (main - current_price) / current_price, 'downside_risk': (current_price - lower) / current_price, 'upside_potential': (upper - current_price) / current_price }) break 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 pred_data = fb.predictions.ticker(ticker) pred = pred_data["prediction"]
# Get sentiment sent_data = fb.sentiments.ticker("S&P 500", ticker, as_dataframe=True) latest_sentiment = float(sent_data.iloc[0]['score']) if len(sent_data) > 0 else 0
# Parse first prediction for key, value in pred.items(): if ',' in str(value): main, lower, upper = map(float, value.split(',')) break
# Expected move from prediction expected_short = float(pred.get("expectedShort", 0))
# 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': main, '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)Error Handling
Handle API errors gracefully:
from requests.exceptions import HTTPError
def safe_get_prediction(fb, ticker: str) -> dict | None: """Safely fetch prediction with error handling.""" try: return fb.predictions.ticker(ticker) except HTTPError as e: if e.response.status_code == 404: print(f"{ticker}: Not found") elif e.response.status_code == 401: print("Authentication failed - check API key") elif e.response.status_code == 429: print("Rate limited - slow down requests") else: print(f"{ticker}: HTTP {e.response.status_code}") return None except Exception as e: print(f"{ticker}: Unexpected error - {e}") return NoneData Validation
Validate API responses before using:
def validate_prediction(data: dict) -> bool: """Validate prediction response structure.""" required_fields = ["ticker", "prediction"] if not all(field in data for field in required_fields): return False
pred = data["prediction"] if "lastUpdate" not in pred: return False
# Check for at least one date-keyed prediction has_prediction = any(',' in str(v) for v in pred.values()) return has_predictionCoverage 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:
# Get all available tickers for a markettickers = fb.available.tickers("daily")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.