Files
OpenBB/openbb_platform/extensions/technical/docs/user-guides/03-multi-symbol.md
Danglewood d3d33a219b [V5] openbb-technical: Refactor for V5 & Add More Quick Win Endpoints (#7502)
* refactor openbb-technical for v5

* forward refs

* linting

* no python 3.15 in test matrix

* reame

* ty

* move all params to body

---------

Co-authored-by: deeleeramone <>
2026-05-29 10:48:51 +03:00

5.0 KiB
Vendored

Multi-Symbol Analysis

Five endpoints take a long-format multi-symbol price series (one DataFrame with a symbol column) and produce cross-sectional or relative-strength output.

Example input shape:

import pandas as pd

df = pd.read_csv("dow30.csv")          # columns: date, symbol, open, high, low, close, volume
print(df.head())
#         date open    high    low    close   volume    symbol
# 0 2024-01-02 187.15  188.44  183.89 185.64  82488700  AAPL
# 1 2024-01-02 376.04  376.04  370.66 370.87  25258600  MSFT
# ...

data = df.to_dict(orient="records")

Correlation (paired)

Returns the rolling Pearson, Spearman, or Kendall correlation of returns for specific symbol pairs.

result = obb.technical.correlation(
    data=data,
    pairs=[("AAPL", "MSFT"), ("AAPL", "NVDA"), ("NVDA", "MSFT")],
    window=60,
    method="pearson",
).to_df()

Output is a long-format frame with one row per (symbol_a, symbol_b, date) tuple. With window=None, returns the single full-sample correlation per pair.

Correlation Matrix (snapshot)

Builds a single point-in-time correlation matrix across every symbol in the input.

result = obb.technical.correlation_matrix(
    data=data,
    window=60,                       # rolling window ending at as_of_date
    method="spearman",
    as_of_date="2024-06-28",         # None = most recent date in input
).results[0]
print(result.symbols)                # ['AAPL', 'AMZN', 'MSFT', ...]
print(result.matrix)                 # nested list, indexed by symbols order

Screen

Filters a universe by indicator-driven predicates. Each condition specifies an indicator endpoint, the column to read, an operator, and a threshold.

matches = obb.technical.screen(
    data=data,
    conditions=[
        {
            "indicator": "rsi",
            "column": "close_RSI_14",
            "operator": "lt",
            "value": 30.0,
        },
        {
            "indicator": "sma",
            "column": "close_SMA_50",
            "operator": "gt",
            "value": 0.0,
        },
    ],
    combine="and",                   # "or" for union semantics
    as_of_date="2024-06-28",         # None = each symbol's latest bar
).results

Supported operators:

Operator value shape Fires when
gt, gte, lt, lte, eq scalar latest value matches
between (low, high) low <= latest <= high
crossed_above, crossed_below (threshold, lookback) series crosses the threshold within the trailing lookback bars
made_high, made_low (0, lookback) latest is the max/min over the trailing lookback bars

Each matched row carries the symbol, the as-of date used, how many conditions fired, and the indicator values at the trigger.

Relative Rotation Graph

Computes the JdK RS-Ratio (relative-strength level) and RS-Momentum (relative-strength rate of change) for every constituent against a benchmark. Used to locate symbols in one of four rotational quadrants.

# The benchmark symbol must be present in `data`. The canonical RRG setup is
# the benchmark (e.g. an index ETF) plus the constituents you want to rotate
# against it. If you load Dow 30 OHLCV, append SPY rows to `data` before this
# call, or pick one of the constituents as the benchmark.
rrg = obb.technical.relative_rotation(
    data=data,
    benchmark="AAPL",                # any symbol present in `data`
    study="price",                   # or "volume", "volatility"
    long_period=252,                 # RS-Ratio standardisation window
    short_period=21,                 # RS-Momentum standardisation window
    window=21,                       # trail length retained in the output
    trading_periods=252,             # used by the volatility study
)

rrg.results.rs_ratios               # one frame per symbol, indexed by date
rrg.results.rs_momentum             # same shape
rrg.results.benchmark               # echoed for charting

Quadrant interpretation (x = RS-Ratio, y = RS-Momentum, both centred at 100):

RS-Ratio RS-Momentum Quadrant Interpretation
> 100 > 100 Leading Outperforming and accelerating
> 100 < 100 Weakening Still outperforming but momentum is fading
< 100 < 100 Lagging Underperforming with negative momentum
< 100 > 100 Improving Underperforming but momentum is turning up

Symbols rotate clockwise through the quadrants over time. The window=21 trail draws the rotation arc on a chart.

Input format constraints

  • symbol column required. All multi-symbol endpoints group by it.
  • Long format only. Each row is one (symbol, date) observation. Don't pre-pivot.
  • Daily data is the default assumption for relative_rotation. It requires at least long_period + window bars per symbol (default ~273 daily bars). The volatility study needs roughly twice as much.
  • Identical date grids preferred. Symbols whose date series don't fully overlap will be intersected pairwise; the correlation/RRG endpoints work on the intersection.