Skip to content

Backtesting with AI Predictions

This guide shows you how to evaluate FinBrain AI predictions through backtesting. You’ll learn how to measure prediction accuracy, build signal-based strategies, and analyze historical performance.

  • How to fetch historical prediction data
  • Measuring prediction accuracy
  • Building a simple backtesting framework
  • Combining predictions with other signals
  • Analyzing results and optimizing parameters
  • Python 3.7+
  • FinBrain API key
  • Basic understanding of pandas
Terminal window
pip install finbrain-python pandas numpy

First, let’s retrieve historical predictions for analysis:

from finbrain import FinBrainClient
import pandas as pd
from datetime import datetime, timedelta
fb = FinBrainClient(api_key="YOUR_API_KEY")
def get_historical_predictions(ticker, days=365):
"""Fetch historical predictions for backtesting"""
date_to = datetime.now().strftime("%Y-%m-%d")
date_from = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
predictions = fb.predictions.ticker(
ticker,
prediction_type="daily",
date_from=date_from,
date_to=date_to
)
# Extract prediction data
pred = predictions.get("prediction", {})
df = pd.DataFrame([{
"ticker": predictions.get("ticker"),
"expectedShort": float(pred.get("expectedShort", 0)),
"expectedMid": float(pred.get("expectedMid", 0)),
"expectedLong": float(pred.get("expectedLong", 0)),
"lastUpdate": pred.get("lastUpdate")
}])
return df
# Get predictions for Apple
predictions = get_historical_predictions("AAPL")
print(predictions)
print(f"\nPrediction data retrieved")

To evaluate predictions, we need actual price data. You can use any price data source:

import yfinance as yf
def get_price_data(ticker, start_date, end_date):
"""Fetch actual price data for comparison"""
stock = yf.Ticker(ticker)
df = stock.history(start=start_date, end=end_date)
df.index = df.index.tz_localize(None) # Remove timezone
return df[["Close"]].rename(columns={"Close": "actual_price"})
# Get actual prices
prices = get_price_data("AAPL", "2023-01-01", "2024-01-31")
print(prices.head())

Let’s evaluate how accurate the predictions are:

def analyze_prediction_signal(prediction_data, actual_return):
"""Analyze if prediction signal was correct"""
expected_short = float(prediction_data.get("expectedShort", 0))
# Check if expected short-term move aligned with direction
direction_correct = (
(expected_short > 0 and actual_return > 0) or
(expected_short < 0 and actual_return < 0) or
(expected_short == 0)
)
# Strong signal check (threshold of 1%)
strong_signal_correct = (
(expected_short > 1 and actual_return > 0) or
(expected_short < -1 and actual_return < 0)
)
return {
"direction_correct": direction_correct,
"strong_signal_correct": strong_signal_correct,
"expected_short": expected_short,
"actual_return": actual_return
}
# Example usage with actual price data
fb = FinBrainClient(api_key="YOUR_API_KEY")
prediction = fb.predictions.ticker("AAPL", prediction_type="daily")
pred = prediction.get("prediction", {})
print("\n=== Prediction Analysis ===")
print(f"Expected Short: {pred.get('expectedShort')}%")
print(f"Expected Mid: {pred.get('expectedMid')}%")
print(f"Expected Long: {pred.get('expectedLong')}%")

Now let’s build a simple backtesting framework:

class SimpleBacktest:
def __init__(self, api_key, initial_capital=100000):
self.fb = FinBrainClient(api_key=api_key)
self.initial_capital = initial_capital
def get_signal(self, ticker):
"""Get current trading signal from prediction"""
prediction = self.fb.predictions.ticker(ticker, prediction_type="daily")
pred = prediction.get("prediction", {})
expected_short = float(pred.get("expectedShort", 0))
# Generate signal based on expected move thresholds
if expected_short > 1:
return "buy", expected_short
elif expected_short < -1:
return "sell", expected_short
else:
return "hold", expected_short
def analyze_ticker(self, ticker):
"""Analyze a ticker for trading signals"""
prediction = self.fb.predictions.ticker(ticker, prediction_type="daily")
pred = prediction.get("prediction", {})
return {
"ticker": ticker,
"expected_short": pred.get("expectedShort"),
"expected_mid": pred.get("expectedMid"),
"expected_long": pred.get("expectedLong"),
"last_update": pred.get("lastUpdate")
}
# Use the backtest framework
backtest = SimpleBacktest(api_key="YOUR_API_KEY")
# Analyze multiple tickers
tickers = ["AAPL", "MSFT", "NVDA"]
for ticker in tickers:
analysis = backtest.analyze_ticker(ticker)
signal, expected = backtest.get_signal(ticker)
print(f"\n{ticker}:")
print(f" Signal: {signal}")
print(f" Expected Short: {analysis['expected_short']}%")
print(f" Expected Mid: {analysis['expected_mid']}%")

