MABW: Volatility Breakout Strategy¶

A systematic trend-following strategy that exploits volatility clustering by entering trends during periods of extreme compression and exiting during excessive expansion.

In [1]:
import numpy as np
import pandas as pd
import yfinance as yf
import warnings
warnings.filterwarnings('ignore')
RANDOM_SEED = 2750
np.random.seed(RANDOM_SEED)
In [2]:
import sys
from pathlib import Path

sys.path.append("systrade")
In [3]:
config_base_path = "systrade"
In [4]:
from backtester.backtest_engine import *
from backtester.data_loader import *
from backtester.visualizations import *
from backtester.utils import *
from backtester.reports import *
In [5]:
from strategies.strategy_mabw import * 
from visuals.plot_mabw_signals import *
In [6]:
# dji_components = ["MMM", "AXP", "AMGN", "AMZN", "AAPL", "BA", "CAT", "CVX", "CSCO", "KO", "DIS", "GS", "HD", "HON", "IBM", "JNJ", "JPM", "MCD", "MRK", "MSFT", "NKE", "NVDA", "PG", "CRM", "SHW", "TRV", "UNH", "VZ", "V", "WMT"]
dji_halfweight = ["GS", "MSFT", "HD", "V", "SHW", "CAT", "MCD", "UNH", "AXP"] #account for 50% of weighting
In [7]:
# Download market data
tickers = dji_halfweight

Walk-Forward Analysis and Sensitivity Analysis¶

In [8]:
from backtester.walkforward_cv import *
In [9]:
set_random_seed(RANDOM_SEED)
data_dict = download_multiple(tickers,start_date='2017-04-01', end_date='2023-01-01')
Downloading data for 9 tickers...
  GS...  1448 bars
  MSFT...  1448 bars
  HD...  1448 bars
  V...  1448 bars
  SHW...  1448 bars
  CAT...  1448 bars
  MCD...  1448 bars
  UNH...  1448 bars
  AXP...  1448 bars
Successfully downloaded 9/9 tickers

In [10]:
trade_config = TradeConfig(
    initial_capital=300_000,
    position_size_pct=0.05,
    commission_pct=0.001,
    slippage_pct=0.0005,
    slippage_fixed=0.0,
    max_trade_size=30_000,        
    min_trade_size=10_000
)

wf_config = create_wf_config(
    training_days=252*2,
    testing_days=21*9,
    holdout_days=21*6,
    min_trades=30,
    n_trials=200,
    n_startup_trials = 50,
    n_jobs=-1,
    timeout=3600,
    random_seed=2570
)
In [11]:
def get_mabw_param_space() -> dict:
   
    return {
        # Core MABW Parameters
        'fast_period': ('int', 5, 50),           # Fast MA
        'slow_period': ('int', 50, 100),         # Slow MA
        'multiplier': ('float', 0.5, 2.0),       # Band multiplier
        
        # Signal Parameters
        'ema_period': ('int', 10, 80),           # EMA signal
        'mabw_llv_period': ('int', 5, 50),       # LLV lookback
        'mab_width_critical': ('int', 20, 60),   # Width exit
        
        # Risk Management
        'atr_period': ('int', 10, 30),           # ATR period
        'atr_multiplier': ('float', 1.5, 4.0)    # ATR multiplier
    }

param_space = get_mabw_param_space()
In [12]:
param_space = get_mabw_param_space()


results_df, sensitivity_df = run_walkforward(
    data_dict=data_dict,
    param_space=param_space,
    strategy_class=MABWStrategy,
    strategy_name="MABWStrategy",
    trade_config=trade_config,
    wf_config=wf_config,
    objective_weights=(0.35, 0.65),  # 35% win rate, 65% Sharpe
    verbose=True
)
[I 2026-01-15 11:56:14,643] A new study created in memory with name: MABWStrategy_global_cv
Global Walk-Forward: 3 windows from 2017-04-03 to 2022-12-30

Running Global Optimization on 3 windows...
Warning: forcing n_jobs=1 to ensure strict reproducibility.
Global Optimization Complete. Best Score: -999.0000
{'fast_period': 35, 'slow_period': 70, 'multiplier': 0.8635188801456073, 'ema_period': 37, 'mabw_llv_period': 15, 'mab_width_critical': 20, 'atr_period': 11, 'atr_multiplier': 2.8947422562204568}
Warning: Error calculating metrics: 'action'
Warning: Error calculating metrics: 'action'
Warning: Error calculating metrics: 'action'
Warning: Error calculating metrics: 'action'
Warning: Error calculating metrics: 'action'
Warning: Error calculating metrics: 'action'

