Research· 14 min read

ICT’s “Chain of Custody” Lecture, Turned Into Code

On July 25 ICT published an hour-long lecture arguing that price is not pushed around by buying and selling pressure but handed from one reference level to the next — along a range that has not been delivered yet. It is an unusually specific claim, because it implies you can name the levels before price arrives. We spent a day encoding every rule in it. Eleven of twelve reduced cleanly to code. The twelfth is discretionary, so we skipped it.

Sources

“ICT Chain Of Custody Of Price” — The Inner Circle Trader, July 25, 2026 (59 minutes).

“Chain Of Custody Of Price With Daily Inefficiencies” — the first follow-up, July 28, 2026 (18 minutes). It makes the layered construction clearer.

“Chain Of Custody Of Price With RTH ORG” — the second follow-up, published about two hours after the first on July 28, 2026 (14 minutes). It adds a third graded range and answers the precedence question directly.

“Predicting Session Low & High With Executions” — July 29, 2026 (11 minutes). A trade review rather than a rules lecture; we treat it separately below and it changes almost nothing in the code. The code and conclusions here are ours.

The short version

  • The core idea is a range you draw before price trades through it, subdivided into quarters and eighths. Those subdivisions are claimed to be where the next levels form. A gap landing on the 50% is a measuring gap; an order block is valid because it sits on a quarter line, not because it touched anything.
  • The series grades three different ranges, and they do different jobs rather than compete. A projected range from an imbalance candle down to a pool of resting liquidity price has not reached; a daily inefficiency graded from its own high to its own low; and the regular trading hours opening range gap, the 9:30 a.m. Eastern opening price against the previous session’s final print. Our indicator draws all three.
  • Eleven of the twelve rule transformations are mechanical once their inputs are fixed — unambiguous enough that two people would compute the same outputs from the same inputs. The twelfth, which liquidity pool price is drawing to, is chosen by narrative, so we skipped it.
  • That discretionary target is a property of the projected range only. The other two ranges do not need one — the opening range gap has both boundaries printed rather than projected and supplies its own destination in full gap closure. There is also a stated precedence: use the opening range gap alone, and bring the daily levels in only when price does something it does not account for.
  • This is a build, not a backtest. No win rates here. We say what we do and don’t yet know at the end.

Why this lecture is worth the trouble

Most trading education resists being coded. It describes a feel, a confluence, a “you’ll know it when you see it.” That is exactly what makes it unfalsifiable and exactly why we keep running these studies: if a claim can be written as code, it can be checked, and if it cannot, that is worth knowing too.

This particular lecture is a bar-by-bar review of a week in NASDAQ futures, and it is dense with statements that are structurally testable — where a level sits, which half of a zone price is allowed to close in, what makes a reference point valid. There is no hedging in the phrasing. Levels are named to the tick.

We also had a specific reason to care. In our fair value gap study, the one filter that separated good gaps from bad ones was whether a gap was anchored to a quarter or eighth of a graded range — 38.0% of those trades won, against 22.2% for gaps that failed the test. This new lecture is essentially the full theory behind that filter. Having already seen the filter do something measurable, we wanted the rest of it.

The idea: a range drawn before it exists

A conventional dealing range is a measurement: a high price reached, a low price reached, and the retracement levels between them. The move is over; you are grading history.

What the lecture describes is different. The upper boundary is real — a candle that has already printed. The lower boundary is a target: a shelf of roughly equal lows where stop orders are presumed to be resting, which price has not reached and may never reach. He calls this an implied or unrealized dealing range, and grades it into eighths anyway.

The payoff of that framing is the part worth pausing on. Once the gradient exists, the levels inside it are specified in advance. You are no longer waiting to see where price reacts and then drawing a line through it — the lines are already there, and each one becomes a prediction about where the next zone will appear. That is what the lecture means by a chain of custody: not one big forecast, but a sequence of short handoffs, each to a level you named beforehand.

Worth being clear about: a framework that always has an explanation for what just happened is not automatically a framework that predicts what happens next. The gradient is dense — nine lines across a range — so price is rarely far from one of them. Whether reactions cluster at those levels more than chance would produce is an empirical question, and not one this article answers.

The anchor rule everything depends on

If the range is wrong, every level derived from it is wrong. The lecture spends a large share of its running time on this single point, and returns to it repeatedly.

