Ichimoku Kinko Hyo (Goichi Hosoda, 1969) — the five-line "one-glance
equilibrium chart", appended as five columns:
${prefix}Tenkan (HH+LL) /2 over conversionPeriod (9) conversion line ${prefix}Kijun (HH+LL) /2 over basePeriod (26) base line ${prefix}SenkouA (Tenkan + Kijun) /2 leading span A ${prefix}SenkouB (HH+LL) /2 over spanBPeriod (52) leading span B ${prefix}Chikou the close itself lagging span
HH/LL are the highest high and lowest low of the window — not
the closes. The cloud (kumo) is the band between the two Senkou spans, and
its colour flips with which span is on top; that is a chart concern (the
corpus' charts ask C3), not a column.
Displacement is data-only — this study does NOT shift rows
On a chart, Senkou A and B are drawn displacement bars into the
future and Chikou displacement bars into the past. This study
keys every column to the bar it is computed from and shifts nothing.
The forward half has no honest alternative: TimeSeries.shift(col, −n)
moves values across rows that already exist, and there are no rows past
the last bar for the spans to land on (the corpus assessment's gap
G5). Inventing them means inventing bar times, which for anything but
a daily series is trading-calendar arithmetic — the same blocker as
[PND-TCAL]. The recommendation there, and here, is the chart-side
lever: a per-layer x-offset in bars (the charts ask C2), which is
where ChartIQ itself puts it and what keeps pond's data/marks separation
intact. ichimokuOffsets hands a chart exactly that map, so the
sign and the column names cannot be got wrong at the call site.
The backward half — Chikou — could have been pre-shifted, since
shift(col, −displacement) lands entirely on rows that exist, and that is
the textbook plot (the Chikou point at bar i is close[i + 26]; note
that TradingView's built-in shifts both halves by displacement − 1, one
bar fewer, a platform choice rather than the definition — the chart-side
offset absorbs either). It ships raw anyway, and this is the
deliberate part:
A pre-shifted Chikou is a look-ahead column. Its value at row i
is not knowable at row i, and every other column in this package is
causal. Joined into a feature matrix or a backtest it leaks the future
silently — there is nothing in the column's name or type to warn a
reader.
It would make the study's own rule non-uniform. With Chikou raw,
the rule is one sentence — no column is displaced, the chart offsets
+displacement on the spans and −displacement on Chikou. Pre-shift
one of the three and a consumer has to remember which.
The plotted form is one call away, and the docstring is where the
warning belongs rather than the default:
// For DRAWING or visual inspection only — the result is non-causal. constplotted=ichimoku(bars).shift('ichiChikou', -26);
Measured on the oracle's 80 bars, the displacement is not a rounding
detail: SenkouA against itself displaced 26 bars differs by up to
11.81, SenkouB by 5.11, and the close against the shifted Chikou
by 17.60, on a series spanning 98.65…118.01. Getting the offset wrong
is a whole different indicator, which is why the number is exposed rather
than left to the caller's memory.
Warm-up, per column
Length-preserving, and each column warms up on its own window:
Tenkan at bar conversionPeriod − 1 (8), Kijun and SenkouA at
basePeriod − 1 (25 — SenkouA is the average of the two and inherits
the later), SenkouB at spanBPeriod − 1 (51), and Chikou at bar
0, since it is the close. Those five are asserted against the pandas
oracle, not recalled.
Missing cells
The three windowed lines take the strict rule (see
rollingBarExtremesValues): a hole in high or low blanks a line
for its whole window and it then recovers — period bars for Tenkan
from a hole at bar k, and so on. Both bar columns blank the same rows of
every line, because the midpoint is (HH + LL) / 2 and NaN propagates
through it. A hole in close blanks Chikou on that bar only, and
nothing else: Ichimoku's other four lines never read the close, which is
the fact a build that computed the ranges over closes would hide (measured
separation below).
Definition, verified
TA-Lib has no Ichimoku. The oracle is a pandas replication at the
published parameters (9 / 26 / 52 / 26), asserting the five first-valid
bars above and separating the study from the common slip — taking the
ranges over the close instead of the bar's high and low: measured at up
to 0.2281 (mean 0.0654) on Tenkan, 0.2383 on Kijun, 0.2226 on
SenkouA and 0.2328 on SenkouB over the oracle's deliberately narrow
bars. That is small in absolute terms because the fixture's bars are
narrow by construction; on a real tape the gap is the bar range itself.
The parameter set is a knob (conversionPeriod / basePeriod /
spanBPeriod / displacement) rather than the fixed nine-twenty-six of
Hosoda's daily-with-a-Saturday-session origin, because every charting
platform exposes it and a crypto or intraday user genuinely retunes it.
No relation between the three windows is enforced: spanBPeriod shorter
than basePeriod is unusual but not wrong, and the study is not the place
to have an opinion.
Edges
In the units of the price. Scaling every price by k scales all
five lines by k; adding c shifts all five by c. Nothing here
normalises.
displacement changes no value (see above). It is validated as a
bar count so that a nonsense value fails at the call rather than
silently reaching a chart, and an oracle case pins that a different
displacement produces a bit-identical set of columns.
A flat window is ordinary input: HH === LL makes the midpoint the
price itself, which is a fact, not a 0/0 (contrast a stochastic's flat
window — there the range is a denominator).
Ichimoku Kinko Hyo (Goichi Hosoda, 1969) — the five-line "one-glance equilibrium chart", appended as five columns:
HH/LLare the highesthighand lowestlowof the window — not the closes. The cloud (kumo) is the band between the two Senkou spans, and its colour flips with which span is on top; that is a chart concern (the corpus' charts ask C3), not a column.Displacement is data-only — this study does NOT shift rows
On a chart, Senkou A and B are drawn
displacementbars into the future and Chikoudisplacementbars into the past. This study keys every column to the bar it is computed from and shifts nothing.The forward half has no honest alternative:
TimeSeries.shift(col, −n)moves values across rows that already exist, and there are no rows past the last bar for the spans to land on (the corpus assessment's gap G5). Inventing them means inventing bar times, which for anything but a daily series is trading-calendar arithmetic — the same blocker as [PND-TCAL]. The recommendation there, and here, is the chart-side lever: a per-layer x-offset in bars (the charts ask C2), which is where ChartIQ itself puts it and what keeps pond's data/marks separation intact. ichimokuOffsets hands a chart exactly that map, so the sign and the column names cannot be got wrong at the call site.The backward half — Chikou — could have been pre-shifted, since
shift(col, −displacement)lands entirely on rows that exist, and that is the textbook plot (the Chikou point at bariisclose[i + 26]; note that TradingView's built-in shifts both halves bydisplacement − 1, one bar fewer, a platform choice rather than the definition — the chart-side offset absorbs either). It ships raw anyway, and this is the deliberate part:iis not knowable at rowi, and every other column in this package is causal. Joined into a feature matrix or a backtest it leaks the future silently — there is nothing in the column's name or type to warn a reader.+displacementon the spans and−displacementon Chikou. Pre-shift one of the three and a consumer has to remember which.The plotted form is one call away, and the docstring is where the warning belongs rather than the default:
Measured on the oracle's 80 bars, the displacement is not a rounding detail:
SenkouAagainst itself displaced 26 bars differs by up to 11.81,SenkouBby 5.11, and the close against the shifted Chikou by 17.60, on a series spanning 98.65…118.01. Getting the offset wrong is a whole different indicator, which is why the number is exposed rather than left to the caller's memory.Warm-up, per column
Length-preserving, and each column warms up on its own window:
Tenkanat barconversionPeriod − 1(8),KijunandSenkouAatbasePeriod − 1(25 —SenkouAis the average of the two and inherits the later),SenkouBatspanBPeriod − 1(51), andChikouat bar 0, since it is the close. Those five are asserted against the pandas oracle, not recalled.Missing cells
The three windowed lines take the strict rule (see rollingBarExtremesValues): a hole in
highorlowblanks a line for its whole window and it then recovers —periodbars forTenkanfrom a hole at bark, and so on. Both bar columns blank the same rows of every line, because the midpoint is(HH + LL) / 2andNaNpropagates through it. A hole incloseblanksChikouon that bar only, and nothing else: Ichimoku's other four lines never read the close, which is the fact a build that computed the ranges over closes would hide (measured separation below).Definition, verified
TA-Lib has no Ichimoku. The oracle is a pandas replication at the published parameters (9 / 26 / 52 / 26), asserting the five first-valid bars above and separating the study from the common slip — taking the ranges over the close instead of the bar's high and low: measured at up to 0.2281 (mean 0.0654) on
Tenkan, 0.2383 onKijun, 0.2226 onSenkouAand 0.2328 onSenkouBover the oracle's deliberately narrow bars. That is small in absolute terms because the fixture's bars are narrow by construction; on a real tape the gap is the bar range itself.The parameter set is a knob (
conversionPeriod/basePeriod/spanBPeriod/displacement) rather than the fixed nine-twenty-six of Hosoda's daily-with-a-Saturday-session origin, because every charting platform exposes it and a crypto or intraday user genuinely retunes it. No relation between the three windows is enforced:spanBPeriodshorter thanbasePeriodis unusual but not wrong, and the study is not the place to have an opinion.Edges
kscales all five lines byk; addingcshifts all five byc. Nothing here normalises.displacementchanges no value (see above). It is validated as a bar count so that a nonsense value fails at the call rather than silently reaching a chart, and an oracle case pins that a differentdisplacementproduces a bit-identical set of columns.HH === LLmakes the midpoint the price itself, which is a fact, not a0/0(contrast a stochastic's flat window — there the range is a denominator).