1. Portfolio Rebalancing on the Probability Simplex

Let $\mathbf{w}_t \in \Delta^N$ be the portfolio allocation vector across $N$ assets satisfying $\sum w_{i,t} = 1$ and $w_{i,t} \ge 0$. Jiang et al. (2017) formulated continuous portfolio rebalancing as a deterministic policy gradient over historical price tensors.


2. Wealth Compounding & Proportional Transaction Costs

Let $\mathbf{y}_t$ be the asset return vector. Wealth updates as:

$$W_{t+1} = W_t \cdot \left[ \mathbf{w}_t \cdot \mathbf{y}_t - c \sum_{i=1}^N \left| w_{i,t} - w_{i,t-1}' \right| \right]$$
import torch
import torch.nn as nn
import torch.nn.functional as F

class SimplexPortfolioPolicyNet(nn.Module):
    """
    Continuous-control portfolio policy outputting allocation weights on unit simplex.
    """
    def __init__(self, n_assets: int = 10, hidden_dim: int = 64):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(n_assets * 5, hidden_dim),
            nn.LayerNorm(hidden_dim),
            nn.SiLU(),
            nn.Linear(hidden_dim, n_assets)
        )

    def forward(self, state: torch.Tensor) -> torch.Tensor:
        logits = self.net(state)
        # Softmax enforces non-negative budget sum to 1.0
        return F.softmax(logits, dim=-1)

3. Institutional Summary

  • Softmax Simplex Output: Always pass network logits through a Softmax layer to guarantee valid portfolio weights.