The rule: anchor to the high of the candle that forms the imbalance— not to the highest wick in the area. The reasoning offered is that a wick is permitted to overshoot, an excursion the market is allowed to make and take back, while the bodies mark the extent of the move that actually counted. Anchoring to the wick would stretch the range and shift every subdivision inside it.

He is blunt about the consequence: get the anchor wrong and nothing downstream works, which he anticipates will be the reason most people report that the method fails. It is a convenient argument — any failure can be attributed to bad anchoring rather than to the method — but it is also, mechanically, an accurate description of how the construction behaves. Move the top of the range and all nine gradient lines move with it.

This is the same objection he raises against trend lines: ask fifty traders to draw one and you get fifty answers, because the anchor points are chosen rather than derived. The anchoring rule here is an attempt to remove that choice. Whether it succeeds is something you can check yourself, by encoding it and seeing whether the chart it produces matches the one in the video.

Twelve rules, and whether each one survives translation

Here is the full inventory, with an honest verdict on each. We counted a rule as mechanical only if we could implement it without inserting a judgment call of our own.

RuleWhat it saysCodeable?
Range anchoringAnchor to the imbalance candle’s high, never the swing wickYes
Choosing the drawThe lower boundary is the pool price is drawing toPartly
Gradient gradingSubdivide into quarters and eighthsYes
Validity testA zone counts only if it lands on a gradient lineYes
Measuring gapA gap at the 50% means the move should accelerateYes
Wick midpointStretched daily wicks are graded; the halfway point is a levelYes
First utilizationOnce a wick owns a level, later wicks there are ignoredYes
Premium sensitivityWhile bearish, no candle body may close in the upper halfYes
Opening gap stackKeep every session’s gap midpoint for the whole weekYes
Suspension blockA gap with a body-imbalance at both ends is one unitYes
Block validationConfirmed when price trades through the candle’s open, close not requiredYes
Wick vs bodyA wick through a liquidity shelf is insignificant; a body is notYes

Eleven clean, one partial. That ratio is genuinely unusual for discretionary trading material, and it is the reason this body of work keeps drawing quantitative attention despite the surrounding noise. Whatever else is true of it, it is specified.

The three rules we found most interesting

Validity by position, not by touch

The conventional way to qualify an order block is by what it does — did it reach the zone above it, did it displace hard enough. The lecture qualifies it by where it is: a block is valid because it sits on a quarter line of the graded range, even when it never reaches the gap above it. Location replaces behaviour as the test. Coded, this is a distance comparison against nine numbers, and it makes an otherwise fuzzy judgment completely reproducible.

Bodies and wicks do different jobs

A theme runs through the whole lecture: wicks are permitted excursions, bodies are commitments. It shows up in the anchoring rule, in the requirement that no body close in the wrong half of a zone, and in the insistence that a wick poking through a shelf of equal lows does not count as taking them — you want to see a body through. This is one of the few places where the framework makes a genuinely falsifiable structural claim, and it is cheap to encode: every rule becomes a comparison against max(open, close) instead of high.

Naming a gap’s location before it forms

Measuring gaps are old — a gap near the middle of a move, implying roughly as much again to come. The lecture’s claim is narrower and much stronger: that you can state where one will appear ahead of time, because it forms at the midpoint of the graded range. That is a real prediction with a real failure mode, which makes it the single most attractive rule in the set to test properly.

What the third lecture adds

The twelve rules above are the inventory from the opening lecture. The opening range gap video adds five more, and they are unusually clean — four of the five reduce to code without a judgment call, which is a better ratio than the original.

RuleWhat it saysCodeable?
ORG boundaries9:30 opening price against the previous session’s final printYes
ORG anchorGrade from the higher of that candle’s open and close, not the wickYes
Its own drawThe destination is full closure of the gapYes
Candle-two ruleThe middle candle of the three is what must lay on a levelYes
PrecedenceUse the ORG alone; add daily levels when it stops explaining pricePartly

The anchor correction is the useful part

Most of this video is spent correcting the grading anchor used in the previous one, on camera, with the reasoning shown. The rule that lands is the same body-versus-wick principle from the opening lecture, applied to a new range: grade from the higher of the opening candle’s open and close rather than from its extreme. Our script anchored the opening range gap to the session open alone, which is wrong whenever that candle closes above where it opened, so this changed our code rather than just our prose.

