deepdow

repository·master·Indexed 22 days ago

https://github.com/jankrepl/deepdow

A Python framework that connects portfolio optimization with deep learning by creating fully differentiable pipelines. Built on torch, deepdow allows researchers to optimize market forecasting and weight allocation simultaneously in a single forward pass. It integrates cvxpylayers for differentiable convex optimization and provides various loss functions, such as Sharpe ratio and maximum drawdown, to evaluate predicted weights against future market evolution.

Tokens
12.5K
Snippets
27
Records
54
Agent score
78%

What's inside deepdow

  1. What is DeepDow?

    master

    DeepDow is a framework designed for portfolio optimization using end-to-end deep learning. Unlike traditional two-stage optimization methods, DeepDow focuses on constructing networks that perform weight allocation in a single forward pass.

    Instead of separating predictive modeling (estimating returns and covariance) from optimization (solving a convex problem), DeepDow merges these steps. The network takes raw features (such as returns and volumes) as input and directly outputs asset allocations. This allows for:

    • Using a single loss function for the entire process.
    • Turning hyperparameters (like risk aversion coefficients) into trainable weights.
    • Extracting features specifically optimized for allocation rather than just prediction.
  2. Key features of deepdow

    master

    The deepdow framework provides several capabilities for research and implementation:

    • Differentiable Layers: All layers are built on torch and are fully differentiable.
    • Convex Optimization: Integrates cvxpylayers for differentiable convex optimization.
    • Portfolio Algorithms: Implements clustering-based portfolio allocation algorithms.
    • Data Loading: Provides multiple strategies including RigidDataLoader and FlexibleDataLoader.
    • Experiment Tracking: Integrates with mlflow and tensorboard via callbacks.
    • Loss Functions: Provides various loss functions such as Sharpe ratio and maximum drawdown.
    • Hardware Support: Supports both CPU and GPU.
  3. Overview of deepdow architecture

    master

    deepdow (read as "wow") is a Python framework that merges market forecasting with portfolio optimization into a single, fully differentiable pipeline.

    Instead of treating forecasting (e.g., LSTM, GARCH) and optimization (e.g., convex optimization) as separate steps, deepdow constructs a pipeline of layers where the final layer performs the weight allocation and preceding layers act as feature extractors. Because the entire network is built on torch, the parameters can be optimized end-to-end using gradient descent.

    Key Constraints:

    • Buy and Hold: It is designed for finding allocations to be held over a specific horizon, not for active trading strategies. Consequently, frequent transaction costs are not the primary focus.
    • Not Reinforcement Learning: While layers can be reused in RL applications, deepdow itself is not a reinforcement learning framework.
  4. How RigidDataLoader works

    master

    The RigidDataLoader is a subclass of torch.utils.data.DataLoader designed for evaluation or scenarios where the temporal and asset dimensions must remain constant across batches.

    Key Characteristics:

    • The lookback, horizon, and assets are constant across different batches.
    • Samples are shuffled.
    • Batch Shapes:
      • X_batch.shape: (batch_size, n_channels, lookback, n_assets)
      • y_batch.shape: (batch_size, n_channels, horizon, n_assets)
      • len(timestamps_batch): batch_size
      • len(asset_names_batch): n_assets

    Usage Tip: Use this for evaluation to ensure the horizon in y_batch is identical for every batch, ensuring consistent portfolio holding periods.

    from deepdow.data import RigidDataLoader
    
    # Assuming 'dataset' is an InRAMDataset instance
    dataloader = RigidDataLoader(dataset, batch_size=4)
    
    for X_batch, y_batch, timestamps_batch, asset_names_batch in dataloader:
        # X_batch and y_batch will have constant shapes
        pass
  5. How rolling window data decomposition works

    master

    To prepare data for training, deepdow uses a rolling window method to decompose a large time series tensor into three disjoint subtensors at any given time step (representing "now"):

    • x (Features): Represents past and present knowledge. Shape: (n_channels, lookback, n_assets).
    • g (Gap): Represents information in the immediate future that cannot be used for investment decisions. Shape: (n_channels, gap, n_assets).
    • y (Labels): Represents the future evolution of the market. Shape: (n_channels, horizon, n_assets).

    By rolling this window across the time dimension, you generate a collection of feature tensors (x1, x2, ...) and corresponding label tensors (y1, y2, ...).

  6. Implement custom Callbacks

    master

    Callbacks allow you to execute code at specific lifecycle stages of the training loop. To create a custom callback, inherit from deepdow.callbacks.Callback and override one or more of the following methods:

    • on_batch_begin: At the start of each batch.
    • on_batch_end: At the end of each batch.
    • on_epoch_begin: At the start of each epoch.
    • on_epoch_end: At the end of each epoch.
    • on_train_begin: At the start of the training.
    • on_train_end: At the end of the training.
    • on_train_interrupt: When training is interrupted.

    Each method receives a metadata dictionary containing the most recent values of relevant variables. Additionally, the callback instance can access the active Run instance via the .run attribute, which is injected during the launch process.

  7. Understand the difference between Networks and Simple Benchmarks

    master

    In deepdow, benchmarks are algorithms that map an input feature tensor x to a weights tensor. They are categorized into two types:

    1. Networks: Benchmarks with learnable parameters. Their allocation algorithm must be a differentiable forward pass implemented using torch functions, modules, or deepdow.layers.
    2. Simple Benchmarks: Benchmarks without learnable parameters. These serve as baselines and do not change predictions over different epochs. Because they are not trainable, their allocation algorithms do not need to be differentiable; you can cast the input torch.Tensor to a numpy array and use external libraries like scipy.

    Use Simple Benchmarks to establish a performance baseline before training a network.

  8. Understand the prediction pipeline and weight allocation

    master

    The goal of a deepdow network is to take the feature tensor x as input and return a single weight allocation vector w of shape (n_assets,).

    Key constraints and behaviors:

    • Sum to One: The weights must satisfy $\sum_{i} w_{i} = 1$.
    • Portfolio Construction: The weights w represent a portfolio that is purchased immediately and held for the duration of the horizon time steps.
    • Pipeline: The neural network $F$ with parameters $\theta$ maps $x \to w$.
  9. Understand the data structure in deepdow

    master

    In deepdow, financial time series are represented as a 3D tensor with three dimensions:

    1. time: The temporal dimension (e.g., daily frequency).
    2. asset: The dimension representing different financial instruments (e.g., multiple stocks).
    3. indicator/channel: The dimension representing different features or data streams (e.g., open price returns, close price returns, and volumes).

    A tensor shape is denoted as (n_channels, n_timesteps, n_assets). For example, a shape of (3, 10, 6) implies 3 channels, 10 timesteps, and 6 assets.

  10. Use Resample as a metallocator for bootstrapping

    master

    The Resample layer is a metallocator that applies parametric bootstrapping to reduce noise in $\boldsymbol{\mu}$ and $\boldsymbol{\Sigma}$ estimates. It wraps a base allocator and performs the following:

    1. Samples n_portfolios * n_draws new vectors from $\mathcal{N}(\boldsymbol{\mu}, \boldsymbol{\Sigma})$.
    2. Runs the base allocator for each pair of sampled $\boldsymbol{\mu}_i$ and $\boldsymbol{\Sigma}_i$.
    3. Averages the resulting allocations to produce the final weight vector.

    Supported Base Allocators:

    • AnalyticalMarkowitz
    • NCO
    • NumericalMarkowitz
  11. Core assumptions in deepdow

    master

    When using deepdow, keep the following architectural assumptions in mind:

    • Contiguous Time: The time dimension is assumed to be contiguous with a single, consistent frequency (e.g., daily).
    • Hold Strategy: Predicted weights w are treated as an investment that is held constant over the specified horizon time steps.
  12. How FlexibleDataLoader works

    master

    The FlexibleDataLoader is designed for training models that can handle variable input shapes (e.g., RNNs). It introduces structural changes to batches by randomly sampling dimensions from specified ranges.

    Key Features:

    • lookback_range: A tuple (min, max) specifying the range for the lookback dimension. The actual lookback is sampled uniformly for every batch.
    • horizon_range: A tuple (min, max) specifying the range for the horizon dimension. The actual horizon is sampled uniformly for every batch.
    • n_assets_range: If asset_ixs is not specified, this tuple (min, max) specifies the range for the number of assets in the batch. Assets are sampled randomly.

    Warning: Do not use FlexibleDataLoader with models that flatten inputs into a 1D vector (like a simple Linear layer) or models that rely on fixed asset ordering, as the variable shapes and random asset shuffling will break the model's ability to learn specific features.

    from deepdow.data import FlexibleDataLoader
    
    dataloader = FlexibleDataLoader(
        dataset, 
        batch_size=4, 
        n_assets_range=(2, 3), 
        lookback_range=(2, 6), 
        horizon_range=(2, 5)
    )
    
    for X_batch, y_batch, timestamps_batch, asset_names_batch in dataloader:
        # X_batch and y_batch shapes will vary per batch
        pass