Price Relative — the ratio of column to benchmark, bar by bar:
${output} = column / benchmark
Appends one column, with no period and no warm-up: it is the only
study in the package that reads a single row, so every row emits (bar 0
included) wherever both inputs exist. A rising line means column is
outperforming, falling means the benchmark is — the level is arbitrary
(it carries the two instruments' price units), which is why the line is
read for its slope and why performanceIndex exists to normalise it
against a starting point.
ChartIQ lists this under two names — Price Relative and Relative
Strength (comparative) — and they are one implementation, which is what
ships here under the unambiguous name. Neither is Wilder's Relative
Strength Index: rsi is a single-series momentum oscillator
bounded 0..100, this is an unbounded two-series ratio, and the collision
of names is the single most common confusion in the corpus. If you want
RSI, call rsi.
The comparison series is a COLUMN, not a second TimeSeries
See correlation's docstring for the reasoning (aligning two bar
clocks is align/joinMany's job, not a study's). A missing benchmark
column throws.
Edges
No TA-Lib function, so the oracle is a pandas replication, with the
inverted ratio (benchmark / column) measured as the separation — the
one substitution that leaves the curve's shape recognisable and every
value wrong.
A zero benchmark reads undefined, and the guard is LIVE. Unlike
the flat-window cases in correlation and beta, the
numerator here is not forced to zero with the denominator, so
5 / 0 is Infinity — and withColumn throws on a non-finite value
rather than recording it as a gap. The guard sits at the study's
output, which is what makes it observable (the #703 rule: a guard
upstream of a window kernel is absorbed and dies; one at the output is
load-bearing). Unreachable on prices, reachable when benchmark is
another study's output that crosses zero, and unit-tested there. A
negative benchmark still produces a number — === 0, not <= 0,
the percentChangeValues rule, because a ratio against a negative
level is defined if unusual and clamping it would invent a rule.
Scale-EQUIVARIANT, not invariant. Multiplying column by k
multiplies the reading by k; multiplying benchmark by k divides it
by k. Both are pinned as property tests, as identities rather than as
"the numbers changed" — this is the one study in the family that is not
scale-invariant, and a test that asserted invariance would have passed
on a study that had normalised the ratio away.
A missing cell in either column blanks that row and nothing else —
a window kernel's recovery rule with a window of one.
benchmark must differ from column: the ratio would be 1
everywhere.
Price Relative — the ratio of
columntobenchmark, bar by bar:Appends one column, with no period and no warm-up: it is the only study in the package that reads a single row, so every row emits (bar
0included) wherever both inputs exist. A rising line meanscolumnis outperforming, falling means the benchmark is — the level is arbitrary (it carries the two instruments' price units), which is why the line is read for its slope and why performanceIndex exists to normalise it against a starting point."Relative Strength" here is not rsi
ChartIQ lists this under two names — Price Relative and Relative Strength (comparative) — and they are one implementation, which is what ships here under the unambiguous name. Neither is Wilder's Relative Strength Index: rsi is a single-series momentum oscillator bounded
0..100, this is an unbounded two-series ratio, and the collision of names is the single most common confusion in the corpus. If you want RSI, call rsi.The comparison series is a COLUMN, not a second
TimeSeriesJoin the benchmark in first and name its column:
See correlation's docstring for the reasoning (aligning two bar clocks is
align/joinMany's job, not a study's). A missingbenchmarkcolumn throws.Edges
benchmark / column) measured as the separation — the one substitution that leaves the curve's shape recognisable and every value wrong.benchmarkreadsundefined, and the guard is LIVE. Unlike the flat-window cases in correlation and beta, the numerator here is not forced to zero with the denominator, so5 / 0isInfinity— andwithColumnthrows on a non-finite value rather than recording it as a gap. The guard sits at the study's output, which is what makes it observable (the #703 rule: a guard upstream of a window kernel is absorbed and dies; one at the output is load-bearing). Unreachable on prices, reachable whenbenchmarkis another study's output that crosses zero, and unit-tested there. A negative benchmark still produces a number —=== 0, not<= 0, the percentChangeValues rule, because a ratio against a negative level is defined if unusual and clamping it would invent a rule.columnbykmultiplies the reading byk; multiplyingbenchmarkbykdivides it byk. Both are pinned as property tests, as identities rather than as "the numbers changed" — this is the one study in the family that is not scale-invariant, and a test that asserted invariance would have passed on a study that had normalised the ratio away.benchmarkmust differ fromcolumn: the ratio would be1everywhere.