Using Analyst Price Targets and Historical Stock Data to Gain an Investment Edge

1 day ago 10

To begin, we’ll retrieve data from the Financial Modeling Prep (FMP) API. This API provides comprehensive financial data, including analyst price targets and historical stock price trends.

  1. Price Target Data
  • priceWhenPosted: The stock price at the time the target was published.
  • adjPriceTarget: The price target adjusted for splits and market conditions.
  • Additional data such as analyst name, news title, publisher, and the source URL.

2. Historical Price Data

  • adjClose: The adjusted closing price for each trading day.

Using Python, we’ll write a script to fetch and clean this data. Ensure you have your API key ready from the FMP platform.

import requests
import pandas as pd
import matplotlib.pyplot as plt
import mplcursors
import webbrowser

API_KEY = 'your_api_key_here'
def fetch_data(ticker):
# Fetch price target data
price_target_url = f'https://financialmodelingprep.com/api/v4/price-target?symbol={ticker}&apikey={API_KEY}'
price_targets = requests.get(price_target_url).json()

# Fetch historical price data
historical_url = f'https://financialmodelingprep.com/api/v3/historical-price-full/{ticker}?apikey={API_KEY}'
historical_prices = requests.get(historical_url).json()

return price_targets, historical_prices

# Replace 'MSFT' with any stock ticker you want to analyze
price_target_data, historical_data = fetch_data('MSFT')

Organize the retrieved data into a pandas DataFrame for easier manipulation, as we’ll be merging the two datasets to align price targets with the corresponding historical prices.

Once we’ve fetched the data, we need to process it to align the timeframes and isolate key details. Our goal is to:

  • Extract the publication dates of the price targets.
  • Map each price target to the corresponding stock price when posted.
  • Include the adjusted closing prices from the historical data for trend visualization.
# Convert price target data into DataFrame
price_target_df = pd.DataFrame(price_target_data)
price_target_df['date'] = pd.to_datetime(price_target_df['publishedDate'])

# Convert historical prices into DataFrame
historical_prices_df = pd.DataFrame(historical_data['historical'])
historical_prices_df['date'] = pd.to_datetime(historical_prices_df['date'])

# Merge the data on dates
merged_df = pd.merge(price_target_df, historical_prices_df, on='date', how='inner')

# Extract relevant columns
merged_df = merged_df[['date', 'priceWhenPosted', 'adjPriceTarget', 'adjClose', 'newsTitle', 'newsPublisher', 'url']]

The power of this analysis comes alive when we visualize the data. Our visualization will include:

  • Yellow dots: Represent the stock price when the price target was posted.
  • Green or Red dots: Represent the adjusted target price, with color coding (green for upward targets, red for downward targets).
  • Arrows: Connecting dots to indicate the trajectory of analysts’ projections (upward or downward).
  • Historical price line: Showing the stock’s actual performance over time.
import matplotlib.dates as mdates
from matplotlib.patches import FancyArrowPatch

# Create the figure and axis
fig, ax = plt.subplots(figsize=(12, 6))

# Plot the historical adjusted close prices
ax.plot(merged_df['date'], merged_df['adjClose'], label='Historical Price', color='blue', linewidth=1.5)

# Add yellow dots for stock prices when targets were posted
yellow_dots = ax.scatter(merged_df['date'], merged_df['priceWhenPosted'], color='yellow', edgecolor='black', zorder=5, label='Price When Posted')

# Add green and red dots for price targets
def get_color(row):
return 'green' if row['adjPriceTarget'] > row['priceWhenPosted'] else 'red'

merged_df['dot_color'] = merged_df.apply(get_color, axis=1)
target_dots = ax.scatter(merged_df['date'], merged_df['adjPriceTarget'], color=merged_df['dot_color'], edgecolor='black', zorder=5, label='Price Target')

# Draw arrows
for i, row in merged_df.iterrows():
arrow = FancyArrowPatch(
(mdates.date2num(row['date']), row['priceWhenPosted']),
(mdates.date2num(row['date']), row['adjPriceTarget']),
color='gray', arrowstyle='-|>', linewidth=0.8, alpha=0.7)
ax.add_patch(arrow)

# Format the plot
ax.set_title('Analyst Price Targets vs. Historical Prices', fontsize=16)
ax.set_xlabel('Date', fontsize=12)
ax.set_ylabel('Price (USD)', fontsize=12)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
ax.legend(loc='upper left', fontsize=10)
plt.xticks(rotation=45)
plt.grid(alpha=0.3)

# Add hover interactivity
dot_to_url = dict(zip(yellow_dots.get_offsets(), merged_df['url']))
cursor = mplcursors.cursor(yellow_dots, hover=True)
@cursor.connect("add")
def on_add(sel):
row = merged_df.iloc[sel.index]
sel.annotation.set_text(f"Analyst: {row['newsPublisher']}\nPrice Target: {row['adjPriceTarget']}$\nPosted Price: {row['priceWhenPosted']}$")
sel.annotation.set_fontsize(10)
sel.annotation.set_bbox(dict(facecolor='white', alpha=0.8, edgecolor='gray'))

def on_click(event):
for artist, url in dot_to_url.items():
if artist.contains(event)[0]:
webbrowser.open(url)

fig.canvas.mpl_connect("button_press_event", on_click)
plt.show()

  • Hover Tooltips: When hovering over the yellow dots, a tooltip appears with the analyst’s name, price target, and the stock’s price when posted.
  • Clickable Points: Clicking a yellow dot opens the corresponding news article in the browser, offering instant access to more context.

Analyzing the resulting visualization offers powerful insights:

  1. Understanding Market Sentiment:
  • Observe how price targets evolve over time and how closely they align with the stock’s actual performance. Frequent upward or downward adjustments can signal shifts in market sentiment or company fundamentals.

2. Spotting Divergences:

  • Analysts’ overly optimistic or pessimistic targets might not match reality. Persistent divergence between historical prices and targets could reflect misaligned market expectations or evolving conditions.

3. Timing Trades:

  • Price targets posted during major news events often influence stock volatility. Use these signals to identify potential entry or exit points.

4. Assessing Analyst Accuracy:

  • Compare historical price trends with targets to determine whether specific analysts or firms consistently provide reliable forecasts.

This visualization bridges the gap between numbers and narrative, offering a clear lens through which investors can explore the intersection of analyst opinions and stock performance. With minimal Python programming, you can recreate this tool for any stock ticker, giving you a robust framework to inform trading strategies.

Try experimenting with different tickers, adding annotations, or exploring new interactivity layers to tailor the visualization further to your needs.

Read Entire Article