Simple moving average strategy to get started with RLX Backtester. This is the foundation for understanding the SDK.
A complete working example showing how to create a simple moving average crossover strategy, run a backtest, and print results. This example demonstrates the Strategy class pattern.
#!/usr/bin/env python3
"""
Simple test of RLXBT SDK
Note: This example requires either:
1. Development build with `--features offline_license` (no license required)
2. Production build with valid license key (set RLX_LICENSE_KEY env var or pass to Backtester)
Get your license at https://rlxbt.com/pricing
"""
import sys
import os
import pandas as pd
import numpy as np
from rlxbt import Strategy, Backtester, load_data
class SimpleMAStrategy(Strategy):
"""Simple Moving Average Crossover Strategy"""
def __init__(self, fast_period=10, slow_period=20):
super().__init__()
self.fast_period = fast_period
self.slow_period = slow_period
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
close = data["close"]
# Calculate indicators
fast_ma = close.rolling(window=self.fast_period).mean()
slow_ma = close.rolling(window=self.slow_period).mean()
# Generate signals
signals = np.zeros(len(data), dtype=int)
# Long when fast > slow
signals[fast_ma > slow_ma] = 1
# Short when fast < slow
signals[fast_ma < slow_ma] = -1
df = pd.DataFrame(index=data.index)
df["signal"] = signals
return df
def run_test():
print("š Running Simple Test")
# Check for license key (optional in dev builds)
license_key = os.environ.get("RLX_LICENSE_KEY")
if license_key:
print(f"š Using license key: {license_key[:20]}...")
else:
print("ā¹ļø No license key set (OK for development builds)")
# Load data
data_path = "data/BTCUSDT_1h_with_indicators.csv"
data = load_data(data_path)
print(f"š Loaded {len(data)} bars")
# Create strategy
strategy = SimpleMAStrategy(fast_period=10, slow_period=20)
# Create backtester
backtester = Backtester(
initial_capital=10000.0,
license_key=license_key,
)
# Run backtest
results = backtester.run(strategy, data)
# Print results
print("\nš Results:")
print(f"Total Return: {results['total_return']:.2%}")
print(f"Sharpe Ratio: {results['sharpe_ratio']:.2f}")
print(f"Max Drawdown: {results['max_drawdown']:.2%}")
print(f"Total Trades: {results['total_trades']}")
print(f"Win Rate: {results['win_rate']:.2%}")
if __name__ == "__main__":
run_test()generate_signals()class MAWithStops(Strategy):
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
close = data["close"]
fast_ma = close.rolling(10).mean()
slow_ma = close.rolling(20).mean()
df = pd.DataFrame(index=data.index)
df["signal"] = np.where(fast_ma > slow_ma, 1,
np.where(fast_ma < slow_ma, -1, 0))
# Add dynamic stop loss and take profit
df["stop_loss"] = np.where(
df["signal"] == 1,
close * 0.98, # 2% below for longs
close * 1.02 # 2% above for shorts
)
df["take_profit"] = np.where(
df["signal"] == 1,
close * 1.04, # 4% above for longs
close * 0.96 # 4% below for shorts
)
return dfFor more control, use the Rust engine directly:
from rlxbt import rlx, load_data
# Load and prepare data
data = load_data("data/BTCUSDT_1h.csv")
data["signal"] = 0
data.loc[data["SMA_20"] > data["SMA_50"], "signal"] = 1
data.loc[data["SMA_20"] < data["SMA_50"], "signal"] = -1
# Create Rust engine directly
engine = rlx.TradingEngine(
initial_capital=100_000.0,
commission=0.001,
slippage=0.0005,
contract_size=1.0,
enable_dynamic_tp_sl=False,
)
# Run with signal column
result = engine.run_with_signals(data, "signal")
print(f"Total Return: {result.total_return * 100:.2f}%")
print(f"Trades: {len(result.trades)}")