The candle-two rule is a genuine tightening of the validity test. The article’s twelve-rule version says a zone counts if it lands on a gradient line; the refinement is that it is specifically the middle candle of the three — the one that creates the inefficiency — whose contact matters, and that a middle candle touching two gradient levels at once implies a stronger move than one touching a single level. Both are cheap to encode and both are falsifiable.

A breakaway gap is more testable than a measuring gap

An inefficiency forming at the midpoint of the opening range gap is treated as a breakaway gap, and it comes with a condition the measuring gap does not have: it must not be traded back into and filled. That is a stated failure mode. The measuring gap claim predicts acceleration, which is a matter of degree and needs a baseline to argue about; the breakaway claim is refuted by a single fill. If we test one rule from this series first, it will be this one, because it is the cheapest to falsify.

The fourth video is a different kind of artifact

A fourth video went up the next morning, and it is worth being precise about what it is, because the title promises rather more than the content delivers to anyone trying to encode it. It is a review of a single completed trade, with the executions shown. It introduces no new range, no new grading, and no new validity test.

What it does provide is the second construction in live use: a daily suspension block in deep discount, graded, with price working down through its lower quadrant and lower octant before turning. If you want to see the daily-inefficiency gradient doing the job the second lecture describes, this is the clearest example in the series. That is genuinely useful, and it is not the same thing as evidence.

Exactly one new mechanical level comes out of it, and it is a small one: the previous session’s 9:30 opening price, used as a profit objective for the current session. It is not the midnight open and not a boundary of today’s opening range gap, so our script did not have it. It does now.

One further read is described but we have not encoded it: a wick protruding from an inversion fair value gap while the candle bodies stay inside it — a mohawk, in his terminology — is treated as continuation rather than failure. That is the body-versus-wick principle again, aimed at a zone rather than a range, and it is probably codeable — we have left it out rather than claim coverage we do not have.

The framing deserves resistance. A video showing an entry near a session low and an exit near the session high, narrated after the position is closed and the outcome known, is the single most persuasive and least informative format in trading education. One session, chosen for review by the person who traded it, tells you nothing about the hit rate of the rules that produced it. Nothing in this video moves the framework from unfalsified to supported, and every open question listed at the end of this article applies to it too.

What we built

One indicator that draws all of it: the implied range with its nine gradient lines, a separately graded daily inefficiency, the opening range gap graded the same way and anchored to the body of the 9:30 candle, graded daily wick midpoints with the first-utilization rule enforced, the week’s accumulated opening-gap midpoints, the previous session’s 9:30 open, suspension blocks, order blocks that flip state when their open is traded through, and inversion zones that are kept and recoloured rather than deleted once filled.

It also draws some ordinary chart furniture that is ours rather than the lectures’ — previous day and previous week high and low, and a dotted vertical at each session boundary. Neither is a rule from the material; they are there because the levels above are easier to read against them.

Three design decisions are worth mentioning because they affect whether the output is trustworthy. Everything derived from higher timeframe data is evaluated on completed bars only, so levels do not appear retroactively when you reload the chart — repainting would make any later study of this worthless. And the range anchor is exposed as a manual input, because auto-selecting the nearest liquidity pool is a convenience, not a faithful implementation of the rule.

The daily grid also needs an automation policy. Our script uses the latest qualifying daily fair value gap or volume imbalance at least 40 NQ points wide, replacing the displayed daily grid when a newer zone qualifies. The latest-zone policy and 40-point threshold are implementation choices, not rules stated in either lecture, and they must be declared before this construction is tested.

The code

The indicator is a single Pine Script v6 file, roughly thirteen hundred lines, and the whole thing is downloadable below. Paste it into the TradingView Pine Editor and add it to an intraday NQ or ES chart with extended hours enabled — several of the levels are anchored to overnight and opening-gap prices that simply do not exist on a regular-hours-only chart. Every threshold discussed above is exposed as an input, so you can disagree with our numbers without editing anything.

ICT_Levels.pine

Pine Script v6 · free to use and modify · please credit Seasonal Edge if you republish or share it

Download the script

Five excerpts are worth reading even if you never run it, because they are the points where a sentence from the lecture becomes an arithmetic statement you can argue with.

