Skip to main content
Nixtla Enterprise now offers top foundation models, MCP, and agentic capabilities: 
Nixtla Blog

Long Term Mid Term and Short Term Forecasting with Polynomial Regression AutoARIMA and TimeGPT-1

Learn how to match forecasting models to your time horizon for better accuracy. Compare polynomial regression for long-term trends, AutoARIMA for mid-term cycles, and TimeGPT-1 for short-term predictions using real currency exchange data. Includes code examples for multi-horizon forecasting strategies.

With forecasting, you're trying to predict the future values of a time series based on its historical patterns, but is your model aligned with how far ahead you're looking? The time horizon, whether you're forecasting hours, weeks, or years ahead, drastically changes the type of model you should use. Ignoring your time horizon in favor of the trending "state of the art" forecasting model could lead to poor accuracy and wasted compute. In general, we can define three levels of forecasting: Long-term forecasting, e.g. predicting the average New York temperatures for 2026–2028 using temperatures from 1925–2025. Short-term forecasting, e.g. predicting the next hour stock price using minute-by-minute updates. Mid-term forecasting, e.g. estimating electricity demand for the coming weeks using daily data from recent months. In this blog post, we'll walk through a single forecasting problem and tackle it using three different approaches: one for long term forecasting, one for mid term forecasting, and one for short term forecasting. Multi-Horizon Forecasting StrategyTo handle long-term, mid-term, and short-term forecasts effectively, we can follow this structured approach: Start with the raw time series. Apply a rolling average of the data based on the desired time horizon (year, month, day). This is called aggregation. Apply a forecasting model suited to that level of aggregation to generate future estimates. Data and SourceAll the code used in this article is available in the GitHub repository PieroPaialungaAI/MultiLevelForecasting. The repository includes helper modules such as utils.py, plotter.py, constants.py and models.py, which handle the backend functionality so we can concentrate on the core logic of the algorithm. The dataset used in this article is publicly available on this Kaggle page. It contains daily exchange rates of various currencies against the euro from 1999 to 2020. For convenience, the dataset is also included in the repository under the data folder (PieroPaialungaAI/MultiLevelForecasting/data), so you don't need to download it separately. The following block of code provides a quick overview of the dataset. The plot displays the time series of the US Dollar value against 1 euro from 1999 to 2025, shown in cyan. import numpy as np import pandas as pd from plotter import * from utils import * data = pd.read_csv('data/euro_conversion_data.csv') plot_timeseries(data)

Raw Time Series

As we can see from the plot above, the timeseries shows a rich and complex structure. There are long-term trends, such as the rise and fall between 2002 and 2015, mid-term cycles, and short-term fluctuations that can be very interesting if we are monitoring the rapid evolution of the market. This is perfect for our study case: we can average the raw time series into yearly, monthly, or daily aggregates and build a tailored forecasting algorithms based on our aggregated time series. Let's work on that. Aggregation CodeThe aggregation of the data based on month/year/day can be done very easily using the aggregate_data function: def aggregate_data(data, key='year', column = Y_COLUMN): data = data.copy() data['Date'] = pd.to_datetime(data['Date']) # ensure proper dtype if key == 'year': data['time_group'] = data['Date'].dt.to_period('Y').astype(str) elif key == 'month': data['time_group'] = data['Date'].dt.to_period('M').astype(str) elif key == 'day': data['time_group'] = data['Date'].dt.to_period('D').astype(str) else: raise ValueError("Unsupported key. Choose from: 'year', 'month', 'day'") return data.groupby('time_group').mean(numeric_only=True).reset_index()[['time_group',column]] Now that we have the aggregated function we can build this aggregated time series dictionary. For each one of them we will perform a forecasting task. keys = ['year','month','day'] key_dict = {key: aggregate_data(data, key = key) for key in keys} Long Term ForecastingLet's give a look at the year aggregated time series. from models import * import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.preprocessing import PolynomialFeatures from constants import * # Declare Dataset y = np.array(key_dict['year']['US dollar']) x_full = np.arange(0, len(y)).reshape(-1, 1) print(x_full.shape) (27, 1) And it looks like this:

Yearly Averaged Data