--- Degradation Analysis ---
Avg Sharpe Degradation: 100.00% (Lower is better)
  < 10%: Very Robust
  > 50%: High Overfitting

--- Parameter Stability (Cluster Analysis) ---
            parameter     cv  range_ratio assessment
1         slow_period  0.197        0.671   Moderate
7      atr_multiplier  0.230        0.797   Moderate
5  mab_width_critical  0.333        1.000       Poor
6          atr_period  0.335        1.026       Poor
2          multiplier  0.359        1.266       Poor
0         fast_period  0.478        1.525       Poor
3          ema_period  0.468        1.619       Poor
4     mabw_llv_period  0.547        1.787       Poor

--- Parameter Importance ---
            parameter  importance
0         slow_period         0.0
1          multiplier         0.0
2     mabw_llv_period         0.0
3  mab_width_critical         0.0
4         fast_period         0.0
No description has been provided for this image
Results saved to wf_method2_results

Backtest on Holdout Dataset¶

In [13]:
start_date = '2023-01-01'
raw_data = download_multiple(tickers, start_date)
Downloading data for 9 tickers...
  GS...  761 bars
  MSFT...  761 bars
  HD...  761 bars
  V...  761 bars
  SHW...  761 bars
  CAT...  761 bars
  MCD...  761 bars
  UNH...  761 bars
  AXP...  761 bars
Successfully downloaded 9/9 tickers

In [14]:
# Load configurations
strategy_config, trade_config, full_config = load_configs(
    f'{config_base_path}/configs/mabw_strategy.yaml',
    f'{config_base_path}/configs/default_settings.yaml'
)
In [15]:
strategy_config
Out[15]:
StrategyConfig(name='MABW', parameters={'fast_period': 10, 'slow_period': 60, 'multiplier': 1.0, 'ema_period': 20, 'atr_period': 14, 'atr_multiplier': 3.0, 'mabw_llv_period': 10, 'mab_width_critical': 30})
In [16]:
trade_config
Out[16]:
TradeConfig(initial_capital=100000, commission_pct=0.001, slippage_pct=0.0005, slippage_fixed=0.01, position_size_pct=0.95, max_trade_size=50000, min_trade_size=100)
In [17]:
trade_config.initial_capital = 300_000
trade_config.max_trade_size = 30_000
trade_config.min_trade_size = 10_000
In [18]:
trade_config
Out[18]:
TradeConfig(initial_capital=300000, commission_pct=0.001, slippage_pct=0.0005, slippage_fixed=0.01, position_size_pct=0.95, max_trade_size=30000, min_trade_size=10000)
In [27]:
strategy_config.parameters = {'fast_period': 35, 'slow_period': 70, 'multiplier': 0.8635188801456073, 'ema_period': 37, 'mabw_llv_period': 15, 'mab_width_critical': 20, 'atr_period': 11, 'atr_multiplier': 2.8947422562204568}
In [28]:
aligned_data = align_data(raw_data)

print(f" Downloaded data for {len(tickers)} tickers")
if len(aligned_data) > 0:
    first_ticker = list(aligned_data.keys())[0]
    date_range = f"{aligned_data[first_ticker].index[0]} to {aligned_data[first_ticker].index[-1]}"
    print(f"   Date range: {date_range}")
    print(f"   Total bars per ticker: {len(aligned_data[first_ticker])}")
 Downloaded data for 9 tickers
   Date range: 2023-01-03 00:00:00 to 2026-01-14 00:00:00
   Total bars per ticker: 761
In [29]:
# Initialize strategy
print("\n Initializing strategy...")
strategy = MABWStrategy(strategy_config)

# Validate configuration
if not strategy.validate_config():
    print(" Invalid configuration!")
 Initializing strategy...
In [30]:
# Run backtest
print("\n Running backtest...")
engine = BacktestEngine(strategy, trade_config)
results = engine.run(aligned_data)

# Print results
print_performance_summary(results.metrics)
 Running backtest...

================================================================================
PERFORMANCE SUMMARY
================================================================================

*** RETURNS ***
  Initial Capital:    $  300,000.00
  Final Value:        $  387,560.93
  Total P&L:          $   87,560.93
  Total Return:              29.19%

*** RISK METRICS ***
  Sharpe Ratio:               0.92
  Sortino Ratio:              1.06
  Max Drawdown:             -14.43%
  Calmar Ratio:               2.02
  Annual Volatility:          9.77%

*** TRADE STATISTICS ***
  Total Trades:                  9
  Win Rate:                  77.78%
  Profit Factor:              6.97
  Expectancy:         $     9695.19
  Best Trade:         $    38553.80
  Worst Trade:        $   -13133.59
  Average Trade:      $     9695.19

