Skip to content
ChartTailor
WorkServicesPricingField NotesAbout Start a build
← Pine Discoveries

The version directive can change the meaning of old security code

Migrating Pine scripts needs a timing review, especially around older `security()` and lookahead behaviour.

The version directive at the top of a Pine script looks administrative. It is not. Moving an old script through Pine versions can change syntax, available functions, defaults, and sometimes the way old patterns should be understood. Around security() and lookahead behaviour, that can change the meaning of a backtest.

The reason this matters in real scripts is that migration is often treated as a compile task. Fix the errors, rename the functions, and the script is done. That is not enough if the old script relied on timing behaviour that needs to be made explicit in the newer version.

Why this catches people

The trap is translating security() mechanically into request.security() without reviewing why the old code used lookahead, offsets, or historical references. Pine versions before the modern request style had different habits, and many old snippets were written to work around behaviour that may not be obvious from the line itself.

A script can compile after migration and still have a different timing contract. That is the dangerous part. The error messages are gone, so the author assumes the migration is complete.

The Pine bit

I review old security code by asking what value the lower-timeframe bar was supposed to receive. If the old script used lookahead_on, was it intentionally using a completed prior higher-timeframe value, or was it unknowingly leaking the current higher-timeframe value? If there is an offset, is it inside the requested expression or outside the returned series?

The version directive should be treated as a prompt to re-audit timing, not just as a compatibility label.

//@version=6
confirmedDaily = request.security(
     syminfo.tickerid,
     "D",
     close[1],
     lookahead = barmerge.lookahead_on)

How I handle it in builds

In migration work, I like to keep a before-and-after chart. If the migrated output changes, that may be correct, but it should be explainable. Sometimes the old version was wrong and the new one is honest. Sometimes the migration introduced a new timing bug. The chart alone cannot decide.

I update names during migration. A variable called dailyClose may have been ambiguous for years. Renaming it to confirmedDailyClose or developingDailyClose is a small change that prevents future misuse.

Where this shows up

A migration checklist should include one deliberately unfair test: compare the old and new versions around a higher-timeframe boundary. If the difference appears exactly where the daily or weekly bar changes, the migration probably touched timing. That is where lookahead and offsets reveal themselves.

I keep old screenshots only as evidence, not as the final authority. Sometimes the old script was repainting or leaking future data. A faithful migration of a bad timing assumption is not a successful migration. The goal is not always to preserve every old plot. The goal is to preserve the intended behaviour and make the timing honest in the current Pine version.

Implementation-wise, I do migrations in two passes. First, make the script compile with the smallest possible behavioural change. Second, review the timing and data-context choices with fresh names and tests. Combining those passes makes it too easy to change behaviour accidentally and then forget which edit caused it.

This is especially important for old snippets that were copied into many scripts. A single bad migration pattern can spread quickly if it looks like a clean modernization.

How I test it

I test migrations with before-and-after behaviour, not just a successful compile. A migrated script can be syntactically modern and behaviourally different. The review should identify which differences are intentional corrections and which are accidental changes.

Checks before I trust it

  • Treat version migration as a behaviour review, not only a syntax update.
  • Re-audit security() or request.security() timing after migration.
  • Check lookahead and offset placement together.
  • Compare old and new chart output and explain any differences.
  • Rename ambiguous higher-timeframe variables during the migration.

The thing worth preserving is that //@version is not paperwork. It is a reminder that old Pine code may carry old timing assumptions, and those assumptions need to be made visible.