Skip to content
Hero Background Light

Stock Prediction APIs: A Developer's Guide

Stock Prediction APIs: A Developer's Guide

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

CriterionQuestions to Ask
CoverageHow many assets? Which markets?
Forecast horizonDays ahead? Months ahead?
Update frequencyReal-time? Daily? Weekly?
Uncertainty quantificationPoint estimate only or confidence intervals?
Track recordHow 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

CriterionWhat to Check
AuthenticationAPI key? OAuth? Rate limits?
Response formatJSON? CSV? Consistent schemas?
LatencyResponse time for single/bulk requests
ReliabilityUptime SLA? Error handling?
DocumentationComplete? Accurate? Code examples?

Integration Options

OptionBest For
REST APIMost applications, flexibility
Python SDKData science workflows, rapid prototyping
WebhooksEvent-driven systems, alerts
Bulk exportsBatch 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 (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:

from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
# Fetch prediction for a single ticker
df = fb.predictions.ticker("AAPL", prediction_type="daily", as_dataframe=True)
# Fetch predictions for multiple tickers
results = {}
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 time
from 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_cache
from 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 refresh
prediction = 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 DataFrame
df = 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 move
  • expectedMidTerm — probability of medium-term move
  • expectedLongTerm — 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 data
prediction = result["prediction"]
print(f"Last updated: {prediction['lastUpdate']}")
print(f"Expected short-term move: {prediction['expectedShort']}%")
# Access individual date forecasts
for 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 predictions
df = 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 opportunities
watchlist = ["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 watchlist
watchlist = ["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 pd
from 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 usage
portfolio = 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 ticker
signal = 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 time
from 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())
# Usage
limiter = 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 None

Data 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) > 0

Coverage and Availability

FinBrain predictions cover:

MarketExamples
US EquitiesS&P 500, NASDAQ, NYSE, DOW 30
InternationalFTSE 100, DAX, TSX, ASX, Hang Seng
ETFsMajor US ETFs
CommoditiesGold, Oil, Natural Gas
CurrenciesMajor forex pairs
CryptoBitcoin, Ethereum, major altcoins
FuturesIndex 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

  1. Look for prediction APIs that provide uncertainty quantification, not just point estimates
  2. Use SDKs when available—they handle authentication, parsing, and common patterns
  3. Cache predictions appropriately since they typically update daily, not intraday
  4. Combine predictions with other signals (sentiment, fundamentals) for robust strategies
  5. Implement proper error handling and rate limiting for production systems
  6. Validate API responses before using in trading logic

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.