---
title: "Aesera"
description: "Learn how to create, train, and evaluate machine learning models in the research environment in QuantConnect with Aesera library."
canonical: https://www.quantconnect.com/docs/v2/research-environment/machine-learning/popular-libraries/aesera
markdown: https://www.quantconnect.com/docs/v2/research-environment/machine-learning/popular-libraries/aesera.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/04%20Research%20Environment/08%20Machine%20Learning/03%20Popular%20Libraries/01%20Aesera
modified: 2026-11-01
index: https://www.quantconnect.com/llms.txt
---

# Aesera

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Research Environment](https://www.quantconnect.com/docs/v2/research-environment.md) > Machine Learning > [Popular Libraries](https://www.quantconnect.com/docs/v2/research-environment/machine-learning/popular-libraries.md) > Aesera

> Code examples are shown in Python. Append `?lang=csharp` to this URL for the C# version of this page.

## Introduction

This page explains how to build, train, test, and store `aesara` models.

> To access Aesara, use the Legacy package environment. To set this environment, see the documentation in [Cloud Platform](https://www.quantconnect.com/docs/v2/cloud-platform/projects/package-environments.md#02-Set-Environment) or [Local Platform](https://www.quantconnect.com/docs/v2/local-platform/development-environment/packages-and-libraries.md#02-Set-Environment).

## Import Libraries

Import the `aesara` and `sklearn` libraries.

```python
import aesara
import aesara.tensor as at
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
import joblib
```

You need the `joblib` library to store models.

## Get Historical Data

[Get some historical market data](https://www.quantconnect.com/docs/v2/research-environment/datasets/us-equity.md#04-Get-Historical-Data) to train and test the model. For example, to get data for the SPY ETF during 2020 and 2021, run:

```python
qb = QuantBook()
symbol = qb.add_equity("SPY", Resolution.DAILY).symbol
history = qb.history(symbol, datetime(2020, 1, 1), datetime(2022, 1, 1)).loc[symbol]
```

## Prepare Data

You need some [historical data](https://www.quantconnect.com/docs/v2/research-environment/machine-learning/popular-libraries/aesera.md#03-Get-Historical-Data) to prepare the data for the model. If you have historical data, manipulate it to train and test the model. In this example, use the following features and labels:

| Data Category | Description |
| --- | --- |
| Features | Normalized close price of the SPY over the last 5 days |
| Labels | Return direction of the SPY over the next day |

The following image shows the time difference between the features and labels:

![Features and labels for training](https://cdn.quantconnect.com/i/tu/ml-keras-function.png)

Follow these steps to prepare the data:

1. Loop through the `close` Series and collect the features.
   ```python
   lookback = 5
   lookback_series = []
   for i in range(1, lookback + 1):
       df = history['close'].shift(i)[lookback:-1]
       df.name = f"close-{i}"
       lookback_series.append(df)
   X = pd.concat(lookback_series, axis=1)
   # Normalize using the 5 day interval
   X = MinMaxScaler().fit_transform(X.T).T[4:]
   ```
2. Obtain the close price and return direction series.
   ```python
   close = history['close']
   returns = history['close'].pct_change().shift(-1)[lookback*2-1:-1].reset_index(drop=True)
   labels = pd.Series([1 if y > 0 else 0 for y in returns])   # binary class
   ```
3. Convert the lists of features and labels into `numpy` arrays.
   ```python
   X = np.array(X)
   y = np.array(labels)
   ```
4. Split the data into training and testing periods.
   ```python
   X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
   ```

## Train Models

You need to [prepare the historical data](https://www.quantconnect.com/docs/v2/research-environment/machine-learning/popular-libraries/aesera.md#04-Prepare-Data) for training before you train the model. If you have prepared the data, build and train the model. In this example, build a Logistic Regression model with log loss cross entropy and square error as cost function. Follow these steps to create the model:

1. Generate a dataset.
   ```python
   # D = (input_values, target_class)
   D = (np.array(X_train), np.array(y_train))
   ```
2. Initialize variables.
   ```python
   # Declare Aesara symbolic variables
   x = at.dmatrix("x")
   y = at.dvector("y")

   # initialize the weight vector w randomly using share so model coefficients keep their values
   # between training iterations (updates)
   rng = np.random.default_rng(100)
   w = aesara.shared(rng.standard_normal(X.shape[1]), name="w")

   # initialize the bias term
   b = aesara.shared(0., name="b")
   ```
3. Construct the model graph.
   ```python
   # Construct Aesara expression graph
   p_1 = 1 / (1 + at.exp(-at.dot(x, w) - b))       # Logistic transformation
   prediction = p_1 > 0.5                          # The prediction thresholded
   xent = y * at.log(p_1) - (1 - y) * at.log(1 - p_1)  # Cross-entropy log-loss function
   cost = xent.mean() + 0.01 * (w ** 2).sum()      # The cost to minimize (MSE)
   gw, gb = at.grad(cost, [w, b])                  # Compute the gradient of the cost
   ```
4. Compile the model.
   ```python
   train = aesara.function(
             inputs=[x, y],
             outputs=[prediction, xent],
             updates=((w, w - 0.1 * gw), (b, b - 0.1 * gb)))
   predict = aesara.function(inputs=[x], outputs=prediction)
   ```
5. Train the model with the training dataset.
   ```python
   pred, err = train(D[0], D[1])

   # Inspect the final outcome
   print("Final model:")
   print(w.get_value())
   print(b.get_value())
   print("target values for D:")
   print(D[1])
   print("prediction on D:")
   print(predict(D[0]))    # whether > 0.5 or not
   ```
   ![Aesera model's training summary](https://cdn.quantconnect.com/i/tu/aesera-model.png)

## Test Models

You need to [build and train the model](https://www.quantconnect.com/docs/v2/research-environment/machine-learning/popular-libraries/aesera.md#05-Train-Models) before you test its performance. If you have trained the model, test it on the out-of-sample data. Follow these steps to test the model:

1. Call the `predict` method with the features of the testing period.
   ```python
   y_hat = predict(np.array(X_test))
   ```
2. Plot the actual and predicted labels of the testing period.
   ```python
   df = pd.DataFrame({'y': y_test, 'y_hat': y_hat}).astype(int)
   df.plot(title='Model Performance: predicted vs actual return direction in closing price', figsize=(12, 5))
   ```
3. Calculate the prediction accuracy.
   ```python
   correct = sum([1 if x==y else 0 for x, y in zip(y_test, y_hat)])
   print(f"Accuracy: {correct}/{y_test.shape[0]} ({correct/y_test.shape[0]}%)")
   ```

![Aesera model's performance](https://cdn.quantconnect.com/i/tu/aesera-model-performance-2.png)

## Store Models

You can save and load `aesara` models using the Object Store.

### Save Models

Follow these steps to save models in the Object Store:

1. Set the key name of the model to be stored in the Object Store.
   ```python
   model_key = "model"
   ```
2. Call the `get_file_path` method with the key.
   ```python
   file_name = qb.object_store.get_file_path(model_key)
   ```
   This method returns the file path where the model will be stored.
3. Call the `dump` method with the model and file path.
   ```python
   joblib.dump(predict, file_name)
   ```
   If you dump the model using the `joblib` module before you save the model, you don't need to retrain the model.

### Load Models

You must save a model into the Object Store before you can load it from the Object Store. If you saved a model, follow these steps to load it:

1. Call the `contains_key` method with the model key.
   ```python
   qb.object_store.contains_key(model_key)
   ```
   This method returns a boolean that represents if the `model_key` is in the Object Store. If the Object Store does not contain the `model_key`, save the model using the `model_key` before you proceed.
2. Call the `get_file_path` method with the key.
   ```python
   file_name = qb.object_store.get_file_path(model_key)
   ```
   This method returns the path where the model is stored.
3. Call the `load` method with the file path.
   ```python
   loaded_model = joblib.load(file_name)
   ```
   This method returns the saved model.

## Examples

The following examples demonstrate some common practices for using the aesara library.

### Example 1: Predict Return Direction

The following research notebook uses an `aesara` machine learning model to predict the next day's return direction by the previous 5 days' close price differences.

```python
# Import the aesara library and others.
import aesara
import aesara.tensor as at
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
import joblib

# Instantiate the QuantBook for researching.
qb = QuantBook()
# Request the daily SPY history with the date range to be studied.
symbol = qb.add_equity("SPY", Resolution.DAILY).symbol
history = qb.history(symbol, datetime(2020, 1, 1), datetime(2022, 1, 1)).loc[symbol]

# Use 1- to 5-day differences as the input features.
lookback = 5
lookback_series = []
for i in range(1, lookback + 1):
    df = history['close'].shift(i)[lookback:-1]
    df.name = f"close-{i}"
    lookback_series.append(df)
X = pd.concat(lookback_series, axis=1)
# Normalize using the 5 day interval.
X = MinMaxScaler().fit_transform(X.T).T[4:]

# Use the close price series to generate the labels.
close = history['close']
# Get the 1-day forward return direction as the labels.
returns = history['close'].pct_change().shift(-1)[lookback*2-1:-1].reset_index(drop=True)
labels = pd.Series([1 if y > 0 else 0 for y in returns])   # binary class

# Split the data into a training set and test set for validation.
X = np.array(X)
y = np.array(labels)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# Create a dataset.
D = (np.array(X_train), np.array(y_train))

# Declare Aesara symbolic variables.
x = at.dmatrix("x")
y = at.dvector("y")

# Initialize the weight vector w randomly using share so model coefficients keep their values
# between training iterations (updates).
rng = np.random.default_rng(100)
w = aesara.shared(rng.standard_normal(X.shape[1]), name="w")

# Initialize the bias term.
b = aesara.shared(0., name="b")

# Construct an Aesara expression graph.
p_1 = 1 / (1 + at.exp(-at.dot(x, w) - b))       # Logistic transformation
prediction = p_1 > 0.5                          # The prediction thresholded
xent = y * at.log(p_1) - (1 - y) * at.log(1 - p_1)  # Cross-entropy log-loss function
cost = xent.mean() + 0.01 * (w ** 2).sum()      # The cost to minimize (MSE)
gw, gb = at.grad(cost, [w, b])                  # Compute the gradient of the cost

# Compile the model. In this example, set the step size as 0.1 times gradients.
train = aesara.function(
          inputs=[x, y],
          outputs=[prediction, xent],
          updates=((w, w - 0.1 * gw), (b, b - 0.1 * gb)))
predict = aesara.function(inputs=[x], outputs=prediction)

# Train the model with the training dataset.
pred, err = train(D[0], D[1])

# Inspect the final outcome.
print("Final model:")
print(w.get_value())
print(b.get_value())
print("target values for D:")
print(D[1])
print("prediction on D:")
print(predict(D[0]))    # whether > 0.5 or not

# Predict the label of the testing set data.
y_hat = predict(np.array(X_test))

# Plot and calculate the accuracy of the predicted testing set labels.
df = pd.DataFrame({'y': y_test, 'y_hat': y_hat}).astype(int)
df.plot(title='Model Performance: predicted vs actual return direction in closing price', figsize=(12, 5))
correct = sum([1 if x==y else 0 for x, y in zip(y_test, y_hat)])
print(f"Accuracy: {correct}/{y_test.shape[0]} ({correct/y_test.shape[0]}%)")

# Store the model in the object store to allow accessing the model in the next research session or in the algorithm for trading.
model_key = "model"
file_name = qb.object_store.get_file_path(model_key)
joblib.dump(predict, file_name)
```
