An end-to-end MLOps pipeline for replicating and deploying the BAVAR-BLED (Bayesian Vector Auto-Regressive Black-Litterman with Elliptical Solver) Reinforcement Learning framework for portfolio optimization. This project implements technical features, a custom gym-like portfolio environment, and a TD3 reinforcement learning agent integrated with a Black-Litterman view solver.
The framework combines statistical forecasting with reinforcement learning:
- BAVAR Ensemble: A Bayesian Vector Auto-Regressive model that generates prior asset returns and covariance distributions.
- BLEDEllipticalSolver: An elliptical Black-Litterman view solver that updates priors with view inputs.
- TD3 RL Agent: A Twin Delayed DDPG reinforcement learning agent that optimizes portfolio weight allocations using views generated by a Transformer and CNN.
├── configs/
│ └── trial_30.yaml # Experiment configurations
├── scripts/
│ ├── train_async.py # Training entrypoint
│ └── evaluate.py # Model evaluation and promotion script
├── src/
│ ├── agent/
│ │ ├── replay_buffer.py # Experience replay
│ │ └── td3.py # Actor, Critic, and TD3 Agent logic
│ ├── data/
│ │ ├── features.py # Indicators, HAR, BAVAR features (JIT optimized)
│ │ └── pipeline.py # Data ingestion and splitting (yfinance)
│ ├── enviroment/
│ │ └── portfolio_env.py # Custom portfolio gym environment
│ ├── evaluate/
│ │ └── evaluate_model.py # Model validation & stage transition logic
│ ├── models/
│ │ ├── bavar.py # Bayesian VAR forecasting ensemble
│ │ ├── bled.py # Black-Litterman elliptical solver
│ │ └── networks.py # CNN and Transformer views generators
│ ├── register/
│ │ └── register_model.py # Model version registry utility
│ └── scoring/
│ └── serve.py # REST API serving logic (FastAPI)
├── Dockerfile # Docker image for API serving
├── docker-compose.yml # Compose setup for API & MLflow
├── LICENSE # MIT License
├── parameters.json # MLOps standardized parameters
└── pyproject.toml # Poetry dependencies
Following the standards of deep_momentum, hyperparameters and metadata are separated in parameters.json:
dataset: Specifies metadata likeasset_class("equity") anduniverse_name("djia_29") to classify the dataset.features: Configures data preprocessing features (e.g.,lookback: 15).training: Houses RL and optimization hyperparameters (batch_size,actor_lr,critic_lr,episodes,num_models).registration: Defines tags to index and retrieve model versions.
The project has deep MLflow logging:
- Parameters & Metrics: Every run logs hyperparameters along with validation metrics (
sharpe_ratio,total_reward,final_portfolio_value). - Git Metadata: Every run reads local Git history and logs tags:
git_sha: Commit hash of the running code.git_branch: Current active branch.git_dirty: Flag showing whether the workspace had uncommitted changes.
- Code Packaging (
code_paths): Source code is programmatically packaged with the MLflow model artifact inside a temporary staging folder (.code_staging). This makes the logged model version entirely self-contained and importable asbavar_bled.srcduring scoring. - Model Version Card: Upon successful training, the registered model version's description is automatically updated with a markdown card documenting performance, hyperparameters, Git commit details, and validation benchmarks:
### Model Version Card
- **Trained At**: 2026-06-25T06:57:00
- **Git Commit**: 093150ee3830e97b5752546e387dcd598fab48af (Branch: main, Dirty: False)
- **Hyperparameters**: batch_size=128, episodes=20, num_models=90...
- **Data Period**: 2014-01-01 to 2024-12-31
- **Performance (Validation Set)**:
- Sharpe Ratio: 1.0000
- Total Reward: -0.1401
- Final Portfolio Value: 86923.2To train the framework on Google Colab leveraging a T4/L4 GPU:
- Enable GPU: Set Runtime -> Change runtime type -> T4 GPU in Google Colab.
- Download & Upload Project:
- Pack the project on your server:
tar -czf bavar_bled.tar.gz --exclude='./mlruns' --exclude='./.git' --exclude='__pycache__' . - Download the file and upload it to the root of your Google Drive.
- Pack the project on your server:
- Run on Colab:
Mount Google Drive and execute the training cell. Running the training script directly inside the Colab Python process allows you to inject CUDA optimizations (
cudnn.benchmark = True) and adjust parameters without modifying any source files:
import os
import sys
import torch
# 1. Add /content to PYTHONPATH to resolve local package imports
sys.path.append("/content")
os.environ["PYTHONPATH"] = "/content:" + os.environ.get("PYTHONPATH", "")
# 2. Enable CUDA kernel selection optimizations
torch.backends.cudnn.benchmark = True
# 3. CPU Thread Tuning (Colab standard VM has 2 virtual CPU cores)
os.environ["PYTHONUNBUFFERED"] = "1"
os.environ["OMP_NUM_THREADS"] = "2"
os.environ["MKL_NUM_THREADS"] = "2"
os.environ["NUMBA_NUM_THREADS"] = "2"
# 4. Set Run Parameters (Increase BATCH_SIZE to 512/1024 for GPU parallelism)
os.environ["MLFLOW_TRACKING_URI"] = "./mlruns"
os.environ["MLFLOW_EXPERIMENT_NAME"] = "bavar_bled"
os.environ["START_DATE"] = "2014-01-01"
os.environ["END_DATE"] = "2024-12-31"
os.environ["EPISODES"] = "20"
os.environ["BATCH_SIZE"] = "1024" # Scale batch size for high-throughput CUDA computation
os.environ["MLFLOW_ALLOW_FILE_STORE"] = "true"
# 5. Import and run training directly
from bavar_bled.src.training.train_mlflow import main
main()- Install dependencies:
poetry install
- Start MLflow Tracking Server:
poetry run mlflow server --host 127.0.0.1 --port 5000
- Execute training:
PYTHONPATH=. poetry run python scripts/train_async.py
- Evaluate and Promote Model:
PYTHONPATH=. poetry run python scripts/evaluate.py --run_id <RUN_ID>
This project is licensed under the MIT License - see the LICENSE file for details.