In this case, we are interested in forecasting the next 2-3 averaged years of our time series. ModelIn our yearly averaged time series we have 27 values: not a whole lot. This could be considered discouraging, as forecasting algorithms (and machine learning models in general) perform well with a large training dataset. However, yearly aggregation has its own advantages. By averaging out short-term fluctuations, the signal becomes reasonably smooth and more focused on long-term trends. In this context, even simple models can capture meaningful patterns effectively, making them surprisingly powerful despite the limited data. To model this kind of smooth, long-term behavior, we can use polynomial regression. This method fits a curved line (a polynomial) to the data using the least squares approach to find the best-fitting parameters. It allows us to capture more complex, nonlinear trends that a straight line wouldn’t be able to model. A common approach to selecting the best polynomial degree and avoid overfitting is to use a train/validation/test split. The model is: Trained on the first part of the time series Validated on the next consecutive segment Tested on the final portion of the time series CodeThe code to do such is this: train, val, test = split_timeseries(y) model_tuple, best_degree = polynomial_fit_and_select(train, val) poly = PolynomialFeatures(degree = best_degree).fit(x_full) X_test_poly = poly.transform(x_full) y_full_pred = model_tuple[0].predict(X_test_poly) train_index = len(train) val_index = len(val) test_index = len(test) And we can plot it using the following block of code. The plot represents: In lime the train part of the time series In blue the validation part of the time series In white the test part of the timeseries In cyan the long term forecasting algorithm result x_full = x_full + 1999 plt.figure(figsize = IMAGE_FIGSIZE) plt.plot(x_full[0:train_index], y[:train_index], label='Train', color = 'lime', marker ='x') plt.plot(x_full[train_index-1:train_index+val_index], y[train_index-1:train_index+val_index], label='Validation', color = 'blue', marker = 'x') plt.plot(x_full[train_index+val_index-1:], y[train_index+val_index-1:], label='Test', color = 'white', marker = 'x') plt.plot(x_full, y_full_pred, color = 'cyan', label = 'Model Prediction')

Year Prediction with Polynomial Regression

As we can see, the model closely follows the shape of the time series and manages to forecast the next three years (2023, 2024, and 2025) with surprising accuracy, despite its simplicity. Mid Term ForecastingThe mid term dataset is roughly 12 times bigger than the long term one, as we can see from the following code: df = key_dict['month'] x_full = np.arange(0, len(df)).reshape(-1, 1) print(x_full.shape) (316, 1) And it looks like this:

Monthly Averaged Data

In this case, we are interested in understanding what will happen, let's say, in the next 3 or 4 months of our time series. ModelFor this dataset, we can try to apply a more complex model. An approach that allows us to control the complexity of the model is called ARIMA. ARIMA (AutoRegressive Integrated Moving Average) is a statistical model that combines three components: autoregression (past values), differencing (to make the series stationary), and moving average (past forecast errors) to predict future values. It’s well-suited for univariate time series that show patterns over time, and it can adapt to trends and seasonality depending on how it's configured. In particular, the ARIMA model is defined by three key hyperparameters: p (number of autoregressive terms), d (number of differences needed to make the series stationary), and q (number of moving average terms), which together control how the model learns from past values and errors. Choosing these numbers is non trivial and requires some time series exploration; however the AutoARIMA tool within statsforecast does the exploration for us and helps us select the optimal p, d and q values for our time series. CodeWith the following block of code, we run AutoARIMA on the most recent portion of the dataset, trimming the data to start from 2024. import matplotlib.pyplot as plt from statsforecast import StatsForecast from statsforecast.models import AutoARIMA df = key_dict['month'] x_full = np.arange(0, len(y)).reshape(-1, 1) df["unique_id"]="1" df.columns=["ds", "y", "unique_id"] Y_train_df = df[(df.ds>='2023-12-01') & (df.ds<='2024-12-01')] Y_test_df = df[df.ds>='2024-12-01'] season_length = 4 # Monthly data horizon = len(Y_test_df)+1 # number of predictions models = [AutoARIMA(season_length=season_length)] sf = StatsForecast(models=models, freq='MS') sf.fit(df=Y_train_df) Y_hat_df = sf.forecast(df=Y_train_df, h=horizon, fitted=True) Y_hat_df.head() values=sf.forecast_fitted_values() values unique_id ds y AutoARIMA 0 1 2024-01-01 1.09051 1.08271 1 1 2024-02-01 1.07947 1.08518 2 1 2024-03-01 1.08722 1.07857 3 1 2024-04-01 1.07278 1.08633 4 1 2024-05-01 1.08122 1.07399 5 1 2024-06-01 1.0759 1.08562 6 1 2024-07-01 1.08441 1.07611 7 1 2024-08-01 1.10122 1.08623 8 1 2024-09-01 1.1106 1.08999 9 1 2024-10-01 1.09043 1.09315 10 1 2024-11-01 1.06301 1.08004 11 1 2024-12-01 1.04787 1.072 As now we have a fitted ARIMA Model, we can use it to predict the first months of 2025. Y_test_pred = sf.forecast(df=Y_train_df, h=4, level=[95]) The following block of code displays the forecast of the ARIMA model: In lime, we show the historical monthly US Dollar to Euro conversion rates starting from 2019, trimmed to focus on the most recent years. In cyan, we display the mid-term forecast generated by the AutoARIMA model. The blue shaded area represents the confidence interval around the forecast, capturing the model’s uncertainty over the next few months. x_full = np.array(pd.to_datetime(df['ds'])) y_full = np.array(df['y']) x_test = np.array(pd.to_datetime(Y_test_df['ds'])) y_test = np.array(Y_test_df['y']) y_pred_test = np.array(Y_test_pred['AutoARIMA']) lower_bound = np.array(Y_test_pred['AutoARIMA-lo-95']) upper_bound = np.array(Y_test_pred['AutoARIMA-hi-95']) x_pred_test = np.array(Y_test_pred['ds']) plt.plot(x_full[240:], y_full[240:], color = 'lime', label = '') plt.plot(x_pred_test, y_pred_test, color ='cyan', label = 'AutoARIMA prediction') plt.fill_between(x_pred_test, lower_bound, upper_bound, color = 'cyan', alpha = 0.3, label = 'AutoARIMA 95p boundaries') plt.plot(x_test, y_test, color = 'lime', label = 'Test Set Data') plt.xlabel('Date (Year, sampled in Month)', fontsize = 12) plt.ylabel('US Dollar-Euro Conversion',fontsize = 12 ) plt.legend() plt.savefig('https://nixtla-blog.vercel.app/images/MultiLevelForecasting/month_prediction.svg')

