---
title: "wrun vs Pine"
description: "Pine works from candles: it runs on TradingView's servers and draws lines, labels and boxes on the chart. A wrun indicator gets the market under the candles.…"
order: 5
section: "getting-started"
---

<!-- source: docs/indicators/getting-started/wrun-vs-pine.md; generated by packages/cli/scripts/gen-indicator-docs.ts, do not edit -->

# wrun vs Pine

Pine works from candles: it runs on TradingView's servers and draws lines,
labels and boxes on the chart. A wrun indicator gets the market under the
candles. Every level of the order book, buy and sell volume as the
exchange tagged each trade, and the live options chain with its greeks
arrive as numbers your code can do arithmetic on. It compiles to
WebAssembly, runs in your browser, and draws its answer in whatever form
fits: a line, a profile on the price axis, a heatmap below the chart, a
card in the corner.

![How deep each one reads, one row per kind of market data: Pine reads candles, other markets and liquidations, funding and open interest in full, buy and sell volume by price and the order book only with limits, and stops before the options chain; wrun reads every row, and the options chain, implied volatility and skew, prediction odds and ETF flows only wrun reads](/wrun/images/diagrams/sees-depth.svg)

**Indicators you can build in wrun and not in Pine:**

- **Real delta.** Buy minus sell volume from the exchange's own trade
  tags ([Order flow HUD](../cookbook/order-flow-hud.md)). Pine's footprint
  infers the side from price moves, on Premium plans and up, one per
  script.
- **Book walls.** The biggest resting bid and ask near price on every bar,
  and how the pressure between the two sides shifts
  ([Order book HUD](../cookbook/order-book-hud.md)).
- **A live gamma map.** Gamma exposure at every strike, the zero-gamma
  flip and the call and put walls, drawn against price from the options
  chain ([Gamma map](../cookbook/gamma-map.md)).
- **Who is trading.** Each bar's volume split by trade size, from trades
  under $1K to trades of $10M and up, buyers and sellers apart.
- **Pictures, not just lines.** A volume profile docked on the price
  axis, an hour-by-weekday heatmap, a HUD of sparklines and gauges
  ([Volume heat hours](../cookbook/volume-heat-hours.md),
  [Market HUD](../cookbook/market-hud.md)).

| | Pine | wrun |
| --- | --- | --- |
| Language | Pine Script, TradingView's own | TypeScript syntax, compiled to WebAssembly |
| Where it runs | TradingView's servers only | Your browser, sandboxed; OpenMarket's servers when the code is protected |
| Order book | Best bid and ask, on 1-tick charts only | Every level, up to 500 a side, on every bar |
| Trades | Sides estimated from price moves | The exchange's own buy and sell tags, by price and by trade size |
| Options | No chain, greeks or implied volatility | Every listed contract with greeks; implied volatility and skew by tenor |
| Drawing | Lines, labels and boxes (500 each), polylines (100), tables | All of that, plus pies, scatters, curves, heatmaps and tiles below the chart, profiles on the price axis, HUD and hover cards |
| History | Lookahead is a switch; TradingView estimates over 95% of indicators repaint | No lookahead to switch on: history shows what you would have seen live |
| Limits | Memory is limited; the number is not published | Every limit is published, and a run that hits one stops and says which |

