Appends one column that oscillates around 1: 1.05 is five percent
of out-performance accumulated over the window, 0.95 five percent of
under-performance, 1 exact parity. undefined for the first period
rows — the look-back reads a bar, not a window, so the warm-up is
period and not period − 1 (percentChange's rule).
It is priceRelative with the arbitrary level divided out: the raw
ratio's height depends on the two instruments' price units and says
nothing, while this asks the only question a level can answer — relative
to period bars ago.
Which "Performance Index" — F-AMBIG, and the fork is named
The corpus (docs/notes/financial-indicators-assessment-2026-07.md §6.7)
carries this from a vendor study menu with the note "normalized relative
performance", and more than one thing ships under the name:
What ships here is the LOOK-BACK form above — each side's own
period-bar growth, divided. It is exactly the missing member of this
family: (perf − 1) × 100 is percentChange(priceRelative, period)identically (the benchmark terms cancel), which is asserted by a
test, so the study adds a name and a normalisation rather than new math.
A moving-average form is published under the same name — Trading
Technologies gives PI = (close / benchmark) × (MA(benchmark) / MA(close)), i.e. the price relative measured against a smoothed
baseline rather than a lagged one
(https://library.tradingtechnologies.com/trade/chrt-ti-performance-index.html).
That variant is not shipped because it is already a composition of
two shipped primitives — priceRelative and a moving average —
whereas the look-back form is the one this family lacked. If you want
it: sma each side, then two priceRelative calls and a ratio.
The scaling is a presentation fork. Some vendors publish × 100
(100 = parity) or − 1 / (x − 1) × 100 (0 = parity). The ratio
ships, matching priceRelative beside it, so the two lines in this
family read on the same kind of axis; the percent form is one
subtraction away and is spelled out above.
The comparison series is a COLUMN, not a second TimeSeries
Join the benchmark in first and name its column — see
correlation's docstring for the recipe and the reasoning. A
missing benchmark column throws.
Edges
No TA-Lib function, so the oracle is a pandas replication at
period 20 and 5, with the analytic first valid bar (period) asserted
and a measured separation from the difference form
(colGrowth − benchGrowth), the substitution that keeps the curve's
shape and moves every value.
Three zero guards, all LIVE, because all three divisions are the
study's own last steps and withColumn throws on a non-finite value
rather than recording it as a gap: a zero column[i−period]
(x/0 = Infinity), a zero benchmark[i] (the benchmark's growth is
Infinity, so the reading would be 0) and a zero
benchmark[i−period] (the benchmark's growth is 0, so the reading
would be Infinity). Each has its own unit test. As in
percentChangeValues the test is === 0, not <= 0 — a ratio
against a negative level is defined if unusual.
Invariant to an independent SCALE of either column, not to a shift.
Both growths are ratios, so k · column cancels exactly; adding a
constant does not cancel and moves every reading. Both pinned, the
second as a deliberate inequality.
A missing cell blanks its own row and the row period bars later,
and nothing else — a window kernel's recovery rule with a look-back of
one bar on each side.
benchmark must differ from column: the reading would be 1
everywhere.
Performance Index — how much
columngrew over the lastperiodbars as a multiple of how muchbenchmarkgrew over the same bars:Appends one column that oscillates around
1:1.05is five percent of out-performance accumulated over the window,0.95five percent of under-performance,1exact parity.undefinedfor the firstperiodrows — the look-back reads a bar, not a window, so the warm-up isperiodand notperiod − 1(percentChange's rule).It is priceRelative with the arbitrary level divided out: the raw ratio's height depends on the two instruments' price units and says nothing, while this asks the only question a level can answer — relative to
periodbars ago.Which "Performance Index" — F-AMBIG, and the fork is named
The corpus (
docs/notes/financial-indicators-assessment-2026-07.md§6.7) carries this from a vendor study menu with the note "normalized relative performance", and more than one thing ships under the name:period-bar growth, divided. It is exactly the missing member of this family:(perf − 1) × 100ispercentChange(priceRelative, period)identically (thebenchmarkterms cancel), which is asserted by a test, so the study adds a name and a normalisation rather than new math.PI = (close / benchmark) × (MA(benchmark) / MA(close)), i.e. the price relative measured against a smoothed baseline rather than a lagged one (https://library.tradingtechnologies.com/trade/chrt-ti-performance-index.html). That variant is not shipped because it is already a composition of two shipped primitives — priceRelative and a moving average — whereas the look-back form is the one this family lacked. If you want it:smaeach side, then twopriceRelativecalls and a ratio.× 100(100 = parity) or− 1/(x − 1) × 100(0 = parity). The ratio ships, matching priceRelative beside it, so the two lines in this family read on the same kind of axis; the percent form is one subtraction away and is spelled out above.The comparison series is a COLUMN, not a second
TimeSeriesJoin the benchmark in first and name its column — see correlation's docstring for the recipe and the reasoning. A missing
benchmarkcolumn throws.Edges
period20 and 5, with the analytic first valid bar (period) asserted and a measured separation from the difference form (colGrowth − benchGrowth), the substitution that keeps the curve's shape and moves every value.withColumnthrows on a non-finite value rather than recording it as a gap: a zerocolumn[i−period](x/0 = Infinity), a zerobenchmark[i](the benchmark's growth isInfinity, so the reading would be0) and a zerobenchmark[i−period](the benchmark's growth is0, so the reading would beInfinity). Each has its own unit test. As in percentChangeValues the test is=== 0, not<= 0— a ratio against a negative level is defined if unusual.k · columncancels exactly; adding a constant does not cancel and moves every reading. Both pinned, the second as a deliberate inequality.periodbars later, and nothing else — a window kernel's recovery rule with a look-back of one bar on each side.benchmarkmust differ fromcolumn: the reading would be1everywhere.