Example scripts
Eight ready LootScript scripts: moving averages, RSI, VWAP with bands, cumulative delta with divergences, open interest, funding rate, cluster imbalances, and a strategy for the Strategy Tester.
Eight ready LootScript scripts — from moving averages and RSI to cumulative delta, open interest, funding rate and clusters. Each is a working indicator you can add to a chart and tweak. All examples compile with the current compiler without errors or warnings.
How to run an example
- Click ƒ on the chart panel; in the Indicators window, click Editor….
- In the Editor, click New (Ctrl+N), replace the template with the example code, and click Save.
- Click Add to chart (Ctrl+Enter). Settings from
input.*will appear in the indicator settings window.
1. Three MAs with type selector
Fast, medium and slow moving averages of the selected type. Background highlights when all three align by trend.
indicator("Три скользящие", shortTitle = "MA×3", overlay = true)
maType = input.string("EMA", "Тип средней", options = ["EMA", "SMA", "WMA", "HMA"])
src = input.source(close, "Источник")
len1 = input.int(20, "Быстрая", minval = 1)
len2 = input.int(50, "Средняя", minval = 1)
len3 = input.int(200, "Медленная", minval = 1)
func ma(s, len) => switch maType {
"SMA" => ta.sma(s, len)
"WMA" => ta.wma(s, len)
"HMA" => ta.hma(s, len)
=> ta.ema(s, len)
}
m1 = ma(src, len1)
m2 = ma(src, len2)
m3 = ma(src, len3)
plot(m1, "Быстрая", color = m1 >= m1[1] ? color.teal : color.red, linewidth = 2)
plot(m2, "Средняя", color = color.orange)
plot(m3, "Медленная", color = color.gray, linewidth = 2)
bgcolor(m1 > m2 and m2 > m3 ? color.new(color.teal, 20) : m1 < m2 and m2 < m3 ? color.new(color.red, 20) : na)How it works
input.stringwithoptionsbecomes a dropdown in the settings.- The
mafunction selects the MA viaswitch. Theta.*state is local to each call site, so three calls tomaproduce three independent averages. - The fast line’s color is an expression: if it’s rising vs the prior bar (
m1[1]) it’s teal, otherwise red. - The panel can draw up to three
plotlines per script — hence three MAs.
2. RSI with zones and alerts
RSI with a filled band between levels. Line and background color when RSI sits in overbought or oversold zones.
indicator("RSI с зонами", shortTitle = "RSI", overlay = false)
len = input.int(14, "Период", minval = 2)
src = input.source(close, "Источник")
ob = input.float(70, "Перекупленность", minval = 50, maxval = 100)
os = input.float(30, "Перепроданность", minval = 0, maxval = 50)
r = ta.rsi(src, len)
hOb = hline(ob, "Перекупленность", color = color.red)
hOs = hline(os, "Перепроданность", color = color.teal)
fill(hOb, hOs, color = color.new(color.purple, 20))
plot(r, "RSI", color = r > ob ? color.red : r < os ? color.teal : color.purple, linewidth = 2)
bgcolor(r > ob ? color.new(color.red, 35) : r < os ? color.new(color.teal, 35) : na)
alertcondition(ta.crossunder(r, ob), "RSI вышел из перекупленности", "RSI опустился ниже верхнего уровня")
alertcondition(ta.crossover(r, os), "RSI вышел из перепроданности", "RSI поднялся выше нижнего уровня")How it works
hlinereturns a level handle, andfillpaints the zone between two handles.- Levels are
input.floatsettings, so lines and fill move with them. alertconditiondeclares two alerts. They don’t ring by themselves — how to enable them is explained on the Script alerts page.- Alpha in
color.newis 0 (transparent) to 255 (opaque).
3. Day VWAP with deviation bands
Volume-weighted average price from UTC midnight and a ±σ band around it.
indicator("VWAP дня с полосами", shortTitle = "VWAP", overlay = true)
src = input.source(hlc3, "Цена")
mult = input.float(1.0, "Ширина полосы, σ", minval = 0.1, step = 0.1)
anchor = session.isfirstbar
vw = ta.vwap(src, anchor)
// Сумма объёма и сумма объёма на квадрат цены с начала дня — для разброса вокруг VWAP.
var float sumV = 0.0
var float sumV2 = 0.0
if anchor {
sumV := 0.0
sumV2 := 0.0
}
if not na(volume) and not na(src) {
sumV := sumV + volume
sumV2 := sumV2 + volume * src * src
}
sigma = sumV > 0 and not na(vw) ? math.sqrt(math.max(sumV2 / sumV - vw * vw, 0)) : na
pUp = plot(vw + mult * sigma, "Верх", color = color.new(color.blue, 150))
plot(vw, "VWAP", color = color.blue, linewidth = 2)
pDn = plot(vw - mult * sigma, "Низ", color = color.new(color.blue, 150))
fill(pUp, pDn, color = color.new(color.blue, 25))How it works
ta.vwaprestarts on the bar where the anchor is true. For cryptosession.isfirstbaris the first bar after 00:00 UTC.varvariables persist across bars. They are zeroed by the same anchor, so the band is calculated for the same period as VWAP.- Deviation is sqrt(weighted mean of price^2 minus VWAP^2).
math.max(…, 0)protects against tiny negatives from rounding. - This is meaningful on intraday timeframes. If you want VWAP since the last funding payment, set
anchor = funding.settled.
4. Daily cumulative delta with divergences
Cumulative delta that resets daily, with marks on bars where price updates an extreme but delta does not.
indicator("Дневная кумдельта с расхождениями", shortTitle = "CVD", overlay = false)
len = input.int(20, "Окно поиска максимумов", minval = 3)
var float cvd = 0.0
if session.isfirstbar {
cvd := 0.0
}
if delta.available {
cvd := cvd + delta.value
}
cvdLine = delta.available ? cvd : na
// Цена обновила максимум окна, а кумдельта — нет: покупатели не подтверждают рост.
bearish = high >= ta.highest(high, len) and cvdLine < ta.highest(cvdLine, len)
bullish = low <= ta.lowest(low, len) and cvdLine > ta.lowest(cvdLine, len)
plot(cvdLine, "Кумдельта", color = cvdLine >= 0 ? color.teal : color.red, linewidth = 2)
hline(0, "Ноль", color = color.gray)
plotshape(bearish, "Медвежье расхождение", style = shape.triangledown, location = location.top, color = color.red, size = size.tiny)
plotshape(bullish, "Бычье расхождение", style = shape.triangleup, location = location.bottom, color = color.teal, size = size.tiny)How it works
delta.valueis aggressive buying minus aggressive selling for the bar. Where the feed is missingdelta.availableis false and the line gaps rather than plotting zero.- The accumulator
varis reset at the start of the day. If you need a cumulative delta over the whole loaded history without resets, use the ready seriesdelta.cum. - Divergence: price at the window high, but cumulative delta below its high for the same window. Minimums are mirrored.
location.topandlocation.bottomplace marks at the pane edges, not at price.
5. Open interest spikes
Open interest change from bar to bar in percent, with marks where it deviates from normal volatility.
indicator("Изменение открытого интереса", shortTitle = "ΔOI %", overlay = false)
len = input.int(50, "Окно для всплесков", minval = 5)
k = input.float(3.0, "Порог всплеска, σ", minval = 0.5, step = 0.5)
pct = oi.available and oi.close[1] > 0 ? 100 * (oi.close - oi.close[1]) / oi.close[1] : na
sd = ta.stdev(pct, len)
spike = not na(sd) and math.abs(pct) > k * sd
plot(pct, "ΔOI, %", style = plot.style_columns, color = pct >= 0 ? color.teal : color.red)
hline(0, "Ноль", color = color.gray)
plotshape(spike, "Всплеск", style = shape.circle, location = location.top, color = color.orange, size = size.tiny)How it works
oi.closeis open interest at the bar close,oi.close[1]at the previous bar.oi.availableprevents computing changes from nothing.- A spike is a bar whose absolute change exceeds
kstandard deviations overlenbars. - Open interest arrives per minute. On timeframes under a minute adjacent bars repeat the same value and the change is zero — that’s the data, not a bug.
6. Funding rate
Perpetual funding rate in percent per period or annualized, with marks on settlements and highlighting for high rates.
indicator("Ставка финансирования", shortTitle = "Funding", overlay = false)
mode = input.string("За период", "Показывать", options = ["За период", "Годовых"])
thr = input.float(0.05, "Порог, %", minval = 0.0, step = 0.01)
perPeriod = funding.rate * 100
periodsPerYear = funding.interval_hours > 0 ? 24.0 / funding.interval_hours * 365 : na
value = mode == "Годовых" ? perPeriod * periodsPerYear : perPeriod
level = mode == "Годовых" ? thr * periodsPerYear : thr
plot(value, "Ставка, %", style = plot.style_columns, color = value >= 0 ? color.teal : color.red)
hline(0, "Ноль", color = color.gray)
plotshape(funding.settled, "Выплата", style = shape.circle, location = location.bottom, color = color.gray, size = size.tiny)
bgcolor(math.abs(value) > level ? color.new(color.orange, 30) : na)How it works
funding.rateis a fraction, not percent: 0.0001 means 0.01%. So the rate is multiplied by 100.- For annualized values the rate is multiplied by the number of settlements per year.
24.0is written as a float deliberately: integer division in LootScript truncates. funding.settledis true on the bar where a payment occurred — a dot is placed there.- The threshold is specified per period and is converted the same way for annualized mode.
7. Cluster imbalances
Marks on the price chart where a bar’s clusters contain a vertical ladder of imbalances or simply many imbalances, plus the POC (maximum volume level) of each bar.
indicator("Дисбалансы кластеров", shortTitle = "Imbalance", overlay = true)
minSteps = input.int(3, "Уровней подряд", minval = 2)
minCount = input.int(5, "Дисбалансов в баре", minval = 1)
levels = cluster.available ? cluster.levels : 0
buys = 0
sells = 0
for i in 0 .. levels {
side = cluster.imbalance(i)
if side == 1 {
buys := buys + 1
} else if side == -1 {
sells := sells + 1
}
}
plot(cluster.poc, "POC", style = plot.style_circles, color = color.orange)
plotshape(cluster.stacked_buy_steps >= minSteps, "Лесенка покупок", style = shape.triangleup, location = location.belowbar, color = color.teal, size = size.small)
plotshape(cluster.stacked_sell_steps >= minSteps, "Лесенка продаж", style = shape.triangledown, location = location.abovebar, color = color.red, size = size.small)
plotshape(buys >= minCount, "Много дисбалансов покупок", style = shape.circle, location = location.belowbar, color = color.new(color.teal, 120), size = size.tiny)
plotshape(sells >= minCount, "Много дисбалансов продаж", style = shape.circle, location = location.abovebar, color = color.new(color.red, 120), size = size.tiny)How it works
cluster.imbalance(i)returns +1, −1 or 0 for price leveli. The imbalance threshold comes from the chart cluster settings, so the script sees the same definition as the chart.cluster.stacked_buy_stepsis how many consecutive levels contain buy imbalances. Thefor i in 0 .. levelsloop counts all imbalances in the bar, not only consecutive ones.- The script subscribes to cluster data and runs on a normal candlestick chart. On exchanges without coverage, and on timeframes under 30 seconds or over a day, there are no clusters — then
levelsis 0 and no marks appear.
8. Strategy: EMA cross with ATR stop
Long entry on MA cross, stop and take-profit in ATR multiples, exit on the opposite cross.
strategy("EMA-кросс со стопом по ATR", overlay = true, initialCapital = 10000,
defaultQtyType = strategy.qty.percent_of_equity, defaultQtyValue = 10,
slippageTicks = 2)
fastLen = input.int(12, "Быстрая EMA", minval = 1)
slowLen = input.int(26, "Медленная EMA", minval = 2)
atrLen = input.int(14, "Период ATR", minval = 1)
stopK = input.float(1.5, "Стоп, в ATR", minval = 0.1, step = 0.1)
takeK = input.float(3.0, "Цель, в ATR", minval = 0.1, step = 0.1)
fast = ta.ema(close, fastLen)
slow = ta.ema(close, slowLen)
atr = ta.atr(atrLen)
// ATR запоминается в момент сигнала, чтобы стоп и цель не ползли вслед за волатильностью.
var float riskAtr = na
if ta.crossover(fast, slow) and strategy.position_size == 0 {
riskAtr := atr
strategy.entry("Long", strategy.long)
}
if ta.crossunder(fast, slow) {
strategy.close("Long", comment = "Обратный кросс")
}
if strategy.position_size > 0 {
entry = strategy.position_avg_price
strategy.exit("Стоп/цель", from_entry = "Long", stop = entry - stopK * riskAtr, limit = entry + takeK * riskAtr)
}
plot(fast, "Быстрая", color = color.teal)
plot(slow, "Медленная", color = color.orange)How it works
strategy(…)parameters are literals: capital 10,000, position size 10% of equity, slippage 2 ticks. Commission is not set, so the tester uses the default fee: 0.02% for limit fills and 0.05% for market and stop. Set your own percentage viacommissionValue.- Market entries execute on the open of the next bar, not on the signal bar’s close: the tester does not look into the future.
strategy.exitsets stop and target from the average entry price. If both are touched in one bar, the tester by default assumes the stop fired.- Results — trades, equity curve, drawdowns — appear in the Strategy Tester… window of the Editor. See Strategies and tester for details.