**Already have Pine scripts?** Any AI
[ports them](#bring-your-pine-scripts), and the compiler checks every line
before anything runs.

## The whole order book

**Walls, gaps and the pressure between bids and asks, on every bar.**

![The order book at one moment: Pine reads one bid and one ask, the best of each, on 1-tick charts only, while the rest of the book stays faint; wrun reads every level on both sides, up to 500 a side on every bar, so the wall of bids six levels down is in view](/wrun/images/diagrams/beyond-book.svg)

1. **Pine**: two rows, the touch. The faint rest is the book it never
   reads.
2. **wrun**: every row, bids and asks.
3. **The wall**: six levels down, a size your code can find and draw.

Crypto charts, spot and perpetual. Imbalance over the nearest levels, plus
the biggest bid and ask within 1% of price:

```typescript sample=gs-beyond-book
param.int("levels", 20, { min: 1, max: 500, label: "Levels per side" });
input("close", ohlcv.close); // the chart's candles
input("book", book.cells, { max_cells: 1000, block_size: 10 }); // the whole book
output("imbalance", line, lower, { color: "#64748b", label: "Imbalance", format: "0.00" });
output("bid_wall", line, overlay, { color: "#16a34a", label: "Bid wall", format: "price" });
output("ask_wall", line, overlay, { color: "#dc2626", label: "Ask wall", format: "price" });

let depth = new BookImbalance(20);

function onStart(): void {
  depth = new BookImbalance(i32(p_levels()));
}

function onBar(): void {
  const n = in_book_cells();
  if (n <= 0) return; // no book on this bar
  const cells = in_book_view(); // [price, size, side] per level
  const close = bar.close();
  let bidWall = NaN; let bidMax = 0.0;
  let askWall = NaN; let askMax = 0.0;
  depth.begin();
  for (let i = 0; i + 2 < n; i += 3) {
    const price = cells[i];
    const qty = cells[i + 1];
    const side = i32(cells[i + 2]); // +1 a bid, -1 an ask
    depth.add(price, qty, side);
    if (Math.abs(price - close) > close * 0.01) continue;
    if (side > 0 && qty > bidMax) { bidMax = qty; bidWall = price; }
    if (side < 0 && qty > askMax) { askMax = qty; askWall = price; }
  }
  depth.end();
  out_imbalance(depth.imbalance()); // (bids - asks) / (bids + asks)
  out_bid_wall(bidWall);
  out_ask_wall(askWall);
}
```

More: [Order flow](../functions/order-flow-kit.md#book-imbalance).

## Who actually traded

**Delta from the exchange's own tags, split by price and by trade size.**

![A footprint, three bars wide: each bar is sliced by price, sell volume drawn to the left of the bar's line and buy volume to the right, each side as the exchange recorded it, with each bar's delta, buy minus sell, written underneath](/wrun/images/diagrams/beyond-footprint.svg)

1. **Each bar**, sliced by price into buckets with real bounds.
2. **Sellers**, left of the bar's line.
3. **Buyers**, right of it.
4. **Delta**, under each bar: buy minus sell. Summed bar after bar, it is
   CVD.

`trades.volume`, `volume_profile` and `trade_volume_by_size`; sizes run in
seven buckets, from under 1K to 10M and up, in USD. Big trades against
small ones, as two running sums of buy minus sell split at 100K:

```typescript sample=gs-beyond-sizes
input("close", ohlcv.close); // the chart's candles
input("sizes", trade_volume_by_size.cells, { max_cells: 7 });
output("large", line, lower, { color: "#c2410c", width: 2, label: "100K and up", format: "si" });
output("small", line, lower, { color: "#94a3b8", label: "Under 100K", format: "si" });

let large = 0.0; // buy minus sell in USD, trades of 100K and up
let small = 0.0; // the same for smaller trades

function onBar(): void {
  const n = in_sizes_cells();
  const cells = in_sizes_view();
  // [bucket, buy_usd, sell_usd, buy_count, sell_count] per bucket
  for (let i = 0; i + 4 < n; i += 5) {
    const net = cells[i + 1] - cells[i + 2]; // buy minus sell
    if (cells[i] >= 4.0) large += net; // bucket 4 starts at 100K
    else small += net;
  }
  out_large(large);
  out_small(small);
}
```

When the lines part, the big trades and the small ones are on opposite
sides. More: [Order flow](../functions/order-flow-kit.md#volume-profile).

## The options chain

**Gamma by strike, the flip and the walls, from the live chain, in one call.**

![The options chain beside price: gamma by strike docked on the price axis, shaded where net gamma is positive and open where it is negative; the call wall above price, the put wall below it, and the gamma flip, dashed, where net gamma crosses zero](/wrun/images/diagrams/beyond-gamma.svg)

1. **Price**: the chart's candles, last close marked on the axis.
2. **Gamma by strike**, docked on the price axis: shaded where net gamma
   is positive, open where it is negative.
3. **Call wall**: the strike above price with the most call open interest.
4. **Gamma flip**: where net gamma, summed up from the lowest strike,
   crosses zero.
5. **Put wall**: the strike below price with the most put open interest.

Any coin an options venue lists. Implied volatility and skew by tenor, one
week to six months, are inputs on every bar of BTC and ETH charts.

The levels and max pain, on a card:

```typescript sample=gs-beyond-chain
input("close", ohlcv.close); // spot is the chart's close
input("chain", options_chain.cells, { max_cells: 4000 });
output("flip", none, overlay, { label: "Gamma flip" });
output("call_wall", none, overlay, { label: "Call wall" });
output("put_wall", none, overlay, { label: "Put wall" });
output("max_pain", none, overlay, { label: "Max pain" });
render.hud("chain_card", {
  position: "top_right", title: "Options chain", columns: 2,
  tiles: [
    tile.value("Call wall", "call_wall", { format: "price" }),
    tile.value("Gamma flip", "flip", { format: "price" }),
    tile.value("Put wall", "put_wall", { format: "price" }),
    tile.value("Max pain", "max_pain", { format: "price" }),
  ],
});

let chain = new OptionsChain(1);

function onStart(): void { chain = new OptionsChain(512); }

function onBar(): void {
  if (bar.isLast()) { // the chain arrives on the live bar
    const n = in_chain_cells();
    const now = bar.time() * 1000.0; // the clock in milliseconds
    if (n > 0) chain.load(in_chain_view(), n, now, bar.close());
  }
  out_flip(chain.zeroGamma()); // net gamma crosses zero here
  out_call_wall(chain.callWall()); // most call open interest above
  out_put_wall(chain.putWall()); // most put open interest below
  out_max_pain(chain.maxPain()); // pays option holders the least
}
```

The [Gamma map](../cookbook/gamma-map.md) recipe docks the profile as
drawn. More: [Options kit](../functions/options-kit.md).

## Off the time axis

**Some answers are not lines. A pie, a curve over strikes or a heatmap gets its own pane.**

![Five panel kinds, each in a pane of its own below the chart: a pie of the bar's volume by trade size, a scatter of one value against another, a curve such as implied volatility by strike, a heatmap such as volume by hour and weekday, and tiles of big numbers with sparklines](/wrun/images/diagrams/beyond-panels.svg)

1. **Pie**: shares of one whole, such as this bar's volume by trade size.
2. **Scatter**: one dot per pair of values, x against y.
3. **Curve**: a line over any axis, such as implied volatility by strike.
4. **Heatmap**: a grid of cells, such as volume by hour and weekday.
5. **Tiles**: big numbers, each with a caption and a sparkline.

This bar's volume by trade size as a pie, rebuilt on the live bar. The
share of trades of 100K and up runs as a line through history:

```typescript sample=gs-beyond-pie
input("close", ohlcv.close);
input("sizes", trade_volume_by_size.cells, { max_cells: 7 });
output("share", line, lower, { color: "#c2410c", label: "100K and up", format: "%" });
const mix = frame("mix", { max_bytes: 1024 }); // the pie's slices
panel.pie({ name: "size_mix", title: "This bar by trade size",
  x: "category", place: "below", frame: mix, hole: 0.5 });

const NAMES: StaticArray<string> = ["Under 1K", "1K to 10K",
  "10K to 100K", "100K to 500K", "500K to 1M",
  "1M to 10M", "10M and up"];
const COLORS: StaticArray<string> = ["#e2e8f0", "#cbd5e1",
  "#94a3b8", "#fdba74", "#fb923c", "#ea580c", "#9a3412"];

function onBar(): void {
  const n = in_sizes_cells();
  const cells = in_sizes_view();
  const live = bar.isLast();
  let total = 0.0; let large = 0.0;
  if (live) { fb_clear(); fb_text('{"rows":['); }
  for (let i = 0; i + 4 < n; i += 5) {
    const usd = cells[i + 1] + cells[i + 2];
    const k = i32(cells[i]) - 1; // buckets run 1 to 7
    total += usd;
    if (k >= 3) large += usd;
    if (live) { // one slice per bucket: [name, value, color]
      if (i > 0) fb_text(",");
      fb_text("["); fb_str(NAMES[k]); fb_text(",");
      fb_f64(usd, 0); fb_text(","); fb_str(COLORS[k]); fb_text("]");
    }
  }
  if (live) { fb_text("]}"); writeFrameBuffer(FRAME_MIX); }
  out_share(total > 0.0 ? (100.0 * large) / total : NaN);
}
```

`fb_*` builds the frame without allocating: the sandbox refuses memory
growth once the bars start. More:
[Cards, frames and panels](../presentation/cards-frames-panels.md),
[Volume profile and value area](../cookbook/volume-profile-value-area.md),
[Volatility term structure](../cookbook/vol-term-structure.md).

## Cards, not tables

**Your code writes numbers and words. The chart draws the card.**

![Three answers on one chart: the legend names the basis line, its value and a word colored for this bar; a HUD card in the corner holds four typed tiles, a value with its change, a sparkline, a gauge and a meter; and a hover card opens where the cursor rests on the line](/wrun/images/diagrams/beyond-cards.svg)

1. **The legend** carries words as well as values, each word colored for
   its bar.
2. **A HUD card** sits at one of nine anchors and holds typed tiles: a
   value with its change, a sparkline, a gauge, a meter.
3. **A hover card** opens where the cursor rests on a line, a legend
   entry or a tile.

The options card above is one; [Market HUD](../cookbook/market-hud.md)
builds a full board. Every block kind:
[What the chart shows](../presentation/overview.md).

## Settings

**Declare the kind. The dialog draws the control.**

- **Presets**: named sets of values; one click fills every setting they
  name ([Presets](../settings/presets.md)).
- **Ranges, multi-selects, lists**: a slider with two handles, a pick of
  weekdays, an editable list of lookbacks
  ([Setting kinds](../settings/kinds.md)).
- **Units**: an offset in percent of price or in ATRs, picked beside the
  number ([Sessions and units](../settings/sessions-and-units.md)).
- **Pages**: settings on pages and sections, with a filter box past
  twelve ([Pages, sections, dividers, notes](../settings/layout.md)).

## No lookahead

**`onBar()` gets one bar. There is no next bar to peek at.**

![Higher timeframes, bar by bar: a 4h candle spans four 1h bars; with lookahead on, a Pine script on history sees the new 4h close from the first of those bars, while in wrun every 1h bar sees the previous close and the new one arrives on the bar after the 4h candle closes](/wrun/images/diagrams/repainting.svg)

1. **One 4h candle** spans four 1h bars.
2. **Pine, lookahead on**: history sees the new 4h close from the first of
   those bars, before it happened. It is off by default; an author turns
   it on.
3. **wrun**: no switch. Every 1h bar sees the last closed 4h candle; the
   new close arrives on the bar after.

The forming bar replays from the last closed bar on every update. No
`varip`, no `barstate.isrealtime`
([Repainting](../core-concepts/repainting.md)).

## Bring your Pine scripts

**Hover a Pine line. See the wrun line that replaces it.**

```pine pair title="Pine" map="1 2 3 4 5 6 7 8 9 10 10 11"
//@version=6
indicator("MA Cross", overlay=true)
fastLen = input.int(9, "Fast")
slowLen = input.int(21, "Slow")
fast = ta.ema(close, fastLen)
slow = ta.sma(close, slowLen)
plot(fast, color=color.orange)
plot(slow, color=color.blue)
up = ta.crossover(fast, slow)
plotshape(up, shape.triangleup,
  location.belowbar)
alertcondition(up, "Golden cross")
```

```typescript pair title="wrun" map="1 3 4 7,2 8,2 10 10 10 11 11 - 5 6 9 9"
//@lang=wrun-ts
param.int("fast_len", 9, { min: 1 });
param.int("slow_len", 21, { min: 1 });
output("fast", line, overlay);
output("slow", line, overlay);
render.shape("cross_up_mark", {
  output: "low", shape: "triangle_up",
  where: "crossed_up" });
alert("golden_cross", {
  when: crossedUp });
…
fast = new Ema(i32(p_fast_len()));
slow = new Sma(i32(p_slow_len()));
const crossed = cross.update(
  fastValue, slowValue);
```

In the editor, **Copy for LLM** hands any AI your code, the build's rules,
the kit's API and every compiler error
([Write it with AI](write-with-ai.md)).
