Skip to main content
Range-based models in Systematica implement trading strategies that identify price ranges within specific time periods and generate signals based on price behavior relative to these ranges. These models use time-based grouping rather than rolling windows, making them fundamentally different from other model types in the framework.

Overview and Architecture

Range-based models operate by dividing time series data into discrete temporal groups (e.g., daily, weekly periods) and defining trading ranges using a subset of each period. The framework provides two complementary strategies:
  • Range Breakout: Trend-following strategy that trades breakouts above/below established ranges
  • Range Mean Reversion: Counter-trend strategy that trades reversals at range boundaries

Core Concepts: Time-Based Grouping vs Rolling Windows

Range-based models use vbt.Splitter.from_grouper to create discrete time periods, contrasting with rolling window approaches used by other models:
AspectRange-Based ModelsRolling Window Models
Grouping Methodsplitter.from_groupersplitter.from_rolling
Period DefinitionFixed time periods (daily, weekly)Sliding windows (N bars)
Range CalculationFirst portion of each periodContinuous moving calculation
Signal ResetResets each periodContinuous evolution

RangeBreakout

RangeBreakout(
    splitter: str = 'from_grouper',
    custom_splitter: str = None,
    custom_splitter_kwargs: Dict[str, Any] = None,
    training_window: str | float = '2h',
    by: str = 'D',
    freq: str = 'auto',
    start_time: str = None,
    end_time: str = '23:00',
    tol: float = 0.5,
)
The RangeBreakout class implements trend-following breakout strategies by detecting when prices break above or below established ranges. Range breakout model implementation using splitter.from_grouper. This model identifies trading ranges during specific time periods and generates signals when price breaks above or below these ranges. Unlike rolling window models, this uses time-based grouping (e.g., daily, weekly) to define ranges. Notes: Parameter Requirements:
  • training_window: Must be a string in time format (e.g., “2h”, “4h”) or a float representing a fraction of the by period. Integer values are NOT supported and will cause errors during cross-validation.
  • When using with Optuna optimization, define training_window as:
>>> training_window = sma.Categorical(
...     "training_window", 
...     choices=["1h", "2h", "4h", "6h", "8h", "12h"]
... )
Signal Model Compatibility: This model outputs discrete position values (-1, 0, 1) and works with the “crossover” signal model. For successful signal generation:
  • Set long_entries < 1.0 (e.g., 0.9) so signals cross the threshold
  • Set short_entries > -1.0 (e.g., -0.9) so signals cross the threshold
  • Exit thresholds should be within (-0.5, 0.5) for optimal results
Common Issues and Solutions:
  1. Integer training_window causes “Must provide at least one range” error
     >>> # WRONG - Integer hours not supported
     >>> model = RangeBreakout(training_window=24)  
     >>> # CORRECT - Use string format
     >>> model = RangeBreakout(training_window="24h")
     >>> # CORRECT - Use fraction of period
     >>> model = RangeBreakout(training_window=0.5)  # 50% of the day
    
  2. All Optuna trials pruned with NaN metrics
     >>> # WRONG - Thresholds at extremes prevent crossovers
     >>> signal_params = {
     ...     "long_entries": 1.0,   # Model output reaches but never crosses 1.0
     ...     "short_entries": -1.0  # Model output reaches but never crosses -1.0
     ... }
     >>> # CORRECT - Thresholds within output range allow crossovers
     >>> signal_params = {
     ...     "long_entries": 0.9,   # Crossover happens when output goes from <0.9 to >0.9
     ...     "short_entries": -0.9, # Crossover happens when output goes from >-0.9 to <-0.9
     ...     "long_exits": 0.1,
     ...     "short_exits": -0.1
     ... }
    
Examples: Basic usage with string training window:
>>> model = RangeBreakout(
...     by="1d",
...     training_window="2h",  # First 2 hours of each day
...     start_time="1:00",
...     end_time="21:00",
...     tol=0.1
... )
>>> output = model(data, "BTCUSDT", "ETHUSDT")
Optuna optimization setup:
>>> study = RangeBreakout.run_optuna_study(
...     data, "BTCUSDT", "ETHUSDT",
...     by="D",
...     training_window=sma.Categorical("training_window", choices=["2h", "4h", "6h"]),
...     signal_model='crossover',
...     long_entries=sma.Float("long_entries", low=0.5, high=0.95),
...     short_entries=sma.Float("short_entries", low=-0.95, high=-0.5),
...     metrics="sharpe_ratio",
...     n_trials=100
... )
See Also:
  • systematica.signals.Crossover : Signal model used with this indicator
  • examples/scripts/models/range_breakout/example_range_breakout.py : Complete example
