AlphaNova
Back to Blog
How to Train a Deep Reinforcement Learning Agent for Asset Allocation with Stable-Baselines3

How to Train a Deep Reinforcement Learning Agent for Asset Allocation with Stable-Baselines3

Dominik Keller
September 11, 2026

Deep Reinforcement Learning for Asset Allocation: A Stable-Baselines3 Tutorial

Deep reinforcement learning (RL) is fundamentally changing how we approach sequential decision problems in finance. At its core, an RL agent learns optimal actions through trial and error: it interacts with an environment, receives feedback in the form of rewards, and gradually discovers a policy that maximises cumulative return. This is the same paradigm that has mastered complex games like chess and Go, and it maps naturally onto portfolio management, where every allocation decision influences future wealth.

The promise is immense, but the field has also faced a well‑documented reproducibility crisis. Landmark studies by Henderson et al. (2018) and Engstrom et al. (2020) revealed that even minor implementation details—random seeds, network initialisation, or environment wrappers—can lead to wildly different performance rankings among algorithms. For quantitative researchers, this means that using an ad‑hoc, self‑coded RL pipeline can silently introduce biases, making it nearly impossible to determine whether a strategy truly works or is merely an artefact of a fragile codebase. Reliable implementations are no longer a luxury; they are essential.

Why Stable-Baselines3 for Financial RL?

Stable‑Baselines3 (SB3) is the open‑source framework that directly addresses this reproducibility challenge. Presented in a JMLR paper (Raffin et al., 2021), SB3 provides a set of state‑of‑the‑art, model‑free RL algorithms that are fully benchmarked, extensively documented, and rigorously tested. The GitHub repository has grown to nearly 14,000 stars, reflecting strong community trust.

Benchmarked, Tested, and Documented

SB3 ships with an automated test suite that covers over 95% of its code. Every algorithm is benchmarked against reference implementations and published results, so you can be confident that the performance you observe is robust and replicable. The documentation includes practical guides, API references, and concrete examples that lower the barrier to entry for non‑specialists.

A Consistent Interface for Seven Model-Free Algorithms

One of SB3’s most powerful design choices is its unified API. Whether you want to use Proximal Policy Optimization (PPO), Advantage Actor‑Critic (A2C), Deep Q‑Networks (DQN), or Soft Actor‑Critic (SAC), the pattern is identical: instantiate a model, call model.learn(), and then model.predict(). Because the environments all conform to the Gymnasium interface, swapping algorithms for an asset allocation task is as simple as changing one line of code. This consistency makes it straightforward to run controlled experiments and identify which algorithm best suits a given market dynamic.

From Research to Industry: Adoption and Community

SB3 is used in academic research and within quantitative teams at financial institutions. Its goal is not to push the frontier of algorithm design but to provide reliable baselines that allow researchers and practitioners to isolate the effect of their innovations—be it a novel reward function or a custom observation space. When you build on SB3, you inherit a foundation that has already been stress‑tested by thousands of users.

Building a Custom Asset Allocation Environment with Gymnasium

Before an agent can learn, it needs a realistic simulation to interact with. Gymnasium (the maintained fork of OpenAI Gym) defines a standard protocol for environments, and any trading simulator must inherit from its Env class.

Inheriting from gymnasium.Env

Start by subclassing gymnasium.Env. You will need to implement four key methods: __init__, reset, step, and render (optional for training). The __init__ method loads your historical price data and calculates any necessary features, ensuring that the environment knows how many assets it will trade.

Defining the Observation Space

Observations encode everything the agent sees at each time step. In an asset allocation task, this typically includes lagged returns, volatility estimates, correlation proxies, and the current portfolio weights. The space is often a Box of shape (n_features,) so that the agent receives a flat feature vector. For example, you might concatenate the 20‑day rolling Sharpe ratios of each asset with the current allocation percentages. All features should be normalised (e.g., using z‑scores) to help the neural network learn.

Specifying the Action Space

The action space represents the portfolio weights the agent chooses. You can make it discrete—allowing only a fixed set of allocation combinations, such as "all in asset A"—or continuous, where each element of the action vector lies in a range (e.g., Box(0, 1, shape=(n_assets,))). In the continuous case, apply a softmax or a normalisation step inside the step method to ensure the weights sum to 1 and stay within bounds. Actions that violate constraints can be clipped, but be mindful that clipping introduces a mismatch between the action the agent sampled and the action that was executed.

Crafting a Risk-Adjusted Reward Function

The reward signal is the compass that guides learning. For asset allocation, a common choice is the Sharpe ratio computed on a sliding window of returns. After each step, the environment calculates the portfolio return as the dot product of the new weights and the asset returns for that period. Using a window (e.g., the last 20 steps), it then computes the annualised Sharpe ratio: the mean excess return over the risk‑free rate divided by the standard deviation of returns, scaled by √252 if daily data is used. For more details on this calculation, see our guide on how to compute the Sharpe ratio from a pandas Series of returns. An alternative is the Sortino ratio, which penalises only downside volatility. The reward is the risk‑adjusted metric itself; the agent’s goal becomes maximising this number episode after episode.

Training an RL Agent to Allocate Assets

