Sitemap

Volatility forecasting with 4 lines of code without ML knowledge

5 min readJul 2, 2026

--

Hello friends! My name is Denis, I am an algorithmic trader and developer.

When I came to algotrading, I really wanted to apply machine learning quickly. But for this, you need to understand ML and Data Science, and I was just starting. Now I already understand, but I know that not all traders are ready to spend months on it.

Especially for those who want to try ML for volatility prediction without deep knowledge, I made the dquant library.

Now you can train a model without any knowledge of feature engineering, splits, or hyperparameters. All you need is a basic understanding of python and the ability to access raw data (open, close, high, low, and volume).
This is not a comprehensive guide, but rather a basic example. For more information, please refer to the documentation.

The whole process consists of 2 steps:

  1. Raw data preparation (open, close, high, low, volume)
  2. Training and prediction (4 lines of code)

What happens under the hood?:

  1. Data is divided into input and output
  2. Features are created from input data, targets from output data
  3. Data is divided into training and validation sets
  4. Training can stop early if the model starts to overfit
  5. At the end of training, an error graph is displayed

You can use the model for predictions, or you can save the model and use it later.
Go.
Installation

pip install dquant

Done. Dependencies (pandas, numpy, xgboost, lightgbm, matplotlib) are pulled automatically.
Check:

import dquant
print(dquant.version)  # prints the version

Quick Start: EURUSD Volatility Prediction for 4 Lines with Yahoo Finance

With Yahoo Finance, we can get price data for a specific period. First, we need to install the yfinance python library.

Installing Yahoo Finance

pip install yfinance

Python code

import pandas as pd
import yfinance as yf
from datetime import datetime, timedelta
from dquant.models import VolClustXGB
# 1. Download hourly data
start_date = datetime.now() - timedelta(days=700)
df = yf.download("EURUSD=X", start=start_date, interval='1h')
# Create a data frame with the input data
df = pd.DataFrame({
'open': df[('Open', 'EURUSD=X')].values,
'high': df[('High', 'EURUSD=X')].values,
'low': df[('Low', 'EURUSD=X')].values,
'close': df[('Close', 'EURUSD=X')].values,
'volume': df[('Volume', 'EURUSD=X')].values
}, index=df.index)
# 2. Create a model
model = VolClustXGB({}, early_stopping=True)
# 3. Train the model
features = ['TR', 'returns', 'abs_returns', 'gap', 'body', 'shadow', 'close_position', 'roll_atr_14']
model.fit(df, feature_list=features, input_bars=70, horizon=20, trees_count=200, show_results=True)
# 4. Make a forecast
rez = model.forecast(df.iloc[-70:].copy(), show=True)

The training and prediction process itself takes 4 lines, and you need to get the raw data first.

What you will see:

Training graph (error on train/validation)

Press enter or click to view image in full size
  • Red histogram — historical volatility
  • Green histogram — forecast for the next 20 bars
Press enter or click to view image in full size

Done. You can immediately set stops or calibrate the position size.

Get Denis Makarov’s stories in your inbox

Join Medium for free to get updates from this writer.

Let’s analyze the code from the dquant library itself in more detail.

The first line

model = VolClustXGB({}, early_stopping=True)

We create a class VolClustXGB, it uses the XGBoost (eXtreme Gradient Boosting) model. The first argument will be an empty dictionary. This means that the default hyperparameters will be used during training. early_stopping=True means that training will automatically stop when the model starts to overfit.
If you want to add your own hyperparameters (for this you need to understand ML), then the dictionary should not be empty. For example:

settings = {
'objective': 'reg:squarederror',
'learning_rate': 0.1,
'n_estimators': 1,
'max_depth': 3,
'min_child_weight': 5,
'subsample': 0.8,
'random_state': 42
}
model = VolClustXGB(settings, early_stopping=True)

But you can also use the default example if you don’t go into ML. This library was created specifically for you.

The second and third lines

features = ['TR', 'returns', 'abs_returns', 'gap', 'body', 'shadow', 'close_position', 'roll_atr_14']
model.fit(df, feature_list=features, input_bars=70, horizon=20, trees_count=200, show_results=True)

This is where the data labeling and training take place.

In the second line, you choose which features you want to use for training.

In the third line, we pass our raw data, df, as the first argument.

The second argument, feature_list=features, represents our features.

The third argument, input_bars=70, specifies the number of bars we want to input. This is our input data, which our model will use to train on. After training, we will need to input this amount of data to our model in order to make predictions.

The fourth argument, horizon=20, is the number of steps in our prediction. In our case, we will train the model to predict volatility 20 bars in advance. Since we have hourly data, we will predict 20 hours in advance.

The fifth argument, trees_count=200, is the maximum number of trees on which we will train our model. We have early_stopping=True in the first line, which means that the model will stop training if overfitting occurs, even if we set 1000 or 10000 trees.

The sixth argument, show_results=True, means that a graph will be displayed after training, showing the decrease in error on the training and validation data.

The fourth line

rez = model.forecast(df.iloc[-70:].copy(), show=True)

And finally, the fourth line. The model is already trained, and we are predicting volatility.

The first argument, df.iloc[-70:].copy(), is our input data. Our model takes 70 bars as input, as we have trained it. In this example, we are simply taking the last 70 bars from our imported data.

The second argument, show=True, displays the prediction result on the chart. If you do not want this, simply omit this argument.

rez = model.forecast(df.iloc[-70:].copy())

The prediction result will be written to the rez variable regardless of whether you want the result on the graph or not.

Saving the model

model.save("eurusd_vol_model")
# later
model.load("eurusd_vol_model")
model.forecast(df.iloc[-70:].copy(), show=True)

How to try it right now

You can run this code directly in your browser using the Jupiter Notebook

Links

The library is completely open-source (MIT). If you find a bug or want a feature, create an Issue, and I will respond quickly.

--

--

Denis Makarov
Denis Makarov

Written by Denis Makarov

Im a algotrader, software developer, startup founder.