Step 5: Advanced Backtest with Multiple Signals

Section titled “Step 5: Advanced Backtest with Multiple Signals”

Combine AI predictions with other signals for better results:

class AdvancedBacktest:
def __init__(self, api_key, initial_capital=100000):
self.fb = FinBrainClient(api_key=api_key)
self.initial_capital = initial_capital
def get_combined_signal(self, market, ticker):
"""Combine multiple signals for better accuracy"""
signals = {"prediction": 0, "sentiment": 0, "insider": 0}
# AI Prediction signal
try:
pred_data = self.fb.predictions.ticker(ticker, prediction_type="daily")
pred = pred_data.get("prediction", {})
if pred:
expected_short = float(pred.get("expectedShort", 0))
if expected_short > 1:
signals["prediction"] = 1
elif expected_short < -1:
signals["prediction"] = -1
except:
pass
# Sentiment signal
try:
sent = self.fb.sentiments.ticker(market, ticker)
sentiment_data = sent.get("sentimentAnalysis", {})
if sentiment_data:
dates = sorted(sentiment_data.keys(), reverse=True)
score = float(sentiment_data[dates[0]]) if dates else 0
if score > 0.5:
signals["sentiment"] = 1
elif score < -0.5:
signals["sentiment"] = -1
except:
pass
# Insider signal
try:
insider = self.fb.insider_transactions.ticker(market, ticker)
transactions = insider.get("insiderTransactions", [])
if transactions:
recent = transactions[:5]
buys = sum(1 for t in recent if "Buy" in t.get("transaction", ""))
sells = sum(1 for t in recent if "Sale" in t.get("transaction", ""))
if buys > sells + 1:
signals["insider"] = 1
elif sells > buys + 1:
signals["insider"] = -1
except:
pass
# Combined score
combined = (
signals["prediction"] * 0.5 +
signals["sentiment"] * 0.3 +
signals["insider"] * 0.2
)
return combined, signals
# Example usage
backtest = AdvancedBacktest(api_key="YOUR_API_KEY")
combined_signal, breakdown = backtest.get_combined_signal("S&P 500", "AAPL")
print(f"\nCombined Signal: {combined_signal:.2f}")
print(f"Breakdown: {breakdown}")

Use as_dataframe=True to get structured DataFrames directly from the SDK:

from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
# Get all S&P 500 predictions as a DataFrame (one API call!)
df = fb.predictions.market("S&P 500", prediction_type="daily", as_dataframe=True)
print(df.head())
# expectedShort expectedMid expectedLong sentimentScore
# ticker
# AAPL 0.22 0.58 0.25 0.186
# MSFT 1.15 1.82 2.10 0.342
# NVDA 2.31 3.45 4.12 0.521
# Filter for bullish signals (expected long-term gain > 2%)
bullish = df[df["expectedLong"] > 2.0]
print(f"\nStrong Bullish Signals: {len(bullish)}")
print(bullish.sort_values("expectedLong", ascending=False))
# Filter for bearish signals
bearish = df[df["expectedShort"] < -1.0]
print(f"\nBearish Signals: {len(bearish)}")
# Combine with sentiment for high-conviction picks
high_conviction = df[(df["expectedLong"] > 1.5) & (df["sentimentScore"] > 0.3)]
print(f"\nHigh Conviction Bullish: {len(high_conviction)}")

Get price forecast time series for a single ticker:

