Mastering the Ratings API: Analyst Upgrade Signals for Swing Trading and Momentum Plays

Mastering the Ratings API: Analyst Upgrade Signals for Swing Trading and Momentum Plays

Mastering the Ratings API: Analyst Upgrade Signals for Swing Trading and Momentum Plays

Analyst ratings play a steady role in how traders interpret a stock’s outlook.

by Thomas Cotter

December 11, 2025


Analyst ratings play a steady role in how traders interpret a stock’s outlook. An upgrade, a downgrade or a revised price target often sets the tone for short-term sentiment, and the reaction can be quick. These actions give a clear signal about how a research firm views a company’s prospects, which makes them useful for screening, watchlist building and event-driven trading.

Benzinga’s Ratings API provides a structured view of these events. Each entry includes the rating action, the current and prior price targets, analyst details and performance metrics. The format makes it easier to review what changed, who issued the call and whether the analyst has a strong track record.

This article walks through the endpoint and shows how to work with rating events in Python. We will look at the response structure, pull recent actions for individual tickers, filter meaningful revisions and connect the data with price movement for simple event studies. The goal is to make it straightforward to integrate ratings data into research tools or trading workflows.

Understanding Rating Actions and Price Targets

How Rating Actions Shape Sentiment

Analyst ratings signal a firm’s view on a company at a specific point in time. An upgrade, downgrade, reiteration or initiation often reflects a change in conviction based on earnings results, guidance, sector conditions or updated forecasts. These actions tend to influence short-term sentiment because they arrive with clear intent and are easy for the market to interpret.

The weight of a rating depends on who issued it and how the stock has been trading. Some calls are routine. Others can shift the tone for a few sessions, especially when they come from widely followed analysts.

The Role of Price Targets

Every rating update usually comes with a price target change. This is the part many traders focus on, since it anchors the analyst’s revised expectations. A modest adjustment may have limited impact. A large upward or downward revision can lead to stronger reactions, particularly when several firms adjust their targets around the same time.

Price targets provide a simple frame. They show the upside or downside implied by the call, which makes them useful for screening or building short-term watchlists.

Why Analyst History Matters

Not all analysts influence the market equally. Some have a strong track record, while others produce inconsistent results. The Ratings API includes performance metrics that help you gauge the credibility behind each action. This gives a clearer sense of whether a call should be treated as routine information or something that may carry more weight.

Together, these elements form a structured view of sentiment around a stock. Rating actions, price-target revisions and analyst history provide a direct way to understand how the market may interpret the latest changes.

Endpoint Walkthrough

The Ratings endpoint returns a structured list of analyst actions, price-target changes and performance metrics. The API supports date filtering, ticker-based queries, action-based filtering and analyst-level lookups. Below is a quick guide to the core request pattern and the fields that matter most.

Base Request

A typical call looks like this:


api_key = "YOUR BENZINGA API KEY"
url = "https://api.benzinga.com/api/v2/calendar/ratings"
 
headers = {"accept": "application/json"}
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 20
}
 
r = requests.get(url, params=params, headers=headers)
data = r.json()
data["ratings"][:2]
api_key = "YOUR BENZINGA API KEY"
url = "https://api.benzinga.com/api/v2/calendar/ratings"
 
headers = {"accept": "application/json"}
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 20
}
 
r = requests.get(url, params=params, headers=headers)
data = r.json()
data["ratings"][:2]
api_key = "YOUR BENZINGA API KEY"
url = "https://api.benzinga.com/api/v2/calendar/ratings"
 
headers = {"accept": "application/json"}
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 20
}
 
r = requests.get(url, params=params, headers=headers)
data = r.json()
data["ratings"][:2]
api_key = "YOUR BENZINGA API KEY"
url = "https://api.benzinga.com/api/v2/calendar/ratings"
 
headers = {"accept": "application/json"}
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 20
}
 