The anchor the third lecture corrected

This is the line that changed. The opening range gap is graded from the body of the 9:30 candle, not from its open and not from its wick, which means the grading cannot be computed until that candle has closed — hence the one-bar delay. The comment records the case the lecture does not cover, so the ambiguity is visible to anyone reading the source instead of buried in behaviour.

// NOTE: the lecture demonstrates a gap where the 9:30 side was the HIGH and
// states the higher of open/close. Whether a gap-down session should instead
// anchor to min(open, close) is not stated; we apply max() either way.
if showOrg and rthOpen[1] and not na(prevRthClose)
    orgAnchor = math.max(open[1], close[1])
    top = math.max(prevRthClose, orgAnchor)
    bot = math.min(prevRthClose, orgAnchor)

The gradient is nine numbers

The entire grading construction — quarters and eighths across a range — is one array. Every level in the article is low + range × f for some f in it.

// the nine levels every range is graded into: bounds, quadrants, octants
var array<float> GRAD = array.from(0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0)

Validity by position, with the precedence baked in

The rule that a zone counts only if it lands on a gradient line is a distance comparison against those nine numbers, with a tolerance you set. It now tests all three ranges, and the order is the point: the opening range gap is checked first because that is the precedence the third lecture states, and the other two are the fallback. The escalation trigger itself — when price does something the opening range gap fails to explain — is qualitative, so the ordering is all we felt able to mechanize.

// which gradient level (if any) a price lays on — any of the three ranges
// qualifies. The ORG is tested first; the others are the fallback.
gradHit(float p) =>
    float hitF = na
    if not na(orgGradTop) and not na(orgGradBot) and orgGradTop > orgGradBot and not na(p)
        orng = orgGradTop - orgGradBot
        for f in GRAD
            if math.abs(p - (orgGradBot + orng * f)) <= gradTol
                hitF := f
                break
    // … the same test against the implied range, then the daily zone
    hitF

The measuring gap becomes an equality test

The strongest claim in the lecture — that you can name where a measuring gap will appear before it forms — reduces to asking whether a new gap’s midpoint landed on f = 0.5. Anything else on the gradient gets a weaker tag. This is the line we would instrument first when we test it.

// validate the PD array that just formed against the gradient
if lastFvgNew
    hTop = gradHit(lastFvgTop)
    hBot = gradHit(lastFvgBot)
    hCe  = gradHit(lastFvgCe)
    if not na(hCe) and hCe == 0.5
        mgFormed := true
        label.new(bar_index, lastFvgCe, "MEASURING GAP", ...)
    else if not na(hTop) or not na(hBot) or not na(hCe)
        pdOnGrad := true

Where our choices are, in comments

The daily-zone selection policy from the previous section is marked in the source rather than buried. Wherever the script decides something the lectures do not specify, the comment says so.

// ─── 5c. Daily inefficiency (a separate graded zone) ───────────────────────
// Both lectures grade a selected daily inefficiency from its own high to its
// own low and project those octants onto the 1-minute. They do not state a
// general selection rule when several historical zones exist. This script uses
// the latest daily FVG/VI that passes dIneffMin; that policy is ours.

Sixteen alert conditions are wired up, which is the part that makes the script usable as a test harness rather than just a drawing tool — measuring gap formed, PD array on gradient, premium sensitivity broken, daily wick midpoint violated, dealing range delivered, order block validated, and a stand-aside signal when price has spent too long inside a single octant band. Three are new from the third lecture: a breakaway gap forming on the opening range gap midpoint, that breakaway gap being refuted by a close back through it, and an FVG whose middle candle spans two gradient levels. The refutation alert matters more than it sounds — a rule that fires when it fails is a rule you can score.

Reading the inputs is the fastest way to see the shape of the argument in the next section: the anchor, the tolerance, the minimum zone size and the daily-zone policy are all knobs, and the levels move when you turn them. Those choices deserve their own section.

The choices that do not reduce

Every projected-range gradient level is computed from two numbers. The first, the anchor, is fully specified. The second — which pool of liquidity price is drawing to — is not.

In the lecture the target is chosen because a particular shelf of equal lows formed too smoothly earlier in the week, and smooth lows are treated as unfinished business the market will return for. That is a judgment about market structure and intent. It draws on the preceding week of commentary, and he says plainly that a viewer arriving cold will find the lecture less useful for exactly that reason.

