Prophet Price Forecast
Apply Meta Prophet for financial time series forecasting, decomposing price data into trend, seasonality, and holiday components with full uncertainty intervals around point predictions for risk-aware trading decisions.
Prophet Price Forecasting
Prophet is an open-source forecasting tool developed by Facebook (now Meta). It is designed to make forecasting at scale easier, especially for business time series with strong seasonal effects and holidays. It works best with time series data that have hourly, daily, or weekly observations, and that exhibit several seasons of historical data.
Why Prophet for Price Forecasting?
Price series data, especially in financial markets or retail, often exhibit clear trends, daily, weekly, or yearly seasonality, and are influenced by external events (like holidays or promotions). Prophet is well-suited for such data due to its:
- Automatic handling of seasonality: It can detect and model multiple types of seasonality (e.g., daily, weekly, yearly).
- Robustness to outliers: It is designed to be robust to missing data and shifts in the trend.
- Holiday and custom event support: It allows users to define custom events that can impact the time series.
- Interpretable parameters: Its components (trend, seasonality, holidays) are easy to understand.
This notebook will guide you through the process of using Prophet for price forecasting, from data preparation to model interpretation.
# Install necessary libraries
!pip install prophet pandas matplotlib numpyRequirement already satisfied: prophet in /usr/local/lib/python3.12/dist-packages (1.3.0) Requirement already satisfied: pandas in /usr/local/lib/python3.12/dist-packages (2.2.2) Requirement already satisfied: matplotlib in /usr/local/lib/python3.12/dist-packages (3.10.0) Requirement already satisfied: numpy in /usr/local/lib/python3.12/dist-packages (2.0.2) Requirement already satisfied: cmdstanpy>=1.0.4 in /usr/local/lib/python3.12/dist-packages (from prophet) (1.3.0) Requirement already satisfied: holidays<1,>=0.25 in /usr/local/lib/python3.12/dist-packages (from prophet) (0.98) Requirement already satisfied: tqdm>=4.36.1 in /usr/local/lib/python3.12/dist-packages (from prophet) (4.67.3) Requirement already satisfied: importlib_resources in /usr/local/lib/python3.12/dist-packages (from prophet) (7.1.0) Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.12/dist-packages (from pandas) (2.9.0.post0) Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.12/dist-packages (from pandas) (2025.2) Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.12/dist-packages (from pandas) (2026.2) Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (1.3.3) Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (0.12.1) Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (4.63.0) Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (1.5.0) Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (26.2) Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (11.3.0) Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (3.3.2) Requirement already satisfied: stanio<2.0.0,>=0.4.0 in /usr/local/lib/python3.12/dist-packages (from cmdstanpy>=1.0.4->prophet) (0.5.1) Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.12/dist-packages (from python-dateutil>=2.8.2->pandas) (1.17.0)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from prophet import Prophet
# Suppress warnings for cleaner output
import warnings
warnings.filterwarnings('ignore')Understanding Prophet's Model Components
Prophet decomposes a time series into three main components:
$$y(t) = g(t) + s(t) + h(t) + \epsilon_t$$
Where:
- $g(t)$: Trend component, which models non-periodic changes in the time series.
- $s(t)$: Seasonality component, which models periodic changes (e.g., weekly, yearly).
- $h(t)$: Holiday component, which models the impact of specified holidays or irregular events.
- $\epsilon_t$: Error term, representing any idiosyncratic changes not accommodated by the model.
Data Preparation for Prophet
Prophet requires the input DataFrame to have two specific columns:
ds: (datestamp) column, which should be of a format parseable by Pandas (e.g.,YYYY-MM-DDorYYYY-MM-DD HH:MM:SS).y: (numeric) column, which represents the measurement we want to forecast (e.g., price).
import pandas as pd
import numpy as np
def generate_mock_price_data(start_date='2020-01-01', periods=730, initial_price=100, trend_strength=0.05, seasonality_amplitude_base=5, volatility=2, spike_frequency=0.02, spike_magnitude=10):
"""
Generates more realistic mock daily price data with trend, seasonality, noise, and occasional spikes.
Inputs:
start_date (str): Start date for the time series.
periods (int): Number of days to generate data for.
initial_price (float): Starting price.
trend_strength (float): Overall strength of the linear trend component.
seasonality_amplitude_base (float): Base amplitude for seasonal components.
volatility (float): Standard deviation for daily random price changes.
spike_frequency (float): Probability of a random spike/drop occurring on any given day.
spike_magnitude (float): Maximum magnitude of a random spike/drop.
Outputs:
pd.DataFrame: A DataFrame with 'ds' and 'y' columns.
"""
dates = pd.date_range(start=start_date, periods=periods, freq='D')
time_index = np.arange(periods)
# 1. Base Trend: A general upward trend, but not perfectly linear
# Using a slightly curved trend to make it less obvious
base_trend = initial_price + trend_strength * time_index + 5 * np.sin(time_index / 100)
# 2. Weekly Seasonality: More complex than a single sine wave
weekly_seasonality = (
seasonality_amplitude_base * np.sin(2 * np.pi * (time_index % 7) / 7) +
(seasonality_amplitude_base / 2) * np.cos(2 * np.pi * (time_index % 7) / 7 + np.pi/4)
)
# 3. Yearly Seasonality: More complex
yearly_seasonality = (
seasonality_amplitude_base * 1.5 * np.sin(2 * np.pi * time_index / 365) +
(seasonality_amplitude_base / 2) * np.cos(2 * np.pi * time_index / (365/2) + np.pi/2)
)
# 4. Random Walk / Daily Price Changes (autocorrelation)
# Each day's price change is a small random step
daily_changes = np.random.normal(0, volatility, periods).cumsum()
# 5. Occasional Spikes/Drops
spikes = np.zeros(periods)
for i in range(periods):
if np.random.rand() < spike_frequency:
# Randomly choose between a spike or a drop
spike_direction = 1 if np.random.rand() > 0.5 else -1
spikes[i] = spike_direction * np.random.uniform(spike_magnitude / 2, spike_magnitude)
# Combine components
prices = base_trend + weekly_seasonality + yearly_seasonality + daily_changes + spikes
prices = np.maximum(5, prices) # Ensure prices are non-negative and have a floor
df = pd.DataFrame({
'ds': dates,
'y': prices
})
return df
# Generate sample price data for 2 years with revised parameters
df_price = generate_mock_price_data(periods=730, initial_price=100, trend_strength=0.08, seasonality_amplitude_base=7, volatility=1.5, spike_frequency=0.03, spike_magnitude=15)
display(df_price.head())
display(df_price.tail())| ds | y | |
|---|---|---|
| 0 | 2020-01-01 | 102.814512 |
| 1 | 2020-01-02 | 104.439765 |
| 2 | 2020-01-03 | 102.895106 |
| 3 | 2020-01-04 | 100.444020 |
| 4 | 2020-01-05 | 101.073664 |
| ds | y | |
|---|---|---|
| 725 | 2021-12-26 | 145.151941 |
| 726 | 2021-12-27 | 144.788752 |
| 727 | 2021-12-28 | 149.430002 |
| 728 | 2021-12-29 | 157.051613 |
| 729 | 2021-12-30 | 158.802334 |
Error: Runtime no longer has a reference to this dataframe, please re-run this cell and try again.
Initializing and Fitting the Prophet Model
Once the data is prepared, initializing and fitting the Prophet model is straightforward. You can customize various parameters during initialization, but for a basic forecast, the default settings often work well.
Prophet(): Initializes the model. You can specify parameters likeseasonality_mode,yearly_seasonality,weekly_seasonality,daily_seasonality,holidays, etc.fit(df): Trains the model using your historical data. It learns the underlying trend, seasonality, and holiday effects from the provideddsandycolumns.
# Initialize Prophet model
# We explicitly set yearly and weekly seasonality to True as our data has these components.
# For financial data, 'multiplicative' seasonality might sometimes be more appropriate if the seasonal effect scales with the trend.
# Here, we'll start with 'additive' which is the default.
m = Prophet(yearly_seasonality=True, weekly_seasonality=True, daily_seasonality=False)
# Fit the model to the historical data
m.fit(df_price)
print("Prophet model fitted successfully!")Prophet model fitted successfully!
Making Future Predictions
After fitting the model, you can make predictions for future time points.
make_future_dataframe(periods=int, freq=str): Creates a DataFrame with future dates (and historical dates used for training).periodsspecifies the number of future time steps, andfreqspecifies the frequency (e.g., 'D' for daily, 'H' for hourly).predict(future_df): Generates a forecast DataFrame containing predictions (yhat), along with lower (yhat_lower) and upper (yhat_upper) bounds for the predictions.
# Create a DataFrame with future dates for forecasting
# Let's forecast for the next 365 days (1 year)
future = m.make_future_dataframe(periods=365)
# Make predictions
forecast = m.predict(future)
print("Forecast DataFrame head:")
display(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].head())
print("\nForecast DataFrame tail (showing future predictions):")
display(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())Forecast DataFrame head:
| ds | yhat | yhat_lower | yhat_upper | |
|---|---|---|---|---|
| 0 | 2020-01-01 | 107.548795 | 103.194590 | 111.335827 |
| 1 | 2020-01-02 | 110.001342 | 105.927107 | 113.746103 |
| 2 | 2020-01-03 | 109.155178 | 105.309395 | 113.247405 |
| 3 | 2020-01-04 | 105.522851 | 101.513271 | 109.614359 |
| 4 | 2020-01-05 | 102.291513 | 98.105198 | 106.105319 |
Forecast DataFrame tail (showing future predictions):
| ds | yhat | yhat_lower | yhat_upper | |
|---|---|---|---|---|
| 1090 | 2022-12-26 | 216.285730 | 177.180685 | 253.835898 |
| 1091 | 2022-12-27 | 219.439381 | 179.985065 | 256.979869 |
| 1092 | 2022-12-28 | 223.710860 | 184.703497 | 260.976656 |
| 1093 | 2022-12-29 | 225.989310 | 187.110168 | 263.941213 |
| 1094 | 2022-12-30 | 224.973425 | 185.514845 | 263.081453 |
Error: Runtime no longer has a reference to this dataframe, please re-run this cell and try again.
Visualizing the Forecast
Prophet provides convenient plotting functions to visualize the forecast and its components.
1. Overall Forecast Plot
This plot shows the historical data (black dots), the model's fitted line (blue line), and the predicted future values with uncertainty intervals (light blue shaded area). This helps in visually assessing the model's performance and the general trend of the forecast.
# Plot the overall forecast
fig1 = m.plot(forecast, figsize=(10, 6))
plt.title('Prophet Price Forecast (Historical + Predicted)')
plt.xlabel('Date')
plt.ylabel('Price')
plt.grid(True)
plt.show()
# Interpretation:
# The black dots represent the actual historical price data.
# The blue line represents the Prophet model's fit to the historical data and its forecast into the future.
# The light blue shaded area indicates the uncertainty interval (yhat_lower to yhat_upper) for the predictions.
# This visualization helps to see how well the model captures the historical trend and seasonality, and where it predicts the price will go.2. Forecast Components Plot
This plot breaks down the forecast into its individual components: trend, yearly seasonality, and weekly seasonality. This is crucial for understanding the underlying drivers of the price movements and for gaining insights into the seasonal patterns.
- Trend: Shows the overall long-term direction of the price.
- Yearly Seasonality: Reveals how the price typically behaves over the course of a year.
- Weekly Seasonality: Shows typical price patterns within a week (e.g., higher on certain days).
# Plot the forecast components
fig2 = m.plot_components(forecast, figsize=(10, 8))
plt.suptitle('Prophet Forecast Components', y=1.02) # Add a main title for all subplots
plt.tight_layout(rect=[0, 0.03, 1, 0.98]) # Adjust layout to prevent title overlap
plt.show()
# Interpretation:
# The top plot shows the overall trend identified by Prophet, which appears to be increasing over time in our mock data.
# The middle plot illustrates the yearly seasonality. For our mock data, there's a clear sinusoidal pattern, representing price fluctuations over a year.
# The bottom plot displays the weekly seasonality. This indicates typical price behavior on each day of the week, e.g., potentially higher prices on weekends or specific weekdays.Customizing Prophet (Advanced)
Prophet offers several ways to customize the model for better performance and more nuanced forecasts:
- Adding Holidays and Special Events: You can define a DataFrame of custom events (e.g., public holidays, product launches, market closures) that can influence prices.
- Custom Seasonality: Beyond yearly, weekly, and daily, you can add custom seasonalities (e.g., quarterly, hourly) if your data supports it.
- Changepoint Detection: Prophet automatically detects changepoints in the trend, but you can manually specify potential changepoint dates or adjust the
changepoint_prior_scaleparameter to control the flexibility of the trend. - Seasonality Mode: Change
seasonality_modefrom 'additive' to 'multiplicative' if the seasonal effect grows with the trend (common in financial time series).
For example, to add custom holidays:
# Example: Adding custom holidays
# Create a DataFrame of holidays (e.g., a 'Black Friday' effect)
holidays = pd.DataFrame({
'holiday': 'black_friday',
'ds': pd.to_datetime(['2020-11-27', '2021-11-26']),
'lower_window': 0,
'upper_window': 1,
})
# Initialize Prophet with holidays
m_holidays = Prophet(holidays=holidays, yearly_seasonality=True, weekly_seasonality=True)
m_holidays.fit(df_price)
future_holidays = m_holidays.make_future_dataframe(periods=365)
forecast_holidays = m_holidays.predict(future_holidays)
print("Forecast with Black Friday holiday effect:")
display(forecast_holidays[['ds', 'yhat', 'black_friday']].tail())
# You can also plot the holiday components:
fig_holidays = m_holidays.plot_components(forecast_holidays)
plt.show()INFO:prophet:Disabling daily seasonality. Run prophet with daily_seasonality=True to override this.
Forecast with Black Friday holiday effect:
| ds | yhat | black_friday | |
|---|---|---|---|
| 1090 | 2022-12-26 | 216.742002 | 0.0 |
| 1091 | 2022-12-27 | 219.913530 | 0.0 |
| 1092 | 2022-12-28 | 224.206290 | 0.0 |
| 1093 | 2022-12-29 | 226.504415 | 0.0 |
| 1094 | 2022-12-30 | 225.488938 | 0.0 |
Conclusion
Prophet is a powerful and user-friendly tool for forecasting time series data, particularly well-suited for price forecasting due to its ability to handle trends, various seasonalities, and custom events. By understanding its components and how to prepare data, you can generate robust and interpretable price forecasts. Remember to always evaluate your model's performance and consider domain-specific knowledge to fine-tune your predictions.