r = requests.get(url, params=params, headers=headers)
data = r.json()
data["ratings"][:2]

Note: Before you execute the code, make sure to replace “YOUR BENZINGA API KEY” with your secret API key. If you don’t have one, you can obtain it by creating a Benzinga API developer account. 

Each item in data[“ratings”] represents a single rating event.


Key Query Parameters

These parameters cover almost every common use case.

Parameter

Description

tickers

Filter by one or more comma-separated symbols.

date, date_from, date_to

Request a specific day or a time range.

action

Restrict to Upgrades, Downgrades, Maintains, Reiterates, or Initiates Coverage On.

analyst, analyst_id, firm, firm_id

Filter calls from specific analysts or research firms.

importance

0–5 score that indicates relevance.

pagesize, page

Pagination options for larger queries.

fields

Optional list of fields for lighter responses.

This set is enough for screening recent upgrades, isolating large price-target revisions or gathering all rating events tied to a watchlist.

Response Structure

Below is a simplified view of the fields you typically work with. This reflects the actual output returned by the API.

1. Event Details:

Field

Meaning

id

Unique identifier for the rating event.

date, time, updated

Event timestamps.

ticker, exchange, name, currency, isin

Security-level identifiers.

action_company

Rating action such as Maintains, Upgrades or Downgrades.

rating_current, rating_prior

Current and previous rating labels.

action_pt

Indicates whether the price target was Raised, Lowered or Maintained.

pt_current, pt_prior

Reported price targets.

adjusted_pt_current, adjusted_pt_prior

Corporate action-adjusted price targets.

pt_pct_change

Percentage change between prior and current targets.

2. Analyst and Meta Information:

Field

Meaning

analyst, analyst_name, analyst_id

Analyst and firm details.

ratings_accuracy

Historical performance metrics when requested.

importance

Internal relevance score from 0 to 5.

notes

Additional context where available.

url, url_calendar, url_news

Links to related pages.

These fields provide enough structure to filter rating actions, rank analysts, study target revisions and evaluate how impactful a call might be.

Use Case 1: Basic Data Extraction

The Ratings endpoint is straightforward to work with, and most entry-level workflows revolve around pulling recent rating actions for a ticker or a small watchlist. The examples below show simple extraction patterns that form the foundation for more advanced filtering later in the article.

Recent Rating Actions for a Single Ticker

This request retrieves the latest upgrades, downgrades or maintains actions for one symbol.


import requests
 
api_key = "YOUR BENZINGA API KEY"
url = "https://api.benzinga.com/api/v2/calendar/ratings"
 
headers = {"accept": "application/json"}
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_company"],
        item["rating_current"],
        item["pt_current"]
    )
import requests
 
api_key = "YOUR BENZINGA API KEY"
url = "https://api.benzinga.com/api/v2/calendar/ratings"
 
headers = {"accept": "application/json"}
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_company"],
        item["rating_current"],
        item["pt_current"]
    )
import requests
 
api_key = "YOUR BENZINGA API KEY"
url = "https://api.benzinga.com/api/v2/calendar/ratings"
 
headers = {"accept": "application/json"}
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_company"],
        item["rating_current"],
        item["pt_current"]
    )
import requests
 
api_key = "YOUR BENZINGA API KEY"
url = "https://api.benzinga.com/api/v2/calendar/ratings"
 
headers = {"accept": "application/json"}
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_company"],
        item["rating_current"],
        item["pt_current"]
    )

This produces a clean list of recent rating events with the rating action and updated price target.


Fetching Price-Target Changes Over a Date Range

You can pull all rating actions for a given window and review how price targets have changed over time.


