A robust transpiler that converts TradingView Pine Script (v5/v6) into JavaScript code compatible with the TradingView Charting Library's Custom Indicators (PineJS) API.
This tool allows you to run Pine Script indicators directly within the Charting Library by transpiling them into standard JavaScript objects that implement the PineJS interface.
- Features
- Installation
- Quick Start
- API Reference
- Transpiled Output Example
- Supported Features
- Architecture
- Environment Support
- Limitations & Known Issues
- Development
- Changelog
- Contributing
- License
- Pine Script v5/v6 Syntax Support: Handles variable declarations (
var,varip), types, control flow (if,for,while,switch), and functions. - Standard Library Mapping: Automatically maps Pine Script's
ta.*,math.*,time.*, andstr.*functions to theirPineJS.Stdequivalents. - StdPlus Polyfills: Includes a built-in
StdPluslibrary to support Pine Script functions that are missing from the nativePineJS.Std(e.g.,bb,kc,crossover,hma). - Zero Dependencies: The core transpiler logic is dependency-free and runs in any JavaScript environment.
- TypeScript First: Full TypeScript support with strict mode enabled and comprehensive type definitions.
npm install @opusaether/pine-transpiler
# or
pnpm add @opusaether/pine-transpiler
# or
yarn add @opusaether/pine-transpilerimport { transpileToPineJS } from '@opusaether/pine-transpiler';
const pineScript = `
//@version=5
indicator("My Custom SMA", overlay=true)
len = input.int(14, "Length")
out = ta.sma(close, len)
plot(out, color=color.blue)
`;
const result = transpileToPineJS(pineScript, 'my-sma-indicator', 'My SMA');
if (result.success) {
// Use with TradingView Charting Library
const indicator = result.indicatorFactory(PineJS);
// Register indicator with chart...
} else {
console.error("Transpilation Failed:", result.error);
}Transpile Pine Script to a TradingView CustomIndicator factory.
function transpileToPineJS(
code: string, // Pine Script source code
indicatorId: string, // Unique identifier for the indicator
indicatorName?: string // Optional display name
): TranspileToPineJSResult;
// Returns:
interface TranspileToPineJSResult {
success: boolean;
indicatorFactory?: IndicatorFactory; // When success=true
error?: string; // When success=false
}Low-level function that returns raw JavaScript string (for advanced use cases).
function transpile(code: string): string;Validate if Pine Script code can be transpiled without executing.
function canTranspilePineScript(code: string): {
valid: boolean;
reason?: string;
};Execute native PineJS JavaScript code and return an indicator factory.
function executePineJS(
code: string,
indicatorId: string,
indicatorName?: string
): TranspileToPineJSResult;import {
transpileToPineJS,
transpile,
canTranspilePineScript,
executePineJS,
// Mappings
TA_FUNCTION_MAPPINGS,
MULTI_OUTPUT_MAPPINGS,
MATH_FUNCTION_MAPPINGS,
TIME_FUNCTION_MAPPINGS,
// Utilities
getMappingStats,
getAllPineFunctionNames,
// Types
COLOR_MAP,
PRICE_SOURCES
} from '@opusaether/pine-transpiler';Here's what the transpiler produces from a simple Pine Script:
Input (Pine Script):
//@version=5
indicator("Simple SMA", overlay=true)
len = input.int(14, "Length")
src = close
out = ta.sma(src, len)
plot(out, color=color.blue)
Output (JavaScript):
// Generated preamble (historical access, helpers)
const _series_close = context.new_var(close);
const _getHistorical_close = (offset) => _series_close.get(offset);
// User code transpiled
let len = input(0);
let src = close;
let out = Std.sma(src, len, context);
plot(out);The transpiler:
- Converts
input.int()to indexedinput()calls - Maps
ta.sma()toStd.sma()with context injection - Resolves
color.blueto the hex color value - Generates historical access helpers for price sources
- Variables:
x = 1,var x = 1,varip x = 1, tuple assignments[a, b] = f(). - Types:
int,float,bool,string,color,array<T>. - Control Flow:
if,for,for...in,while,switchstatements and expressions. - User-Defined Functions:
f(x) => x * 2, multi-line with block syntax. - Inputs:
input(),input.int(),input.float(),input.bool(),input.string(),input.color(),input.source(). - Exports/Imports:
export var,export function,import "lib" as Lib. - Type Definitions:
type Pointwith fields and methods.
| Category | Functions |
|---|---|
| Moving Averages | sma, ema, wma, rma, vwma, swma, alma, hma, linreg, smma |
| Oscillators | rsi, stoch, tsi, cci, mfi, roc, mom, change, percentrank |
| Volatility | atr, tr, stdev, variance, dev |
| Bands | bb, bbw, kc, kcw, donchian |
| Trend | adx, supertrend, sar, pivothigh, pivotlow |
| Cross Detection | cross, crossover, crossunder, rising, falling |
| Volume | obv, cum, accdist, vwap |
| Range | highest, lowest, highestbars, lowestbars, median, mode |
| Multi-output | macd → [macdLine, signalLine, histogram], dmi → [plusDI, minusDI, dx, adx, adxr] |
abs, acos, asin, atan, ceil, cos, exp, floor, log, log10, max, min, pow, random, round, sign, sin, sqrt, tan, sum, avg, todegrees, toradians
time, year, month, dayofweek, dayofmonth, hour, minute, second, timeframe.*
Basic array.* support mapped to JavaScript arrays with type preservation.
The transpiler follows a classic compiler pipeline with four distinct phases:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Pine Script Source │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 1. LEXER (src/parser/lexer.ts) │
│ • Tokenizes Pine Script input │
│ • Handles significant whitespace (INDENT/DEDENT) │
│ • Tab normalization (4 spaces) │
│ • 16 token types: IDENTIFIER, NUMBER, STRING, OPERATOR, etc. │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 2. PARSER (src/parser/parser.ts) │
│ • Recursive descent parser with precedence climbing │
│ • Builds Abstract Syntax Tree (30 node types) │
│ • Supports named arguments, generics, destructuring │
│ • Error recovery via synchronize() │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 3. AST (src/parser/ast.ts) │
│ │
│ Program │
│ ├── VariableDeclaration { name, value, modifier, typeAnnotation } │
│ ├── FunctionDeclaration { name, params, body } │
│ ├── IfStatement { condition, consequent, alternate } │
│ ├── ForStatement { iterator, start, end, step, body } │
│ ├── CallExpression { callee, arguments } │
│ └── ... 24 more node types │
│ │
│ Node Types: │
│ • Statements: VariableDeclaration, FunctionDeclaration, IfStatement, │
│ ForStatement, WhileStatement, ReturnStatement, SwitchStatement, etc. │
│ • Expressions: BinaryExpression, UnaryExpression, CallExpression, │
│ MemberExpression, ConditionalExpression, Identifier, Literal, etc. │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 4. GENERATOR (src/generator/) │
│ • MetadataVisitor: Extracts inputs, plots, sources, historical access │
│ • ASTGenerator: Converts AST to JavaScript string │
│ • Function Mappings: Resolves ta.*/math.*/time.* to PineJS.Std │
│ • StdPlus Injection: Polyfills for missing Std functions │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ JavaScript / PineJS Output │
└─────────────────────────────────────────────────────────────────────────────┘
src/
├── index.ts # Main entry, transpileToPineJS, runtime mocks
├── parser/
│ ├── lexer.ts # Tokenizer with indentation handling
│ ├── parser.ts # Recursive descent parser
│ └── ast.ts # AST node type definitions
├── generator/
│ ├── ast-generator.ts # AST to JavaScript code generation
│ └── metadata-visitor.ts # AST visitor for metadata extraction
├── mappings/
│ ├── technical-analysis.ts # ta.* function mappings (50+ functions)
│ ├── math.ts # math.* function mappings
│ ├── time.ts # time.* and timeframe.* mappings
│ ├── comparison.ts # Comparison operators
│ ├── utilities.ts # Utility functions
│ └── price-sources.ts # Price source mappings
├── stdlib/
│ └── index.ts # StdPlus polyfill library
└── types/
├── index.ts # Type exports
└── runtime.ts # Runtime type definitions
| Environment | Support |
|---|---|
| Node.js 18+ | ✅ Full support (ESM & CJS) |
| Browsers | ✅ Full support (ESM) |
| Deno | ✅ Via npm specifier |
| Bun | ✅ Full support |
The package ships with dual format support:
- ESM:
dist/index.js(default forimport) - CJS:
dist/index.cjs(forrequire()) - Types:
dist/index.d.ts
While the transpiler covers a significant portion of Pine Script, there are inherent limitations due to the differences between the Pine Script runtime and the Charting Library's JS API:
| Feature | Status | Notes |
|---|---|---|
strategy.* |
❌ Not Supported | Indicators only; no backtesting |
request.security |
❌ Not Supported | Requires async data fetching |
request.financial |
❌ Not Supported | External data sources |
matrix.* |
❌ Not Supported | Parsed but not implemented |
line.*, label.*, box.*, table.* |
No-op stubs; no drawing output |
-
Recursive Calculations: The
StdPluspolyfill is stateless. Functions requiring recursive historical state may have incomplete implementations.ta.macd: Returns correct MACD/signal lines; histogram may showNaN- Custom recursive indicators may not work correctly
-
Historical Access: Variables with
[offset]syntax require pre-declaration tracking. Complex nested historical access patterns may not resolve correctly. -
No Source Maps: Generated JavaScript cannot be mapped back to Pine Script lines for debugging.
| Component | Coverage | Tests | Notes |
|---|---|---|---|
| Lexer | ✅ Comprehensive | 85+ | Tokens, operators, indentation |
| Parser | ✅ Comprehensive | 150+ | Expressions, statements |
| Generator | ✅ Comprehensive | 200+ | AST generation, metadata visitor |
| Mappings | ✅ Comprehensive | 250+ | TA, math, time, utilities |
| CLI | ✅ Good | 15+ | Command-line interface |
| StdPlus | ✅ Good | 50+ | Polyfill functions |
| Integration | ✅ Good | 50+ | End-to-end transpilation |
# Install dependencies
pnpm install
# Run tests
pnpm test
# Run tests in watch mode
pnpm test -- --watch
# Build
pnpm build
# Type check
pnpm typecheck
# Lint
pnpm lint
# Lint with auto-fix
pnpm lint:fixSee CHANGELOG.md for a detailed history of changes, new features, and bug fixes.
See CONTRIBUTING.md for guidelines.
Key areas for contribution:
- Adding missing
ta.*function implementations to StdPlus - Improving test coverage for edge cases
- Adding source map generation
- Documentation improvements
AGPL-3.0 © Opus Aether
This project is licensed under the GNU Affero General Public License v3.0. This means:
- ✅ You can use, modify, and distribute this software
- ✅ If you run a modified version on a network server, you must make the source code available to users
- ✅ Any modifications must also be licensed under AGPL-3.0
- ✅ See LICENSE for full details
- Inspired by TradingView's Pine Script language
- Compatible with TradingView Charting Library
This project is an independent, open-source initiative and is not affiliated with, endorsed by, or connected to TradingView Inc.
- TradingView and Pine Script are trademarks of TradingView Inc.
- This transpiler is a clean-room implementation based on public documentation and behavior observation. It does not use or contain any proprietary code from TradingView.
- Use this tool at your own risk. The authors assume no responsibility for trading decisions or financial losses resulting from the use of this software.