Complete hedge fund workflow with portfolio management, risk controls, and multi-strategy backtesting. This is what institutional traders use in production.
Complete institutional workflow demonstrating multi-strategy portfolio management, risk controls with VaR limits, and performance attribution.
from rlxbt import Strategy, load_data, PortfolioManager, RiskManager, GridSearchOptimizer
import pandas as pd
import numpy as np
class TrendFollowingStrategy(Strategy):
"""EMA crossover with trend filters"""
def __init__(self, fast_period=10, slow_period=20, trend_filter=50):
super().__init__()
self.fast_period = fast_period
self.slow_period = slow_period
self.trend_filter = trend_filter
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
close = data["close"]
ema_fast = close.ewm(span=self.fast_period).mean()
ema_slow = close.ewm(span=self.slow_period).mean()
target_position = pd.Series(0, index=data.index)
target_position[ema_fast > ema_slow] = 1
target_position[ema_fast < ema_slow] = -1
return pd.DataFrame({"signal": target_position}, index=data.index)
class MeanReversionStrategy(Strategy):
"""RSI-based mean reversion with Bollinger Bands"""
def __init__(self, rsi_period=14, rsi_oversold=30, rsi_overbought=70, bb_period=20):
super().__init__()
self.rsi_period = rsi_period
self.rsi_oversold = rsi_oversold
self.rsi_overbought = rsi_overbought
self.bb_period = bb_period
def calculate_rsi(self, prices):
delta = prices.diff()
gain = (delta.where(delta > 0, 0)).rolling(window=self.rsi_period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=self.rsi_period).mean()
rs = gain / loss
return 100 - (100 / (1 + rs))
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
close = data["close"]
rsi = self.calculate_rsi(close)
# Bollinger Bands
bb_middle = close.rolling(window=self.bb_period).mean()
bb_std = close.rolling(window=self.bb_period).std()
bb_lower = bb_middle - (bb_std * 2)
bb_upper = bb_middle + (bb_std * 2)
# Generate stateful signals
signals = np.zeros(len(data), dtype=int)
current_position = 0
for i in range(self.rsi_period, len(data)):
if current_position == 0:
if rsi.iloc[i] < self.rsi_oversold and close.iloc[i] <= bb_lower.iloc[i]:
current_position = 1 # Long
elif rsi.iloc[i] > self.rsi_overbought and close.iloc[i] >= bb_upper.iloc[i]:
current_position = -1 # Short
elif current_position == 1 and rsi.iloc[i] > 50:
current_position = 0 # Exit long
elif current_position == -1 and rsi.iloc[i] < 50:
current_position = 0 # Exit short
signals[i] = current_position
return pd.DataFrame({"signal": signals}, index=data.index)
class BreakoutStrategy(Strategy):
"""Volatility breakout using ATR"""
def __init__(self, lookback=20, atr_period=14, atr_multiplier=2.0):
super().__init__()
self.lookback = lookback
self.atr_period = atr_period
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
close, high, low = data["close"], data["high"], data["low"]
# ATR calculation
tr = pd.concat([
high - low,
(high - close.shift()).abs(),
(low - close.shift()).abs()
], axis=1).max(axis=1)
atr = tr.rolling(window=self.atr_period).mean()
# Breakout levels
highest_high = high.rolling(window=self.lookback).max().shift(1)
lowest_low = low.rolling(window=self.lookback).min().shift(1)
# Generate signals
signals = np.zeros(len(data), dtype=int)
current_position = 0
for i in range(self.lookback, len(data)):
if current_position == 0:
if close.iloc[i] > highest_high.iloc[i] + (atr.iloc[i] * 0.5):
current_position = 1
elif close.iloc[i] < lowest_low.iloc[i] - (atr.iloc[i] * 0.5):
current_position = -1
elif current_position == 1 and close.iloc[i] < lowest_low.iloc[i]:
current_position = 0
elif current_position == -1 and close.iloc[i] > highest_high.iloc[i]:
current_position = 0
signals[i] = current_position
return pd.DataFrame({"signal": signals}, index=data.index)def run_institutional_demo():
print("š¦ RLX INSTITUTIONAL SDK - HEDGE FUND DEMO")
# Load data
data = load_data("data/BTCUSDT_1h_with_indicators.csv")
print(f"ā
Loaded {len(data)} bars")
# Define strategies
strategies = [
TrendFollowingStrategy(fast_period=10, slow_period=30),
MeanReversionStrategy(rsi_period=14, rsi_oversold=30, rsi_overbought=70),
BreakoutStrategy(lookback=20, atr_period=14),
]
# Create portfolio
portfolio = PortfolioManager(
initial_capital=10_000_000, # $10M AUM
strategies=strategies,
allocation="equal_weight", # or 'risk_parity', 'max_sharpe'
commission=0.0,
slippage=0.0,
)
print(f"ā
Portfolio Created: ${portfolio.initial_capital:,.0f}")
# Configure risk management
risk_manager = RiskManager(
max_portfolio_var=0.02, # Max 2% Value at Risk
max_strategy_drawdown=0.10, # Max 10% drawdown per strategy
max_portfolio_drawdown=0.15, # Max 15% portfolio drawdown
max_correlation=0.70, # Max 70% correlation between strategies
var_confidence=0.95, # 95% confidence VaR
)
print(f"ā
Risk Manager: VaR {risk_manager.limits.max_portfolio_var:.1%}")
# Run backtest
print("š Running Portfolio Backtest...")
results = portfolio.backtest(data=data, risk_manager=risk_manager)
print("ā
Backtest Complete!") # Check risk limits
risk_checks = risk_manager.check_risk_limits(results)
print(risk_manager.generate_risk_report(results))
# Performance attribution
print("š Performance Attribution")
print(f"{'Strategy':<25} {'Return':<10} {'Weight':<10} {'Trades':<10} {'Win Rate':<10}")
for strategy_name, strategy_data in results["strategy_returns"].items():
print(f"{strategy_name:<25} "
f"{strategy_data['return']:>8.2%} "
f"{strategy_data['weight']:>8.2%} "
f"{strategy_data['trades']:>9} "
f"{strategy_data['win_rate']:>8.2%}")
# Final summary
print("\nš INSTITUTIONAL SUMMARY")
print(f"Total Return: {results['total_return']:>8.2%}")
print(f"Sharpe Ratio: {results['sharpe_ratio']:>8.2f}")
print(f"Max Drawdown: {results['max_drawdown']:>8.2%}")
print(f"Initial Capital: ${results['initial_capital']:>12,.0f}")
print(f"Final Capital: ${results['final_capital']:>12,.0f}")
print(f"Risk Status: {'ā
PASS' if risk_checks['all_limits_ok'] else 'ā FAIL'}")| max_portfolio_var | Maximum Value at Risk (2%) |
| max_strategy_drawdown | Per-strategy drawdown limit (10%) |
| max_portfolio_drawdown | Total portfolio drawdown (15%) |
| max_correlation | Strategy correlation limit (70%) |