*** COSTS ***
  Total Commission:   $        0.00
  Total Slippage:     $        0.00
  Total Costs:        $        0.00

================================================================================

In [31]:
plot_performance_dashboard(results.portfolio_state, trade_config.initial_capital)
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
In [32]:
# Prepare data with indicators (SAVE THIS!)
prepared_data = {}
for ticker, df in aligned_data.items():
    prepared = strategy.prepare_data(df)
    prepared['ticker'] = ticker
    prepared_data[ticker] = prepared
In [33]:
plot_mabw_signals(
    data=prepared_data['UNH'],
    ticker='UNH',
    results=results,
    start_date='2023-01-01',
    end_date='2025-12-31',
    strategy_config=strategy_config
)
================================================================================
MABW STRATEGY SIGNALS FOR UNH
Period: 2023-01-01 to 2025-12-31
================================================================================
No description has been provided for this image
MABW Strategy Statistics for UNH:
--------------------------------------------------------------------------------
  Total Entry Signals: 2
  Total Exit Signals: 1

  Trade Performance:
    Total P&L: $-13,133.59
    Wins: 0 | Losses: 1
    Win Rate: 0.0%
    Avg Loss: $-13,133.59
================================================================================
In [34]:
for ticker in prepared_data.keys():
    plot_mabw_signals(
        data=prepared_data[ticker],
        ticker=ticker,
        results=results,
        start_date='2023-01-01',
        end_date='2025-12-31',
        strategy_config=strategy_config
    )
================================================================================
MABW STRATEGY SIGNALS FOR GS
Period: 2023-01-01 to 2025-12-31
================================================================================
No description has been provided for this image
MABW Strategy Statistics for GS:
--------------------------------------------------------------------------------
  Total Entry Signals: 1
  Total Exit Signals: 0
================================================================================

================================================================================
MABW STRATEGY SIGNALS FOR MSFT
Period: 2023-01-01 to 2025-12-31
================================================================================
No description has been provided for this image
MABW Strategy Statistics for MSFT:
--------------------------------------------------------------------------------
  Total Entry Signals: 1
  Total Exit Signals: 0
================================================================================

================================================================================
MABW STRATEGY SIGNALS FOR HD
Period: 2023-01-01 to 2025-12-31
================================================================================
No description has been provided for this image
MABW Strategy Statistics for HD:
--------------------------------------------------------------------------------
  Total Entry Signals: 1
  Total Exit Signals: 0
================================================================================

================================================================================
MABW STRATEGY SIGNALS FOR V
Period: 2023-01-01 to 2025-12-31
================================================================================
No description has been provided for this image
MABW Strategy Statistics for V:
--------------------------------------------------------------------------------
  Total Entry Signals: 1
  Total Exit Signals: 0
================================================================================

================================================================================
MABW STRATEGY SIGNALS FOR SHW
Period: 2023-01-01 to 2025-12-31
================================================================================
No description has been provided for this image
MABW Strategy Statistics for SHW:
--------------------------------------------------------------------------------
  Total Entry Signals: 0
  Total Exit Signals: 0
================================================================================

================================================================================
MABW STRATEGY SIGNALS FOR CAT
Period: 2023-01-01 to 2025-12-31
================================================================================
No description has been provided for this image
MABW Strategy Statistics for CAT:
--------------------------------------------------------------------------------
  Total Entry Signals: 1
  Total Exit Signals: 0
================================================================================

================================================================================
MABW STRATEGY SIGNALS FOR MCD
Period: 2023-01-01 to 2025-12-31
================================================================================
No description has been provided for this image
MABW Strategy Statistics for MCD:
--------------------------------------------------------------------------------
  Total Entry Signals: 1
  Total Exit Signals: 0
================================================================================

================================================================================
MABW STRATEGY SIGNALS FOR UNH
Period: 2023-01-01 to 2025-12-31
================================================================================
No description has been provided for this image
MABW Strategy Statistics for UNH:
--------------------------------------------------------------------------------
  Total Entry Signals: 2
  Total Exit Signals: 1

  Trade Performance:
    Total P&L: $-13,133.59
    Wins: 0 | Losses: 1
    Win Rate: 0.0%
    Avg Loss: $-13,133.59
================================================================================

================================================================================
MABW STRATEGY SIGNALS FOR AXP
Period: 2023-01-01 to 2025-12-31
================================================================================
No description has been provided for this image
MABW Strategy Statistics for AXP:
--------------------------------------------------------------------------------
  Total Entry Signals: 1
  Total Exit Signals: 0
================================================================================