Strategy Guide

Build, test, and optimize profitable trading strategies

1 Signal Format

RLX uses a simple signal format for trading decisions:

1
Long
Buy / Hold Long
-1
Short
Sell / Hold Short
0
Neutral
Close Position

Signal Behavior

  • • Signal 1 while short → Close short, open long
  • • Signal -1 while long → Close long, open short
  • • Signal 0 → Close any open position

2 Strategy Class

Create custom strategies by inheriting from the Strategy base class:

Python
import pandas as pd
from rlxbt import Strategy, Backtester

class RSIStrategy(Strategy):
    def __init__(self, period=14, oversold=30, overbought=70):
        super().__init__()
        self.name = "RSI Strategy"
        self.period = period
        self.oversold = oversold
        self.overbought = overbought

    def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
        # Calculate RSI
        delta = data['close'].diff()
        gain = (delta.where(delta > 0, 0)).rolling(self.period).mean()
        loss = (-delta.where(delta < 0, 0)).rolling(self.period).mean()
        rs = gain / loss
        rsi = 100 - (100 / (1 + rs))
        
        # Generate signals
        signals = pd.DataFrame(index=data.index)
        signals['signal'] = 0
        signals.loc[rsi < self.oversold, 'signal'] = 1   # Long
        signals.loc[rsi > self.overbought, 'signal'] = -1  # Short
        
        return signals

# Use the strategy
strategy = RSIStrategy(period=14, oversold=25, overbought=75)
backtester = Backtester(initial_capital=100000.0)
result = backtester.run(strategy, df)

3 Take Profit & Stop Loss

Add dynamic take-profit and stop-loss levels to your signals:

Python
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
    signals = pd.DataFrame(index=data.index)
    
    # Your signal logic...
    signals['signal'] = ...
    
    # Dynamic TP/SL based on ATR
    atr = calculate_atr(data, period=14)
    
    # 2x ATR take profit, 1x ATR stop loss
    signals['take_profit'] = data['close'] + (atr * 2)
    signals['stop_loss'] = data['close'] - atr
    
    return signals

Pro Tip: Use ATR for Dynamic Levels

ATR-based TP/SL adapts to market volatility automatically.

4 JSON Strategies (No Code)

Define strategies in JSON without writing Python code. Perfect for rapid prototyping and CI/CD pipelines.

Simple Format

btc_rsi_strategy.json
{
  "entry_long": "RSI_14 < 30",
  "exit_long": "RSI_14 > 70",
  "entry_short": "RSI_14 > 70",
  "exit_short": "RSI_14 < 30"
}

Advanced Format

institutional_strategy.json
{
  "entry_rules": [
    {
      "condition": "RSI_14 < 30 && close > SMA_200",
      "signal": "OversoldLong",
      "direction": 1
    },
    {
      "condition": "RSI_14 > 70 && close < SMA_200",
      "signal": "OverboughtShort",
      "direction": -1
    }
  ],
  "exit_rules": [
    {
      "condition": "RSI_14 > 70",
      "reason": "Overbought"
    },
    {
      "condition": "current_drawdown > 0.15",
      "reason": "PortfolioProtection"
    }
  ],
  "stop_loss_pct": 0.025,
  "take_profit_pct": 0.045,
  "max_hold_bars": 45
}

Expression Syntax

Operator Example Description
> < >= <= RSI_14 > 70Comparison
== !=position_size != 0Equality
&&RSI < 30 && MACD > 0Logical AND
||RSI > 80 || RSI < 20Logical OR
( ) (RSI < 30) && (close > SMA) Grouping

5 Multi-Strategy Portfolios

Run multiple strategies simultaneously and combine them into a diversified portfolio.

Python
from rlxbt import PortfolioManager, CapitalAllocator

# Define strategies
strategies = [
    TrendFollowingStrategy(),
    MeanReversionStrategy(),
    BreakoutStrategy()
]

# Create portfolio with risk-parity allocation
portfolio = PortfolioManager(
    initial_capital=1_000_000,
    strategies=strategies,
    allocation="risk_parity",
    rebalance_frequency="monthly"
)

# Run backtest
results = portfolio.backtest(data)

print(f"Portfolio Return: {results['total_return']:.2%}")
print(f"Sharpe Ratio: {results['sharpe_ratio']:.2f}")

Allocation Methods

equal_weight

Equal capital to each strategy

risk_parity

Inverse volatility weighting

max_sharpe

Optimize for maximum Sharpe

min_variance

Minimize portfolio variance

6 Strategy Optimization

Find optimal parameters using grid search and walk-forward analysis.

Grid Search

Python
from rlxbt import GridSearchOptimizer

optimizer = GridSearchOptimizer(metric="sharpe_ratio")

# Define parameter grid
param_grid = {
    'rsi_period': [7, 14, 21],
    'oversold': [20, 30, 40],
    'overbought': [60, 70, 80]
}

# Run optimization (27 combinations)
results = optimizer.optimize(
    strategy_class=RSIStrategy,
    param_grid=param_grid,
    data=data,
    verbose=True
)

print(f"Best params: {results['best_params']}")
print(f"Best Sharpe: {results['best_score']:.4f}")

Walk-Forward Analysis

Python
from rlxbt import WalkForwardAnalysis

wfa = WalkForwardAnalysis(
    train_size=0.7,    # 70% for training
    test_size=0.3,     # 30% for testing
    n_splits=5         # 5 walk-forward periods
)

results = wfa.run(
    strategy_class=RSIStrategy,
    param_grid=param_grid,
    data=data,
    verbose=True
)

print(f"Avg Out-Sample Return: {results['avg_out_sample_return']:.2%}")

Detect Overfitting

If in-sample performance is much better than out-sample, your strategy may be overfit to historical data.

📊 Real Optimization Results

RSI Strategy on BTCUSDT 1h (33,579 bars, 27 combinations)

RankPeriodOversoldOverboughtSharpeReturn
🥇 1740800.0084+26.19%
🥈 2740600.0060+18.42%
🥉 3740700.0058+21.35%