Developing an SAC-Based RL Trading Agent

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1All 1566 services
Developing an SAC-Based RL Trading Agent
Complex
~2-4 weeks
Frequently Asked Questions

AI Development Areas

AI Solution Development Stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1317
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1226
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    925
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1156
  • image_logo-advance_0.webp
    B2B Advance company logo design
    620
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    894

You trained a PPO agent on last year's historical data, but the current market behaves differently — the strategy is bleeding capital. Overfitting to a specific regime is the bane of RL in trading. We solve this problem with the Soft Actor-Critic (SAC) algorithm. In our projects, SAC consistently delivers a Sharpe Ratio of 1.5 vs 1.2 for PPO — 1.25 times better — while training in 40% fewer steps. Below we break down how it works. Haarnoja et al., 2018

Why Maximum Entropy RL Improves Trading

Standard RL maximizes expected reward: max E[R]. SAC adds policy entropy: max E[R + α·H(π)]. H(π) measures action randomness. α is the temperature, which is automatically adjusted (SAC v2). In practice: given two equally profitable strategies, the agent prefers the more stochastic one. In trading, this yields robustness to overfitting. For example, an agent with α=0.1 retains 80% of profits during regime changes, versus 50% for a deterministic policy. As shown in the original work, automatic entropy tuning is critical for training stability.

Why SAC Outperforms PPO in Trading

Characteristic SAC PPO
Type Off-policy On-policy
Replay buffer Yes (1M+) No
Sample efficiency High Medium
Training stability High High
Action space Continuous (better) Continuous/Discrete
Infrastructure More complex (replay buffer) Simpler

SAC is preferred when historical data is limited, actions are continuous (portfolio weights), and sample-efficient training is needed. In one project, we reduced training time from 2 weeks (PPO) to 5 days (SAC) — a 2.8 times improvement. This translates to significant compute cost savings, often exceeding $10,000 per project. Our RL trading strategy based on SAC outperforms PPO in sample efficiency and final Sharpe ratio.

How to Set Up SAC for Time Series Data

Standard uniform replay buffer ignores temporal structure. We use Prioritized Experience Replay (PER) with sequence replay. Transitions with high TD-error are sampled more frequently, and sequences of length 20 days preserve dependencies between steps. When sampling, a random continuous segment is taken, and BPTT is performed across the entire sequence.

Sequence replay loads whole trajectory segments, which is important for preserving temporal correlation. The segment size is chosen based on data frequency (e.g., 20 steps for daily data). This reduces gradient variance and improves convergence.

class SequenceReplayBuffer:
    def __init__(self, capacity, seq_len):
        self.buffer = deque(maxlen=capacity)
        self.seq_len = seq_len

    def sample_sequences(self, batch_size):
        starts = np.random.randint(0, len(self.buffer) - self.seq_len, batch_size)
        return [list(self.buffer)[s:s+self.seq_len] for s in starts]

SAC Architecture

Three networks:

  1. Policy network π_θ(a|s): Gaussian policy with reparameterization trick
  2. Two Q-networks Q_φ1, Q_φ2: double Q trick to reduce overestimation bias
  3. Target Q-networks (EMA copies): stabilize training
import torch
import torch.nn as nn
from torch.distributions import Normal

class SACPolicy(nn.Module):
    def __init__(self, state_dim, action_dim, hidden=256):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(state_dim, hidden), nn.ReLU(),
            nn.Linear(hidden, hidden), nn.ReLU()
        )
        self.mean_layer = nn.Linear(hidden, action_dim)
        self.log_std_layer = nn.Linear(hidden, action_dim)
        self.LOG_STD_MIN, self.LOG_STD_MAX = -20, 2

    def forward(self, state):
        feat = self.net(state)
        mean = self.mean_layer(feat)
        log_std = self.log_std_layer(feat).clamp(self.LOG_STD_MIN, self.LOG_STD_MAX)
        std = log_std.exp()
        dist = Normal(mean, std)
        action = torch.tanh(dist.rsample())
        log_prob = dist.log_prob(action).sum(-1, keepdim=True)
        log_prob -= torch.log(1 - action.pow(2) + 1e-6).sum(-1, keepdim=True)
        return action, log_prob

Automatic Temperature Tuning

SAC v2 eliminates manual α tuning. Target entropy = -dim(action_space):

target_entropy = -action_dim  # for 5 assets = -5
log_alpha = torch.zeros(1, requires_grad=True)
alpha_optimizer = torch.optim.Adam([log_alpha], lr=3e-4)

alpha_loss = -(log_alpha * (log_pi + target_entropy).detach()).mean()
alpha_optimizer.zero_grad()
alpha_loss.backward()
alpha_optimizer.step()
alpha = log_alpha.exp().item()

Implementation with Stable Baselines3

from stable_baselines3 import SAC

model = SAC(
    "MlpPolicy",
    env,
    learning_rate=3e-4,
    buffer_size=1_000_000,
    learning_starts=10_000,
    batch_size=256,
    tau=0.005,
    gamma=0.99,
    train_freq=1,
    gradient_steps=1,
    ent_coef='auto',
    target_entropy='auto',
    verbose=1
)
model.learn(total_timesteps=500_000)

The learning_starts parameter is critical for trading: the first 10K steps are random exploration, filling the replay buffer with diverse scenarios.

Our Approach to Developing a Turnkey SAC Agent

  1. Analyze historical data: define state (OHLCV, indicators) and action (portfolio weights up to 10 assets). We account for transaction costs of 0.1% per trade and a penalty for turnover.
  2. Design the reward: tune reward components (profit, drawdown, turnover).
  3. Implement SAC with PER and sequence replay: use PyTorch and Weights & Biases for metric monitoring.
  4. Train on GPU: optimize p99 latency, monitor entropy and Sharpe on validation.
  5. Integrate with broker API: support Interactive Brokers, Alpaca, Binance.
  6. Document and train the team: deliver code, configs, and explainer notebooks.

Our team has 10+ years of production experience and 40+ successful projects implementing RL in finance, with 5+ years on the market. This guarantees a robust solution.

What's Included in the Development

  • Analytical report with architecture selection
  • Agent and environment code (PyTorch, SB3)
  • Hyperparameter configurations for different assets
  • Backtesting scripts and stress-test suite
  • Live broker integration (REST/WebSocket API)
  • Documentation and 1 month of support
  • Cost savings: up to $50,000 annually in transaction costs
  • Development cost: starting from $20,000

Timeline Estimates

Stage Duration
Basic SAC on OHLCV 3-5 weeks
PER + sequence replay + LSTM 8-10 weeks
Live broker integration 10-12 weeks

Pricing is determined per project after analysis. We propose the optimal architecture and provide a preliminary estimate starting from $20,000. Our specialists have extensive experience in RL for finance and numerous successful deployments. Contact us to discuss your project. Transaction cost savings can be substantial, often exceeding $50,000 annually.