params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "parameters[date_from]": "2025-12-01",
    "parameters[date_to]": "2025-12-05",
    "pagesize": 20
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_pt"],
        item["pt_prior"],
        "→",
        item["pt_current"]
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "parameters[date_from]": "2025-12-01",
    "parameters[date_to]": "2025-12-05",
    "pagesize": 20
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_pt"],
        item["pt_prior"],
        "→",
        item["pt_current"]
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "parameters[date_from]": "2025-12-01",
    "parameters[date_to]": "2025-12-05",
    "pagesize": 20
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_pt"],
        item["pt_prior"],
        "→",
        item["pt_current"]
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "parameters[date_from]": "2025-12-01",
    "parameters[date_to]": "2025-12-05",
    "pagesize": 20
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_pt"],
        item["pt_prior"],
        "→",
        item["pt_current"]
    )

This makes it easy to scan for significant revisions, whether raised or lowered.


Pulling Rating Events for a Watchlist

Multiple symbols can be queried in one request by separating them with commas.


params = {
    "token": api_key,
    "parameters[tickers]": "AAPL,MSFT,AMZN,NVDA",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(item["ticker"], item["action_company"], item["pt_current"])
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL,MSFT,AMZN,NVDA",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(item["ticker"], item["action_company"], item["pt_current"])
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL,MSFT,AMZN,NVDA",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(item["ticker"], item["action_company"], item["pt_current"])
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL,MSFT,AMZN,NVDA",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(item["ticker"], item["action_company"], item["pt_current"])

This pattern is useful for checking if any names in a portfolio or watchlist were upgraded, downgraded or had their targets revised recently.


Use Case 2: Applied Filtering and Analysis

The Ratings endpoint becomes more useful when you begin filtering for specific types of events. Upgrades, large price-target revisions and calls from consistent analysts often carry more weight than routine updates. This section shows how to work with those patterns directly in Python.

Filtering Only Upgrades or Downgrades

Many workflows start by isolating rating actions that reflect a clear change in outlook. You can filter at the API level by passing action=Upgrades or action=Downgrades.


params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "parameters[action]": "Upgrades",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_company"],
        item["rating_prior"],
        "→",
        item["rating_current"],
        item["pt_current"]
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "parameters[action]": "Upgrades",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_company"],
        item["rating_prior"],
        "→",
        item["rating_current"],
        item["pt_current"]
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "parameters[action]": "Upgrades",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_company"],
        item["rating_prior"],
        "→",
        item["rating_current"],
        item["pt_current"]
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "parameters[action]": "Upgrades",
    "pagesize": 10
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
for item in ratings:
    print(
        item["date"],
        item["action_company"],
        item["rating_prior"],
        "→",
        item["rating_current"],
        item["pt_current"]
    )

This gives a clean list of upgrades with the updated rating and price target.


Identifying Significant Price-Target Revisions

Price-target changes often matter more than the rating label, especially when the revision is large. You can use pt_pct_change to find meaningful moves.


params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 50
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
significant = []
 
for item in ratings:
    try:
        if abs(float(item["pt_pct_change"])) >= 10:
            significant.append(item)
    except:
        pass
 
for item in significant:
    print(
        item["date"],
        item["action_pt"],
        item["pt_prior"],
        "→",
        item["pt_current"],
        f"({item['pt_pct_change']}%)"
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 50
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
significant = []
 
for item in ratings:
    try:
        if abs(float(item["pt_pct_change"])) >= 10:
            significant.append(item)
    except:
        pass
 
for item in significant:
    print(
        item["date"],
        item["action_pt"],
        item["pt_prior"],
        "→",
        item["pt_current"],
        f"({item['pt_pct_change']}%)"
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 50
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
significant = []
 
for item in ratings:
    try:
        if abs(float(item["pt_pct_change"])) >= 10:
            significant.append(item)
    except:
        pass
 
for item in significant:
    print(
        item["date"],
        item["action_pt"],
        item["pt_prior"],
        "→",
        item["pt_current"],
        f"({item['pt_pct_change']}%)"
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL",
    "pagesize": 50
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
significant = []
 
for item in ratings:
    try:
        if abs(float(item["pt_pct_change"])) >= 10:
            significant.append(item)
    except:
        pass
 
for item in significant:
    print(
        item["date"],
        item["action_pt"],
        item["pt_prior"],
        "→",
        item["pt_current"],
        f"({item['pt_pct_change']}%)"
    )

This pattern helps surface rating events that imply a clear shift in analyst expectation.


Building a Simple Priority Watchlist

The endpoint also includes an importance field from 0 to 5. Combined with price-target changes and the action type, it can be used to build a basic watchlist of events that may deserve closer attention.


params = {
    "token": api_key,
    "parameters[tickers]": "AAPL,MSFT,AMZN,NVDA",
    "pagesize": 30
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
watchlist = []
 
for item in ratings:
    try:
        if (
            item["action_company"] in ("Upgrades", "Maintains")
            and float(item["pt_pct_change"]) >= 5
            and int(item.get("importance", 0)) >= 3
        ):
            watchlist.append(item)
    except:
        pass
 
for item in watchlist:
    print(
        item["date"],
        item["ticker"],
        item["analyst"],
        item["action_company"],
        item["pt_prior"],
        "→",
        item["pt_current"],
        f"({item['pt_pct_change']}%)",
        "Importance:",
        item["importance"]
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL,MSFT,AMZN,NVDA",
    "pagesize": 30
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
watchlist = []
 
for item in ratings:
    try:
        if (
            item["action_company"] in ("Upgrades", "Maintains")
            and float(item["pt_pct_change"]) >= 5
            and int(item.get("importance", 0)) >= 3
        ):
            watchlist.append(item)
    except:
        pass
 
for item in watchlist:
    print(
        item["date"],
        item["ticker"],
        item["analyst"],
        item["action_company"],
        item["pt_prior"],
        "→",
        item["pt_current"],
        f"({item['pt_pct_change']}%)",
        "Importance:",
        item["importance"]
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL,MSFT,AMZN,NVDA",
    "pagesize": 30
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
watchlist = []
 
for item in ratings:
    try:
        if (
            item["action_company"] in ("Upgrades", "Maintains")
            and float(item["pt_pct_change"]) >= 5
            and int(item.get("importance", 0)) >= 3
        ):
            watchlist.append(item)
    except:
        pass
 
for item in watchlist:
    print(
        item["date"],
        item["ticker"],
        item["analyst"],
        item["action_company"],
        item["pt_prior"],
        "→",
        item["pt_current"],
        f"({item['pt_pct_change']}%)",
        "Importance:",
        item["importance"]
    )
params = {
    "token": api_key,
    "parameters[tickers]": "AAPL,MSFT,AMZN,NVDA",
    "pagesize": 30
}
 
r = requests.get(url, params=params, headers=headers)
ratings = r.json().get("ratings", [])
 
watchlist = []
 
for item in ratings:
    try:
        if (
            item["action_company"] in ("Upgrades", "Maintains")
            and float(item["pt_pct_change"]) >= 5
            and int(item.get("importance", 0)) >= 3
        ):
            watchlist.append(item)
    except:
        pass
 
for item in watchlist:
    print(
        item["date"],
        item["ticker"],
        item["analyst"],
        item["action_company"],
        item["pt_prior"],
        "→",
        item["pt_current"],
        f"({item['pt_pct_change']}%)",
        "Importance:",
        item["importance"]
    )


This creates a focused list of upgrades or maintained ratings with a noticeable target increase and a higher importance score, which is a practical starting point for swing-trade or short-term idea generation.

Use Case 3: Advanced Event Study

Rating actions become more informative when you place them next to price movement. One simple approach is to align each event with intraday bars for the same stock and see how the price moved immediately after the call.

Pulling Rating Events for a Time Window

First, request rating actions for a specific ticker and date range.


import pandas as pd
 
ratings_url = "https://api.benzinga.com/api/v2/calendar/ratings"
headers = {"accept": "application/json"}
 
ratings_params = {
    "token": api_key,
    "parameters[tickers]": "NVDA",
    "pagesize": 100
}
 
ratings_r = requests.get(ratings_url, params=ratings_params, headers=headers)
ratings_raw = ratings_r.json().get("ratings", [])
 
ratings_df = pd.DataFrame(ratings_raw)
 
ratings_df["event_time"] = pd.to_datetime(
    ratings_df["date"] + " " + ratings_df["time"],
    utc=True
)
ratings_df = ratings_df.sort_values("event_time").reset_index(drop=True)
ratings_df[["date", "time", "analyst", "action_company", "pt_prior", "pt_current"]].head()
import pandas as pd
 
ratings_url = "https://api.benzinga.com/api/v2/calendar/ratings"
headers = {"accept": "application/json"}
 
ratings_params = {
    "token": api_key,
    "parameters[tickers]": "NVDA",
    "pagesize": 100
}
 
ratings_r = requests.get(ratings_url, params=ratings_params, headers=headers)
ratings_raw = ratings_r.json().get("ratings", [])
 
ratings_df = pd.DataFrame(ratings_raw)
 
ratings_df["event_time"] = pd.to_datetime(
    ratings_df["date"] + " " + ratings_df["time"],
    utc=True
)
ratings_df = ratings_df.sort_values("event_time").reset_index(drop=True)
ratings_df[["date", "time", "analyst", "action_company", "pt_prior", "pt_current"]].head()
import pandas as pd
 
ratings_url = "https://api.benzinga.com/api/v2/calendar/ratings"
headers = {"accept": "application/json"}
 
ratings_params = {
    "token": api_key,
    "parameters[tickers]": "NVDA",
    "pagesize": 100
}
 
ratings_r = requests.get(ratings_url, params=ratings_params, headers=headers)
ratings_raw = ratings_r.json().get("ratings", [])
 
ratings_df = pd.DataFrame(ratings_raw)
 
ratings_df["event_time"] = pd.to_datetime(
    ratings_df["date"] + " " + ratings_df["time"],
    utc=True
)
ratings_df = ratings_df.sort_values("event_time").reset_index(drop=True)
ratings_df[["date", "time", "analyst", "action_company", "pt_prior", "pt_current"]].head()
import pandas as pd
 
ratings_url = "https://api.benzinga.com/api/v2/calendar/ratings"
headers = {"accept": "application/json"}
 
ratings_params = {
    "token": api_key,
    "parameters[tickers]": "NVDA",
    "pagesize": 100
}
 
ratings_r = requests.get(ratings_url, params=ratings_params, headers=headers)
ratings_raw = ratings_r.json().get("ratings", [])
 
ratings_df = pd.DataFrame(ratings_raw)
 
ratings_df["event_time"] = pd.to_datetime(
    ratings_df["date"] + " " + ratings_df["time"],
    utc=True
)
ratings_df = ratings_df.sort_values("event_time").reset_index(drop=True)
ratings_df[["date", "time", "analyst", "action_company", "pt_prior", "pt_current"]].head()

This gives you a chronologically ordered list of rating events for the chosen window.

Retrieving Price Bars

You can use intraday or daily bars depending on the level of detail you want. Below is an example for 1-hour bars extracted using the Benzinga Historical Bar Data endpoint.


bars_url = "https://api.benzinga.com/api/v2/bars"
 
bars_params = {
    "token": api_key,
    "symbols": "AAPL",
    "from": ratings_df.date[0],
    "to": ratings_df.date.iloc[-1],
    "interval": "1H"
}
 
bars_r = requests.get(bars_url, params=bars_params, headers=headers)
bars_raw = bars_r.json()
 
candles = bars_raw[0]["candles"]
 
bar_rows = []
for c in candles:
    bar_rows.append(
        {
            "dateTime": c["dateTime"],
            "open": float(c["open"]),
            "high": float(c["high"]),
            "low": float(c["low"]),
            "close": float(c["close"]),
            "volume": int(c["volume"])
        }
    )
 
bars_df = pd.DataFrame(bar_rows)
bars_df["dateTime"] = pd.to_datetime(bars_df["dateTime"], utc=True)
bars_df = bars_df.sort_values("dateTime")
bars_df["close_next"] = bars_df["close"].shift(-1)
bars_df = bars_df.dropna()
 
bars_df.tail()
bars_url = "https://api.benzinga.com/api/v2/bars"
 
bars_params = {
    "token": api_key,
    "symbols": "AAPL",
    "from": ratings_df.date[0],
    "to": ratings_df.date.iloc[-1],
    "interval": "1H"
}
 
bars_r = requests.get(bars_url, params=bars_params, headers=headers)
bars_raw = bars_r.json()
 
candles = bars_raw[0]["candles"]
 
bar_rows = []
for c in candles:
    bar_rows.append(
        {
            "dateTime": c["dateTime"],
            "open": float(c["open"]),
            "high": float(c["high"]),
            "low": float(c["low"]),
            "close": float(c["close"]),
            "volume": int(c["volume"])
        }
    )
 
bars_df = pd.DataFrame(bar_rows)
bars_df["dateTime"] = pd.to_datetime(bars_df["dateTime"], utc=True)
bars_df = bars_df.sort_values("dateTime")
bars_df["close_next"] = bars_df["close"].shift(-1)
bars_df = bars_df.dropna()
 
bars_df.tail()
bars_url = "https://api.benzinga.com/api/v2/bars"
 
bars_params = {
    "token": api_key,
    "symbols": "AAPL",
    "from": ratings_df.date[0],
    "to": ratings_df.date.iloc[-1],
    "interval": "1H"
}
 
bars_r = requests.get(bars_url, params=bars_params, headers=headers)
bars_raw = bars_r.json()
 
candles = bars_raw[0]["candles"]
 
bar_rows = []
for c in candles:
    bar_rows.append(
        {
            "dateTime": c["dateTime"],
            "open": float(c["open"]),
            "high": float(c["high"]),
            "low": float(c["low"]),
            "close": float(c["close"]),
            "volume": int(c["volume"])
        }
    )
 
bars_df = pd.DataFrame(bar_rows)
bars_df["dateTime"] = pd.to_datetime(bars_df["dateTime"], utc=True)
bars_df = bars_df.sort_values("dateTime")
bars_df["close_next"] = bars_df["close"].shift(-1)
bars_df = bars_df.dropna()
 
bars_df.tail()
bars_url = "https://api.benzinga.com/api/v2/bars"
 
bars_params = {
    "token": api_key,
    "symbols": "AAPL",
    "from": ratings_df.date[0],
    "to": ratings_df.date.iloc[-1],
    "interval": "1H"
}
 
bars_r = requests.get(bars_url, params=bars_params, headers=headers)
bars_raw = bars_r.json()
 
candles = bars_raw[0]["candles"]
 
bar_rows = []
for c in candles:
    bar_rows.append(
        {
            "dateTime": c["dateTime"],
            "open": float(c["open"]),
            "high": float(c["high"]),
            "low": float(c["low"]),
            "close": float(c["close"]),
            "volume": int(c["volume"])
        }
    )
 
bars_df = pd.DataFrame(bar_rows)
bars_df["dateTime"] = pd.to_datetime(bars_df["dateTime"], utc=True)
bars_df = bars_df.sort_values("dateTime")
bars_df["close_next"] = bars_df["close"].shift(-1)
bars_df = bars_df.dropna()
 
bars_df.tail()

Now you have a regular time series of 1-hour bars for the same period.


Matching Each Rating Event With The Next Price Bar

To see how the market reacted, align each rating event with the next available bar and compute a simple forward return.


merged = pd.merge_asof(
    ratings_df.sort_values("event_time"),
    bars_df.sort_values("dateTime"),
    left_on="event_time",
    right_on="dateTime",
    direction="forward"
)
 
merged["return_next_bar_pct"] = (
    (merged["close_next"] - merged["close"]) / merged["close"] * 100
)
merged = pd.merge_asof(
    ratings_df.sort_values("event_time"),
    bars_df.sort_values("dateTime"),
    left_on="event_time",
    right_on="dateTime",
    direction="forward"
)
 
merged["return_next_bar_pct"] = (
    (merged["close_next"] - merged["close"]) / merged["close"] * 100
)
merged = pd.merge_asof(
    ratings_df.sort_values("event_time"),
    bars_df.sort_values("dateTime"),
    left_on="event_time",
    right_on="dateTime",
    direction="forward"
)
 
merged["return_next_bar_pct"] = (
    (merged["close_next"] - merged["close"]) / merged["close"] * 100
)
merged = pd.merge_asof(
    ratings_df.sort_values("event_time"),
    bars_df.sort_values("dateTime"),
    left_on="event_time",
    right_on="dateTime",
    direction="forward"
)
 
merged["return_next_bar_pct"] = (
    (merged["close_next"] - merged["close"]) / merged["close"] * 100
)

Inspecting The Event Reaction Table

A compact view of the final table might look like this.


cols = [
    "date",
    "analyst",
    "action_company",
    "action_pt",
    "pt_prior",
    "pt_current",
    "close",
    "close_next",
    "return_next_bar_pct"
]
 
merged[cols][20:30]
cols = [
    "date",
    "analyst",
    "action_company",
    "action_pt",
    "pt_prior",
    "pt_current",
    "close",
    "close_next",
    "return_next_bar_pct"
]
 
merged[cols][20:30]
cols = [
    "date",
    "analyst",
    "action_company",
    "action_pt",
    "pt_prior",
    "pt_current",
    "close",
    "close_next",
    "return_next_bar_pct"
]
 
merged[cols][20:30]
cols = [
    "date",
    "analyst",
    "action_company",
    "action_pt",
    "pt_prior",
    "pt_current",
    "close",
    "close_next",
    "return_next_bar_pct"
]
 
merged[cols][20:30]


This is not a trading strategy by itself. It is a clear event study view that shows how price moved in the bar immediately after each rating action. From here you can extend the window, export the table to a dashboard or combine it with other Benzinga endpoints if needed.

Common Questions About the Ratings API

What does the Ratings endpoint actually return?

It provides a structured list of analyst actions for a stock, including the rating change, the updated price target, the size of the revision and who issued the call. This lets you review rating activity without digging through individual reports.

Which fields matter most when working with this data?

Most workflows rely on the action type (action_company), the target revision (pt_prior, pt_current, pt_pct_change), the analyst name and the importance score. These fields are enough to filter meaningful events or build simple screens.

How is this different from a standard stock data API?

A stock data API tells you what the price did. The Ratings endpoint helps explain why sentiment may have shifted by showing which firms changed their outlook and how aggressively they adjusted their targets.

Can the Ratings API be used in short-term analysis?

Yes. Each event has a clear timestamp, which makes it easy to line up rating actions with intraday bars and see how the stock moved afterward. This is a simple way to build event-driven watchlists or reaction studies.

Closing Notes

The Benzinga Ratings endpoint offers a clear way to track analyst actions, price-target revisions and changes in sentiment. With structured fields and simple filtering, it becomes easy to scan for meaningful updates, build small screening tools or study how the market reacts around these events.

If you want to explore further, the endpoint works smoothly alongside Benzinga’s bars and news data, giving you a complete view of both the event and the market’s response.

Quick Contact

Address

1 Campus Martius Detroit,

MI 48226, United States

Get in Touch

We love to help & we love to listen. Please fill out the form below and we’ll get back to you within a day

We love to help & we love to listen. Please fill out the form below and we’ll get back to you within a day

What data do you find interesting*