CODESCRIPT

How your code runs

CodeScript walks the chart bar by bar and runs your whole script once, top to bottom, for each one. Once that clicks, both your indicator values and the timing of your fills start to make sense.

While writing, you picture a single moment: the price now, the average now. The engine runs those same lines again for every bar. What comes out is not one number but as many values as there are bars.

Once per bar, top to bottom

With 500 bars on the chart, your code runs 500 times. Each pass starts at the first line and ends at the last. When the next bar arrives, everything is worked out again.

That is why line order matters. A variable has to exist before you use it, because the engine moves downward and never peeks ahead.

CODESCRIPT
// bu satirlarin tamami her bar icin bir kez, bastan sona calisir
ortalama = sma(close, 20)
fark = close - ortalama
plot(ortalama, "SMA20", "#2962ff")
plot(fark, "fark", "#ff9800", "fark")

A blue 20-bar average on the price panel and, in a lower panel, the gap between close and that average. Both values are produced on every bar.

NOTE

Every pass recalculates, yet nothing from earlier is thrown away. The engine keeps what you produced on previous bars, and that accumulation is what forms the line you see.

What you assign is a series

Write hizli = sma(close, 10) and hizli is not a single number. It is a series carrying one value per bar. In your code you treat it like an ordinary number, and the engine does the work bar by bar.

The same holds for conditions. The comparison close > yavas does not yield one true/false; it yields one for each bar. Conditions are series too.

CODESCRIPT
// hizli tek bir sayi degil, her bara bir deger dusen seridir
hizli = sma(close, 10)
yavas = sma(close, 30)
plot(hizli, "hizli", "#26a69a")
plot(yavas, "yavas", "#ef5350")
plotshape(crossover(hizli, yavas), style="triangleup", location="belowbar", color="#26a69a")

A green 10-bar and a red 30-bar average on the price panel, with a green triangle under every bar where the fast one crosses above the slow one.

CAUTION

Mistaking a series for a single number is the classic trap. plot(hizli) draws its value on every bar, not just the most recent one.

Reading values from earlier bars

The real payoff of series is access to the past. prev hands you a series' value from as many bars back as you ask, and change gives you the difference.

CODESCRIPT
// prev bir onceki barin degerini, change ise aradaki farki verir
oncekiKapanis = prev(close, 1)
plot(oncekiKapanis, "onceki kapanis", "#9598a1")
plot(change(close, 1), "bar farki", "#2962ff", "fark")
barcolor(iff(close > oncekiKapanis, "#26a69a", "#ef5350"))

A grey close line lagging one bar on the price panel, the per-bar price difference in a lower panel, and bars tinted green or red against the previous close.

NOTE

On the earliest bars there is nothing behind to read, so the result stays empty (na). If you don't want the chain to break there, turn the gap into a number with nz.

prev(source, n=1)

A series holding the value from n bars ago.

source
series
The series whose past value you want.
n
number
How many bars to step back; 1 if omitted.

change(source, n=1)

The difference between the series now and its value n bars ago.

source
series
The series whose change is measured.
n
number
The number of bars back to compare against; 1 if omitted.

iff(condition, ifTrue, ifFalse)

A series holding, for each bar, whichever value the condition selects.

condition
boolean
The condition, judged bar by bar.
ifTrue
series
The value or color taken while the condition holds.
ifFalse
series
The value or color taken while it does not.

The path price takes inside a bar

A bar carries four prices: open, low, high and close. As it forms, price does not sit at all four at once; it travels between them. The engine cannot see inside the bar, so it assumes a path from the bar's type.

  • On an up bar, where the close sits above the open: open, then low, then high, then close.
  • On a down bar, where the close sits below the open: open, then high, then low, then close.
  • Pending orders and protective levels are checked step by step along that same route.

This assumption is no small detail; it changes the outcome. When both the take-profit and the stop-loss levels are touched on one bar, the route decides which of them fills.

Pending orders follow that sequence

A market order waits for nothing; it fills on the bar its condition fires. A pending order rests at a level and fills only if price actually trades through it. A take-profit and a stop-loss are pending orders too.

CODESCRIPT
// giriste ayni emre hem kar-al hem zarar-kes bagliyoruz
enterLong(crossover(close, sma(close, 20)), id='poz')
exit(true, id='koru', fromEntry='poz', limit=close * 1.03, stop=close * 0.98)
plot(sma(close, 20), "SMA20", "#2962ff")

The position opens on the crossing bar with two protections attached to the same order: a take-profit 3% up and a stop-loss 2% down. Whichever price meets first inside the bar fills, and the other is cancelled.

Tie the protective levels to volatility instead of a fixed percentage and the distance adjusts itself between quiet and busy bars. Below, the stop sits one atr away and the target two.

CODESCRIPT
// koruma seviyelerini sabit yuzde yerine oynaklikla olcuyoruz
oynaklik = atr(14)
enterLong(crossover(close, ema(close, 50)), id='poz')
exit(true, id='koru', fromEntry='poz', limit=close + 2 * oynaklik, stop=close - oynaklik)
plot(ema(close, 50), "EMA50", "#ff9800")

An orange EMA50 line with an entry on each upward cross, and a protective distance that widens or tightens with the bar's volatility.

CAUTION

If the two levels land on exactly the same point, the stop-loss fills first. That is deliberate: the worse case goes first so a backtest never flatters its own result.

Closed bars and the forming bar

Historical bars are closed and their values are settled. On a live chart the rightmost bar is still forming, and your code reruns on every price update. There, a condition can flash true and be gone seconds later.

If you want the decision made only on a completed bar, pair your condition with barstate.isconfirmed.

CODESCRIPT
// karari yalniz kapanmis barda ver
sinyal = crossover(close, sma(close, 20))
kesin = sinyal and barstate.isconfirmed
enterLong(kesin)
exit(crossunder(close, sma(close, 20)))
plotshape(kesin, style="triangleup", location="belowbar", color="#26a69a")

The entry and its triangle appear only after the bar closes, so a fleeting cross on the forming bar opens no trade.

TIP

In a backtest every bar is already closed, so barstate.isconfirmed is always true. The difference shows up only on a live chart, and it is a common reason results look one way in testing and another in practice.

Common mistakes

  • Confusing a series with its latest value. A condition is judged afresh on every bar.
  • Defining a variable below the line that uses it. The engine reads downward and does not look ahead.
  • Posting a pending order on the wrong side of price. A buy limit belongs below price, a buy stop above it.
  • Assuming the take-profit wins when both protective levels are touched on one bar. On an exact tie the stop-loss goes first.
  • Trusting a signal from a bar that has not closed yet. Until it does, that signal can still be withdrawn.

The bar-by-bar pass, the series mindset and the in-bar price path: the rest of the language rests on these three rules. From here, indicators and orders come much more easily.