Once the environment is built and validated, training with SB3 is remarkably concise.

Instantiating and Configuring the PPO Algorithm

PPO has emerged as a robust on‑policy algorithm that balances sample efficiency and ease of tuning. With SB3, you create a model like this:

from stable_baselines3 import PPO

model = PPO(
    "MlpPolicy",
    env,
    verbose=1,
    learning_rate=3e-4,
    n_steps=2048,
    batch_size=64,
    tensorboard_log="./ppo_asset_alloc_tensorboard/"
)

The "MlpPolicy" tells SB3 to use a feed‑forward neural network (you can swap in a "CnnPolicy" or a custom policy if needed). The environment already defines the observation and action spaces, so SB3 automatically sizes the network appropriately. Most hyper‑parameters are left at sensible defaults.

The Training Loop: Interacting with the Environment

The entire training loop reduces to a single method call:

model.learn(total_timesteps=100_000)

Under the hood, SB3 collects rollouts by running the current policy on the environment, computes advantages, and updates the policy network in mini‑batches. The heavy lifting—policy gradient estimation, clip‑range scheduling, and value‑function optimisation—is handled by the library. You remain free to experiment with the environment’s reward function or observation space without touching the algorithm’s internals.

Logging and Monitoring Progress

During training, SB3 can log episode rewards, value losses, and other metrics to TensorBoard. Watching the rolling average of the reward (e.g., the portfolio Sharpe ratio) climb over time provides a first sanity check. However, never rely solely on in‑sample performance. The real test lies ahead.

Evaluating RL Trading Strategies Out-of-Sample

A policy that performs brilliantly on the data it was trained on is worthless if it crumbles under new market conditions.

Out-of-Sample Backtesting

Run the trained agent on a separate historical period that was not used during training. Use model.predict(observation, deterministic=True) to obtain the action at each step. Compute the out‑of‑sample Sharpe ratio, maximum drawdown, and any other metric that captures the risk‑return profile you care about. Compare the agent’s equity curve against a simple equal‑weight benchmark. If the out‑of‑sample Sharpe ratio is significantly positive and the drawdown is acceptable, you have a candidate strategy.

Beyond the Sharpe Ratio: Robustness Checks

Sharpe ratios can be gamed, especially when returns are non‑normal. Supplement your analysis with skewness, kurtosis, and rolling performance windows. Most importantly, test across different market regimes. A strategy that thrives in a low‑volatility bull market may collapse in a turbulent bear market. These robustness checks mirror the philosophy behind the walk‑forward test—the only backtest that truly matters for assessing whether a signal will survive out‑of‑sample.

One crucial lesson from RL research: small implementation details matter enormously. Because SB3 provides a standardised, tested pipeline, you can attribute differences in backtest performance to your environment design and feature engineering rather than to hidden bugs in the RL algorithm.

From Sandbox to Production: The AlphaNova Challenge

Training an agent in a local sandbox is one thing; testing it against a diverse market universe under rigorous out‑of‑sample conditions is quite another. AlphaNova provides exactly that platform.

Walk-Forward, Cross-Sectional Signal Forecasting

AlphaNova hosts walk‑forward, cross‑sectional signal forecasting competitions. You receive obfuscated financial data—tabular, with multiple assets per period—and submit a pure Python Predictor class. Your code does not execute trades directly; it outputs a signal for each asset, and AlphaNova’s infrastructure translates that signal into a portfolio, evaluating it strictly out‑of‑sample using the Sharpe ratio. This design ensures that only genuinely uncorrelated, overfit‑filtered signals count toward the prize pools.

Prizes, Profit Sharing, and IP Ownership

Cash prizes are paid in stablecoins or directly to a bank account. There is no staking, no token volatility—performance alone determines earnings. Prize pools scale with participation, and the top‑performing signals may earn ongoing profit sharing. You retain full intellectual property. Competitions are free to enter, and a local runner is provided so you can test your Predictor before submission.

How to Participate

The workflow is straightforward: download the local runner, develop and debug your Predictor, then submit it to the platform. Your signal will be evaluated on data it has never seen, in a walk‑forward fashion that prevents the look‑ahead bias that plagues many backtests. If you have already built a custom Gymnasium environment and trained an RL agent using SB3, adapting your logic into a Predictor class is a natural progression.

Conclusion and Next Steps

Combining custom Gymnasium environments with Stable‑Baselines3 gives you a powerful, reproducible research framework for asset allocation and beyond. SB3’s rigorous benchmarks, consistent API, and extensive documentation let you focus on what matters: designing informative observation spaces and reward functions that capture genuine market inefficiencies. As you continue experimenting, explore the SB3 documentation and its GitHub repository for more advanced features like custom callbacks, her replay buffers, and quantile regression DQN.

Once you are satisfied with your local results, the logical next step is to test your models in a realistic, institutional‑grade setting. Join the latest AlphaNova competition and see whether your RL‑driven predictions can deliver consistent out‑of‑sample performance. It’s free to enter, your intellectual property remains yours, and your signal’s Sharpe ratio is the only currency that matters.

How to Train a Deep Reinforcement Learning Agent for Asset Allocation with Stable-Baselines3 | AlphaNova Blog