You can approximate it — nearest untouched shelf below price is a reasonable proxy, and it is what our automatic mode does. But approximation is not the rule, and the distinction matters more here than usual, because the target is one of only two inputs. Choose a different pool and every level moves. All the mechanical precision downstream is precision conditional on a discretionary choice upstream.

It is worth being exact about how far that objection reaches, because it is easy to overstate. The discretionary draw is a property of one of the three constructions, not of the method. The opening range gap gradient needs no chosen target at all, and it is the one the third lecture says to reach for first — a full session is traded on it alone to make the point. So this is the reason the projected range specifically is hard to test, not a reason to dismiss the framework.

This is the recurring finding across all four of our studies of this material. The rules are unusually well specified; the discretion has simply moved somewhere less visible. In the session-strategy study it lived in trade selection. In the projected construction here it lives in a single number — the draw — that the rest of the framework treats as given. The daily grid removes that target choice but introduces a separate question: which printed zone should be active. The opening range gap removes both, and pays for it by only ever describing a single session.

The other two ranges isolate different problems

Everything above concerns the projected range. The daily inefficiency — graded from its own high to its own low — does not require a narrative liquidity target. For the same selected zone, two people get the same boundaries and the same nine lines. They could still select different zones, however, because the lectures do not give a general eligibility, priority or expiry rule when several daily inefficiencies exist. The third lecture does not close this gap either: the daily zone it uses is one carried over from the previous fortnight’s commentary.

The opening range gap is the cleanest of the three, and it is worth being clear about why. Its high and low are the 9:30 opening price and the previous session’s final print — two printed values, no projection and no selection. Its destination is full closure of the gap, which is stated rather than inferred. It resets every session, so there is no question of which one is active. Of the three constructions, it is the only one where two people following the stated rules cannot produce different charts.

That still makes it a cleaner candidate for testing once the zone-selection rule is preregistered. With the input zone fixed, a failure cannot be absorbed by moving its boundaries after the fact: reactions either cluster at its octants above the base rate or they do not. The test must state which zones qualify, which one takes priority and how long it remains active.

Which is why they are best read as doing different jobs rather than competing. A selected daily zone is a map of where price may react; it says nothing about direction. The projected range is a directional hypothesis with a named destination, and it costs you a judgment call to get one. Recording both the selected zone and the projected target before the fact keeps the discretionary inputs visible instead of letting them hide inside the arithmetic.

What we don’t know yet

We want to be exact about the limits of this piece, because the temptation with a framework this articulate is to mistake coherence for evidence.

  • We have not measured whether reactions cluster at the gradient levels. With nine lines across a range, the baseline rate of price being near one is high. The test has to be against that baseline, not against zero.
  • We have not tested the measuring gap claim — whether a gap at the midpoint is followed by faster, shallower continuation than a gap elsewhere in the range.
  • We have not tested premium sensitivity — whether a body closing in the wrong half genuinely precedes failure more often than it does not.
  • We have not tested the breakaway gap — whether a gap on the opening range gap midpoint goes unfilled more often than a gap anywhere else in that range. This is the one we would run first, because a fill refutes it outright and the script now alerts on exactly that.
  • One lecture, one instrument, one week. The walkthrough is a single week of NASDAQ futures, presented in hindsight, with the outcome known. That is a teaching format, not evidence, and it should not be read as either. The two follow-ups add a second week and a single session respectively, which does not change the character of the evidence.

Those are all answerable questions, which is the whole point of encoding the rules first. A framework you can write down is a framework you can check. That study is the natural follow-up to this one, and when we run it we will publish whatever it says — as we did when two heavily promoted session strategies did not survive contact with the data.

This article is independent research and education, not investment advice or a recommendation to trade any instrument or strategy. It describes and analyses concepts taught publicly by The Inner Circle Trader (ICT) in this lecture; the summary, code, and conclusions here are our own, and no affiliation or endorsement is implied. Nothing in it should be read as a claim that any method predicts future prices.

We test patterns for a living

Seasonal Edge stress-tests recurring market patterns across 4,500+ securities with the same skepticism we applied here — win rates, out-of-sample checks, and regime awareness included.

Explore Seasonal Edge →