Method generated by attrs for class RangeBreakout.

Ancestors

  • systematica.models.base.BaseStatArb
  • abc.ABC

Static methods

apply_between_time

apply_between_time(
    data: vectorbtpro.data.base.Data,
    start_time: str,
    end_time: str,
    **kwargs,
) ‑> vectorbtpro.data.base.Data
Helper function to clean data using pandas between_time. More information in the Pandas Documentation Parameters:
NameTypeDefaultDescription
datavbt.Data--Input data containing time series data.
start_timedatetime.time--Initial time as a time filter limit.
end_timedatetime.time--End time as a time filter limit.
kwargstp.Kwargs--Additional keyword arguments for between_time.
Returns:
TypeDescription
vbt.DataSlice data object.

Instance variables

  • by: str: Split data temporarily. Defaults to D for daily.
  • custom_splitter: str: Custom splitter function, if provided. Defaults to None.
  • custom_splitter_kwargs: Dict[str, Any]: Additional arguments for the custom splitter. Defaults to None.
  • end_time: str: End time as a time filter limit. If None, no processing is done. Defaults to 00:00.
  • freq: str: Frequency of the index (e.g., daily, 15 min, index_mean). Infer or convert the frequency for a datetime index. If freq is None, the frequency is inferred using parse_index_freq. If a string is provided: If auto, the frequency is detected with auto_detect_freq. If the string starts with index_, the corresponding method (obtained after stripping the prefix) is applied to the differences between consecutive index values. If freq_from_n is an integer (positive or negative), the index is limited to the first or last N elements respectively. Defaults to auto.
  • splitter: str: Splitter method for cross-validation, by default from_grouper.
  • start_time: str: Initial time as a time filter limit. If None, no processing is done. Defaults to None.
  • tol: float: Range tolerance to trigger a long/short signal such as trigger = tol * range_values. Defaults to 0.5.
  • training_window: str | float: Specification for further splitting of each range. The split size of the training window used in splitter.from_grouper. It could be a float (e.i. 0.5, which split each range in half) or a string (e.i. 4h or 4 hours. which takes the first 4 hours of the range). Defaults to 2h (2 hours).

Methods

check_training_window

check_training_window(
    self,
    attribute: Type,
    value: Any,
)
Validate training_window. Parameters:
NameTypeDefaultDescription
attributetp.Type--The attribute being validated.
valuetp.Any--The model instance.
Raises:
TypeDescription
ValueErrorIf the training window size is greater than the temporal parameter by.

plot_model_output

plot_model_output(
    self,
    data: vectorbtpro.data.base.Data,
    symbol: str,
    use_close: bool = True,
    **layout_kwargs,
) ‑> vectorbtpro.utils.figure.FigureWidget
Plot range breakout. Parameters:
NameTypeDefaultDescription
datavbt.Data--A data object containing asset prices and other relevant information.
symbolstr--The asset symbol to plot.
use_closeboolTrueUse close price if set to True. Otherwise, use open price.
layout_kwargstp.Kwargs--Additional layout arguments for the figure.
Returns:
TypeDescription
vbt.FigureWidgetA Plotly FigureWidget containing range breakout model.

plot_signals

plot_signals(
    self,
    data: vectorbtpro.data.base.Data,
    symbol: str,
    use_close: bool = True,
    **layout_kwargs,
) ‑> vectorbtpro.utils.figure.FigureWidget
Plot range breakout. Parameters:
NameTypeDefaultDescription
datavbt.Data--A data object containing asset prices and other relevant information.
symbolstr--The asset symbol to plot.
use_closeboolTrueUse close price if set to True. Otherwise, use open price.
layout_kwargstp.Kwargs--Additional layout arguments for the figure.
Returns:
TypeDescription
vbt.FigureWidgetA Plotly FigureWidget containing range breakout model.