Month Prediction with AutoARIMA

As we can see, the AutoARIMA model does a solid job here. The forecast (in cyan) tracks the actual test data (in lime) pretty closely, and the 95% confidence interval (in dark teal) comfortably captures the uncertainty without being overly wide. It’s a good example of how a well-tuned statistical model can perform strongly for mid-term forecasting. Short Term ForecastingFor short-term forecasting, we focus on the daily movements of the US Dollar–Euro conversion rate. Our dataset is already sampled at the daily level and this is how it looks like: df = key_dict['day'] x_full = np.arange(0, len(df)).reshape(-1, 1) print(x_full.shape) (6723, 1)

Day Averaged Data

ModelFor short-term forecasting, we shift our focus to daily data, where small fluctuations matter and recent changes carry the most weight. In this setting, traditional statistical models often fall short, we need something that can handle fine-grained patterns and fast dynamics. That’s where deep learning models, like TimeGPT-1, come into play. TimeGPT-1 is a transformer-based model specifically trained for time series forecasting across a wide range of domains. Unlike traditional models, it doesn't require manual feature engineering or extensive tuning, it learns patterns directly from raw temporal data. Its ability to generalize and handle complex, non-linear trends makes it especially powerful for short-term, high-frequency forecasting tasks. CodeThe code to forecast the first 10 days of 2025 can be seen in the following block of code. from nixtla import NixtlaClient keys = ['year','month','day'] key_dict = {key: aggregate_data(data, key = key) for key in keys} df = key_dict['day'] df = df.rename(columns = {'time_group': 'ds'}) df = df[df.ds >= '2024-01-01'] df = df.reset_index().drop('index', axis = 1) x_full = np.arange(0, len(y)).reshape(-1, 1) df["unique_id"]="1" timestamps = pd.date_range(start='2024-01-01', periods=len(df), freq='D') df['ds'] = timestamps df.columns=["ds", "y", "unique_id"] Y_train_df = df[(df.ds <= '2024-11-09') & (df.ds >= '2024-01-01')] Y_test_df = df[df.ds >= '2024-11-09'] test = Y_test_df input_seq = Y_train_df api_key = "your_api_key" nixtla_client = NixtlaClient(api_key=api_key) fcst_df = nixtla_client.forecast( df=input_seq, h=10, level=[75], finetune_steps=3, finetune_loss='mae', model='timegpt-1', time_col='ds', target_col='y' ) And this is how it looks like: In blue, we show the training data, which is the historical daily US Dollar to Euro conversion leading up to the forecast window. In lime, we display the actual test data for the short-term future. In cyan, we plot the TimeGPT-1 forecast for the next few days. The cyan shaded area represents the 75% confidence interval produced by TimeGPT-1, capturing the model's uncertainty in its predictions.

Day Prediction with TimeGPT

TimeGPT-1 is doing a great job here. The forecast (in cyan) aligns well with the actual test data (in lime), and the p75 confidence boundaries (in cyan) wrap the predictions nicely without being too loose or overly optimistic. It shows how transformer-based models can effectively capture short-term fluctuations, even in noisy daily data. ConclusionsIn this article, we explored how to approach forecasting across multiple time horizons, long term, mid term, and short term, using data aggregation and tailored models. In particular, we did the following: We introduced a strategy to handle different forecasting time scales by aggregating raw time series data into yearly, monthly, and daily frequencies. We applied Polynomial Regression for long-term forecasting, showing that even simple models can perform well on smoothed, low-frequency data. We used AutoARIMA for mid-term forecasting, allowing automatic selection of model parameters and achieving strong results on monthly data. We used TimeGPT-1, a transformer-based model for short-term forecasting, demonstrating its ability to capture fine-grained dynamics in high-frequency daily data.