Run TradingView Pine Script outside TradingView.
Quick start · Library API · See it in production: the wavealgo leaderboard ↗
Resin compiles Pine Script v5/v6 to a plain JavaScript module and runs it — same indicators, same series semantics, your own machine. TradingView will not let a script leave the platform; this is how you get it out.
- 95.1% of 10,618 real-world scripts compile (measured, method below)
- 9,883 tests, plus a differential oracle matched to an independent implementation at 1e-9
- Zero runtime dependencies — the CLI runs straight from a clone, no install step, no build step
- Running in production — every score on the wavealgo leaderboard is computed by this engine
Requires Node 22.18+ (it executes the TypeScript source directly). Nothing to install:
git clone https://github.com/nullarch/resin.git
cd resin
# run an indicator and print the last bar's plot values
node bin/resin.mjs run examples/rsi-cross.pine --bars 300RSI 57.66239695569333
Smoothed 54.056462491106444
# compile it to a JavaScript module you can read
node bin/resin.mjs build examples/rsi-cross.pine -o rsi-cross.js
# point it at a folder of your scripts and find out how much of it compiles
node bin/resin.mjs check ./my-scripts
# dump everything a chart would need — colors, shapes, drawings — as JSON
node bin/resin.mjs run examples/rsi-cross.pine --bars 300 --viz viz.json
# optional: get `resin` on your PATH instead of typing node bin/resin.mjs
npm install -g @nullarch/resinrun synthesizes deterministic bars by default; pass --data bars.json to use
your own OHLCV data. The same CLI works without the clone: npx @nullarch/resin build my.pine.
Pine is a good language for expressing a trading idea and a bad place to keep one. You cannot run a Pine script in CI, cannot backtest a thousand of them in an afternoon, cannot embed one in a bot, and cannot take the indicator you spent a weekend tuning and put it in your own application. Every one of those needs the script to run somewhere else.
Resin is a compiler and a runtime, not a charting product. It gives you the values; what you do with them is yours.
The clearest demonstration of "run Pine outside TradingView" is a site that does it at scale. wavealgo.com/leaderboard — built by the same team — grades Pine strategies the way a single chart never can: each script is compiled by this engine and backtested across 6 markets × 3 timeframes, 18 cells per script, with TradingView's next-bar-open fill rule and per-side fees, then given a verdict and an alpha score. Every number on that page came out of this compiler; the methodology is public.
If you want to see what Resin's output looks like before cloning anything, start there.
Against a snapshot of 12,424 public Pine v5/v6 scripts collected from GitHub:
| scripts | ||
|---|---|---|
| Snapshot | 12,424 | v5/v6, deduplicated |
| — TradingView rejects them too | −1,085 | verified against TradingView's own compiler |
| — import a private library we cannot resolve | −719 | out of scope |
| Denominator | 10,618 | |
| Compiles | 10,100 | 95.1% |
The 1,085 exclusions are not our judgment. Every failing script was submitted to TradingView's own compiler and recorded; those are the ones TradingView also refuses. An earlier version of this project made that call by inference instead and came close to discarding about 1,200 perfectly valid scripts.
The corpus is not in this repository. It is thousands of third-party scripts
under mixed and often absent licenses, and redistributing it is not ours to do.
So you cannot reproduce that specific number here — you can only reproduce the
method, by running resin check over scripts you already have.
The corpus/ directory you will find here is a different set, not that survey:
Pine fixtures taken from the reference implementation's own test suite, which the
differential replay below runs against its golden output. Source comments that
cite corpus/wild/... do mean the survey, and those paths do not resolve here.
Three independent checks, because a compiler that is merely self-consistent is not worth much:
- Differential against a reference implementation. A separate Python
implementation of the same language runs the same script over the same bars
and the outputs are compared bar by bar — 263 scripts in
oracle/, matched to 1e-9. The two disagree in a handful of places on purpose, because the reference is the one that is wrong there; each of those is argued at the call site rather than silently waived. - TradingView's own compiler, as the arbiter of what is even valid Pine. This is what turns "we fail on this script" into either "our gap" or "not valid Pine" without anyone guessing.
- The test suite, which is where the semantics actually live.
Pine's semantics are unusual and most of the work is there rather than in the
syntax. Every value is a time series, var and varip have their own
initialization rules, na is not NaN in every context, technical-analysis
functions carry hidden per-call state that has to be allocated at compile time,
and a conditionally-executed ta.* call still has to advance its state on bars
where the branch is not taken. Those are the parts that are implemented and
tested.
68 ta.* functions, the strategy engine (entries, exits, pyramiding,
strategy.* state), user-defined types and methods, arrays, maps, matrices,
request.security with higher-timeframe aggregation, drawing objects, and the
input.* family.
import { transpile, compile, Context } from '@nullarch/resin';
const result = transpile(source, { chartTf: 'D' });
if (!result.ok) throw new Error(result.errors.join('\n'));
const ctx = new Context(
data, result.varSlots.length, result.taSlotCount, result.fnVarSlotCount,
result.historySlotCount, result.taScratchSize, {},
result.plotTitles.length, result.securityTfs, result.refHistorySlotCount,
result.condCallHistorySlotCount, result.condCallRefHistorySlotCount,
);
const bar = compile(result.code)(ctx);
for (let i = 0; i < ctx.barCount; i++) { ctx.advance(); bar(); }
console.log(ctx.plots[0].toArray());run(result, data) does the same thing in one call when you do not need to
observe state as it goes, and its return carries viz: plot styles and per-bar
colors, marker conditions, background/bar-color stripes, fills, and every
label/line/box/table the script created. The supported surface is exactly what
src/index.ts exports and nothing else — everything under src/ beyond that
is internal and will change. See API.md.
The package ships TypeScript source. Bundlers (Next.js, Vite, webpack) consume it as-is; on plain Node, run your script with the bundled loader hook:
node --import @nullarch/resin/register your-script.mjs- No charts. Resin computes plot series. Drawing them is your problem.
- Charts are data here, not pixels. Since 0.2.0 the visualization calls are
captured instead of dropped: plot styles and per-bar colors,
plotshape/plotchar/plotarrow/plotcandle/plotbar,bgcolor/barcolor/hline/fill, and everylabel/line/box/tablecreation come back underrun(result, data).viz— orresin run --viz out.jsonfrom the CLI. resin-lightweight-charts renders that data on TradingView's own open-source charts;polyline,linefill,alertandalertconditionremain no-ops. - Order fills follow TradingView's documented rule — market orders at the next bar's open — but that has not been confirmed against TradingView itself. The rule is implemented from the specification, not from a side-by-side run. If you are relying on backtest numbers rather than indicator values, treat them as provisional.
- Intrabar fills cannot be confirmed from bar data at all. A stop, a limit or a trailing exit fills somewhere inside a bar and OHLC does not record where. Any engine, this one included, is guessing a path. TradingView has the same limitation and says so.
request.securityis aggregated from the bars you supply, not fetched. If you feed daily bars and the script asks for weekly, Resin builds the weekly series by calendar aggregation.- No
v4or earlier. v5 is the floor. - Some semantics are reasoned, not confirmed. TradingView does not document
everything — what
dayofweekreturns at a week boundary, hownapropagates through a particular builtin. Where the behaviour had to be inferred, the reasoning and its evidence sit in a comment at the call site, marked as a hypothesis rather than a measurement. - Known gaps are recorded where they bite. The long tail is things like
history access on a user-defined-type field through a multi-hop function
parameter, or
request.securitygiven an expression built from a loop variable. Each is commented at the point where it is refused, with a workaround when one exists.
Resin was developed by an autonomous agent loop over 800-odd iterations, each one a single commit against a fixed set of state files. That is worth knowing because it explains the shape of the thing: the verification apparatus above is not decoration, it is what made the loop safe to leave running. The differential oracle, the external arbiter for validity, and a standing rule that no claim counts until it has been re-measured are the reasons a machine could write this without quietly breaking it.
One consequence is visible in the source, and you should know about it before you read anything:
- All 365 compiler and runtime error messages are English — they began in Korean, and they were translated first, ahead of everything else on this list, because they were the only item that affected using the tool rather than reading it. The full suite, including the 3,000-script differential replay, pinned that change to zero behavioral movement.
- About a third of the comments in
src/are in Korean, roughly 14,000 lines. Skipping them is not really an option — much of the reasoning behind an odd-looking branch lives there — so they are being translated rather than stripped. - Code, identifiers, README and API docs are English throughout.
Translation happens upstream in the development repository and lands here by re-snapshot, so it arrives in batches rather than a trickle.
PineTS is an existing AGPL-3.0
Pine-to-JavaScript project. Resin shares no code with it. It was consulted as a
black-box behavioural reference for TradingView semantics that are otherwise
undocumented — the value of dayofweek, which plot styles exist, that sort of
thing — and every place that happened is cited in a source comment so the
provenance is auditable rather than asserted. Facts about a third-party product
are not copyrightable; its implementation was not read into this one.
Apache-2.0. See LICENSE.
Pine Script and TradingView are trademarks of TradingView, Inc. This project is not affiliated with or endorsed by TradingView.