# Get price forecasts as DataFrame
forecasts = fb.predictions.ticker("AAPL", prediction_type="daily", as_dataframe=True)
print(forecasts)
# main lower upper
# date
# 2024-11-04 201.33 197.21 205.45
# 2024-11-05 202.77 196.92 208.61
# 2024-11-06 203.99 196.90 211.08
# Calculate expected return from current price
current_price = 200.0 # Example
forecasts["expected_return"] = (forecasts["main"] - current_price) / current_price * 100
print(forecasts)

Here’s a complete script using DataFrames for clean, efficient analysis:

from finbrain import FinBrainClient
import pandas as pd
fb = FinBrainClient(api_key="YOUR_API_KEY")
def screen_market(market="S&P 500"):
"""Screen entire market using DataFrame output"""
# Get all predictions in one call
df = fb.predictions.market(market, prediction_type="daily", as_dataframe=True)
# Generate signal scores
df["score"] = 0
# Prediction signals
df.loc[df["expectedShort"] > 2, "score"] += 2
df.loc[(df["expectedShort"] > 1) & (df["expectedShort"] <= 2), "score"] += 1
df.loc[df["expectedShort"] < -2, "score"] -= 2
df.loc[(df["expectedShort"] < -1) & (df["expectedShort"] >= -2), "score"] -= 1
# Sentiment signals
df.loc[df["sentimentScore"] > 0.3, "score"] += 1
df.loc[df["sentimentScore"] < -0.3, "score"] -= 1
# Generate signal labels
df["signal"] = "hold"
df.loc[df["score"] >= 3, "signal"] = "strong_buy"
df.loc[(df["score"] >= 1) & (df["score"] < 3), "signal"] = "buy"
df.loc[df["score"] <= -3, "signal"] = "strong_sell"
df.loc[(df["score"] <= -1) & (df["score"] > -3), "signal"] = "sell"
return df
# Run the screener
results = screen_market("S&P 500")
print("=== Market Screening Results ===")
print(f"Total tickers: {len(results)}")
print(f"Strong Buy: {len(results[results['signal'] == 'strong_buy'])}")
print(f"Buy: {len(results[results['signal'] == 'buy'])}")
print(f"Hold: {len(results[results['signal'] == 'hold'])}")
print(f"Sell: {len(results[results['signal'] == 'sell'])}")
print(f"Strong Sell: {len(results[results['signal'] == 'strong_sell'])}")
# Top picks
print("\n=== Top 10 Bullish Picks ===")
top_picks = results.nlargest(10, "score")
print(top_picks[["expectedShort", "expectedLong", "sentimentScore", "score", "signal"]])
# Bottom picks (potential shorts)
print("\n=== Top 10 Bearish Picks ===")
bottom_picks = results.nsmallest(10, "score")
print(bottom_picks[["expectedShort", "expectedLong", "sentimentScore", "score", "signal"]])
def comprehensive_analysis(market, ticker):
"""Combine predictions, sentiment, and insider data"""
fb = FinBrainClient(api_key="YOUR_API_KEY")
# Get all data as DataFrames
predictions = fb.predictions.ticker(ticker, prediction_type="daily", as_dataframe=True)
sentiment = fb.sentiments.ticker(market, ticker, as_dataframe=True)
insiders = fb.insider_transactions.ticker(market, ticker, as_dataframe=True)
print(f"=== {ticker} Analysis ===")
# Price forecasts
print("\nPrice Forecasts:")
print(predictions)
# Sentiment trend
print("\nSentiment Trend:")
print(sentiment.tail(5))
print(f"Avg Sentiment (5d): {sentiment['sentiment'].tail(5).mean():.3f}")
# Recent insider activity
print("\nRecent Insider Transactions:")
if len(insiders) > 0:
print(insiders[["insiderTradings", "transaction", "shares", "USDValue"]].head(5))
return predictions, sentiment, insiders
# Analyze a specific ticker
preds, sent, ins = comprehensive_analysis("S&P 500", "AAPL")
  1. Use sufficient historical data - At least 1 year for meaningful results
  2. Account for transaction costs - Include commissions and slippage
  3. Avoid overfitting - Don’t optimize parameters on the same data you test
  4. Consider market conditions - Results may vary in bull vs bear markets
  5. Combine multiple signals - AI predictions + sentiment + insider data