Starter KitAI Broker Docs
Index

PineScript Algo Trading

Initialization and Usage

This guide explains how to initialize PineTS and run indicators or strategies with detailed documentation of all available options and return values.

Table of Contents


Installation

```bash npm install pinets ```


PineTS Constructor

The PineTS class is the main entry point for working with indicators and strategies.

Syntax

```typescript const pineTS = new PineTS( source: IProvider | any[], tickerId?: string, timeframe?: string, limit?: number, sDate?: number, eDate?: number ); ```

Parameters

ParameterTypeRequiredDescription
sourceIProvider | any[]YesEither a data provider instance (e.g., Provider.Binance) or an array of OHLCV data
tickerIdstringNo*The trading pair symbol (e.g., 'BTCUSDT'). Required when using a provider
timeframestringNo*The timeframe/interval for the data. Required when using a provider
limitnumberNoMaximum number of candles to fetch (default: provider-specific, max 5000)
sDatenumberNoStart date in milliseconds timestamp. Used for date range queries
eDatenumberNoEnd date in milliseconds timestamp. Used for date range queries

* Required when using a provider, optional when passing an array of data

Understanding Candle Fetching and Ordering

How limit Works

When you specify a limit without date ranges, PineTS fetches the most recent candles working backwards from the current time:

```typescript // Fetches the last 100 daily candles (most recent) const pineTS = new PineTS(Provider.Binance, 'BTCUSDT', 'D', 100); // Result: 100 candles from ~100 days ago until now ```

Important notes:

  • Data is fetched from newest to oldest from the exchange
  • Maximum limit is 5000 candles (hard cap, might be changed in the future as we optimize the runtime performance)
  • If no limit is specified, the provider's default is used (varies by provider)

How Date Ranges Work

When you specify sDate and eDate, PineTS fetches all candles within that date range:

```typescript const startDate = new Date('2024-01-01').getTime(); // Start: Jan 1, 2024 const endDate = new Date('2024-12-31').getTime(); // End: Dec 31, 2024

const pineTS = new PineTS( Provider.Binance, 'BTCUSDT', 'D', undefined, // No limit - use date range instead startDate, endDate ); // Result: All daily candles from Jan 1 to Dec 31, 2024 ```

Date range behavior:

  • Fetches all candles between sDate and eDate
  • If the date range spans more than 1000 candles, PineTS automatically handles pagination
  • Still subject to the 5000 candle maximum
  • Data is ordered chronologically (oldest to newest)

Priority and Combinations

ScenarioBehavior
Only limit specifiedFetches the last limit candles from now
Only sDate and eDate specifiedFetches all candles in the date range (up to 5000)
Both limit and date rangeDate range is used, limit is ignored
Neither specifiedUses provider default (typically 500-1000 candles)

Data Ordering After Fetching

Regardless of how data is fetched, PineTS ensures the data is in chronological order:

```typescript // After initialization, data is ordered: [oldest ... newest] const pineTS = new PineTS(Provider.Binance, 'BTCUSDT', 'D', 100);

await pineTS.run((context) => { const { close } = context.data;

// close[0] = current bar (most recent)
// close[1] = previous bar
// close[2] = 2 bars ago
// ... and so on

console.log('Current close:', close[0]);
console.log('Previous close:', close[1]);

}); ```

Time series indexing:

  • [0] = current/most recent bar
  • [1] = previous bar
  • [2] = 2 bars ago
  • This matches Pine Script's time series behavior

Examples of Different Fetching Scenarios

```typescript // Example 1: Last 100 candles (from now backwards) const recent = new PineTS(Provider.Binance, 'BTCUSDT', '1h', 100); // Gets: ~100 hours of data up to current time

// Example 2: Specific date range (all candles in range) const historical = new PineTS(Provider.Binance, 'ETHUSDT', 'D', undefined, new Date('2023-01-01').getTime(), new Date('2023-12-31').getTime()); // Gets: All daily candles in 2023 (365 candles)

// Example 3: Large limit (will be capped at 5000) const maxData = new PineTS(Provider.Binance, 'BTCUSDT', '1h', 10000); // Gets: Only 5000 most recent hourly candles (max cap)

// Example 4: No limit (provider default) const defaultData = new PineTS(Provider.Binance, 'BTCUSDT', 'D'); // Gets: Provider default amount (typically 500-1000 candles) ```


Initialization Options

Option 1: Using a Data Provider

The easiest way to initialize PineTS is using a built-in data provider:

```typescript import { PineTS, Provider } from 'pinets';

// Basic initialization with limit const pineTS = new PineTS(Provider.Binance, 'BTCUSDT', 'D', 100);

// With date range const startDate = new Date('2024-01-01').getTime(); const endDate = new Date('2024-12-31').getTime(); const pineTSWithDateRange = new PineTS( Provider.Binance, 'ETHUSDT', '1h', undefined, // no limit startDate, endDate ); ```

Available Providers

Currently supported providers:

  • Provider.Binance - Binance exchange data provider

Supported Timeframes

The following timeframes are supported with Binance provider:

TimeframeDescriptionBinance Interval
'1'1 minute1m
'3'3 minutes3m
'5'5 minutes5m
'15'15 minutes15m
'30'30 minutes30m
'60'1 hour1h
'120'2 hours2h
'240' or '4H'4 hours4h
'D' or '1D'1 day1d
'W' or '1W'1 week1w
'M' or '1M'1 month1M

Option 2: Using Custom Data

You can also provide your own OHLCV data as an array:

```typescript import { PineTS } from 'pinets';

const customData = [ { openTime: 1640995200000, open: 46000, high: 47000, low: 45500, close: 46500, volume: 1234.56, closeTime: 1641081599999, }, // ... more candles ];

const pineTS = new PineTS(customData); ```

Custom Data Format

Each data point in the array must include:

FieldTypeRequiredDescription
opennumberYesOpening price
highnumberYesHighest price
lownumberYesLowest price
closenumberYesClosing price
volumenumberYesTrading volume
openTimenumberNoOpening time (milliseconds timestamp)
closeTimenumberNoClosing time (milliseconds timestamp)

The run() Method

The run() method executes your indicator or strategy code across all candles in the dataset.

Syntax

```typescript const context = await pineTS.run( pineTSCode: Function | String, n?: number ): Promise ```

Parameters

ParameterTypeDefaultDescription
pineTSCodeFunction | StringRequiredThe indicator/strategy function to execute
nnumberAll periodsNumber of most recent periods to process. If not specified, processes all available data

Return Value

Returns a Promise<Context> object containing:

  • result: The computed indicator values
  • data: Market data arrays (open, high, low, close, volume, etc.)
  • plots: Any plot data generated
  • Additional context properties

Context Object

The context object is passed to your indicator function and contains all the data and utilities needed for calculations.

Available Properties

```typescript interface Context { // Market data (time-series arrays) data: { open: number[]; // Opening prices high: number[]; // Highest prices low: number[]; // Lowest prices close: number[]; // Closing prices volume: number[]; // Volume data hl2: number[]; // (high + low) / 2 hlc3: number[]; // (high + low + close) / 3 ohlc4: number[]; // (open + high + low + close) / 4 openTime: number[]; // Opening timestamps closeTime: number[]; // Closing timestamps };

// Pine Script namespaces
ta: TechnicalAnalysis; // Technical analysis functions
math: PineMath; // Mathematical operations
input: Input; // Input parameters
request: PineRequest; // Data requests
array: PineArray; // Array operations
core: {
    plot: Function; // Plot data
    plotchar: Function; // Plot characters
    na: Function; // Not-a-number handling
    nz: Function; // Replace NaN with zero
    color: any; // Color utilities
};

// Execution state
idx: number; // Current bar index
NA: any; // Not-a-number constant (NaN)

// Variable scopes (for Pine Script compatibility)
params: any; // Parameter variables
const: any; // Constant variables
var: any; // Var-scoped variables
let: any; // Let-scoped variables

// Results
result: any; // Computed results
plots: any; // Plot data

// Market context
marketData: any[]; // Raw market data
source: IProvider | any[]; // Data source
tickerId: string; // Trading pair
timeframe: string; // Timeframe
limit: number; // Data limit
sDate: number; // Start date
eDate: number; // End date

} ```

Quick Access to Common Data

```typescript const { result } = await pineTS.run((context) => { // Destructure commonly used items const { ta, math, core } = context; const { close, open, high, low, volume } = context.data;

// Your indicator logic here
const ema9 = ta.ema(close, 9);
const ema21 = ta.ema(close, 21);

return { ema9, ema21 };

}); ```


Return Values

The run() method returns different formats depending on what your indicator returns:

Single Value Return

If your indicator returns a single value, context.result will be an array:

```typescript const { result } = await pineTS.run((context) => { const { ta } = context; const { close } = context.data;

const sma = ta.sma(close, 20);
return sma; // Single value

});

// result is an array of numbers console.log(result); // [45123.5, 45234.2, 45345.8, ...] ```

Object Return (Multiple Values)

If your indicator returns an object, context.result will be an object with arrays:

```typescript const { result } = await pineTS.run((context) => { const { ta } = context; const { close } = context.data;

const ema9 = ta.ema(close, 9);
const ema21 = ta.ema(close, 21);
const rsi = ta.rsi(close, 14);

return { ema9, ema21, rsi }; // Object with multiple values

});

// result is an object with arrays console.log(result.ema9); // [45123.5, 45234.2, ...] console.log(result.ema21); // [44987.3, 45098.7, ...] console.log(result.rsi); // [65.4, 67.2, ...] ```

Accessing the Full Context

You can access the entire context object for more information:

```typescript const context = await pineTS.run((context) => { const { ta } = context; const { close } = context.data;

const ema = ta.ema(close, 9);
return { ema };

});

console.log(context.result); // The indicator results console.log(context.data); // Market data console.log(context.tickerId); // 'BTCUSDT' console.log(context.timeframe); // 'D' console.log(context.marketData); // Raw OHLCV data ```


Complete Examples

Example 1: Simple Moving Average

```typescript import { PineTS, Provider } from 'pinets';

async function runSMA() { // Initialize with 200 daily candles const pineTS = new PineTS(Provider.Binance, 'BTCUSDT', 'D', 200);

// Calculate 20-period SMA
const { result } = await pineTS.run((context) => {
    const { ta } = context;
    const { close } = context.data;

    const sma20 = ta.sma(close, 20);
    return sma20;
});

console.log('SMA(20):', result);

}

runSMA(); ```

Example 2: Multiple Indicators

```typescript import { PineTS, Provider } from 'pinets';

async function runMultipleIndicators() { const pineTS = new PineTS(Provider.Binance, 'ETHUSDT', '4H', 500);

const { result } = await pineTS.run((context) => {
    const { ta, math } = context;
    const { close, high, low } = context.data;

    // Calculate multiple indicators
    const rsi = ta.rsi(close, 14);
    const [macd, signal, histogram] = ta.macd(close, 12, 26, 9);
    const [upperBand, middleBand, lowerBand] = ta.bb(close, 20, 2);
    const atr = ta.atr(high, low, close, 14);

    // Return all results
    return {
        rsi,
        macd,
        signal,
        histogram,
        upperBB: upperBand,
        middleBB: middleBand,
        lowerBB: lowerBand,
        atr,
    };
});

console.log('RSI:', result.rsi);
console.log('MACD:', result.macd);
console.log('ATR:', result.atr);

}

runMultipleIndicators(); ```

Example 3: With Date Range

```typescript import { PineTS, Provider } from 'pinets';

async function runWithDateRange() { const startDate = new Date('2024-01-01').getTime(); const endDate = new Date('2024-06-30').getTime();

const pineTS = new PineTS(
    Provider.Binance,
    'BTCUSDT',
    'D',
    undefined, // No limit, use date range
    startDate,
    endDate
);

const { result } = await pineTS.run((context) => {
    const { ta } = context;
    const { close } = context.data;

    const ema50 = ta.ema(close, 50);
    const ema200 = ta.ema(close, 200);

    return {
        ema50,
        ema200,
        bullish: ema50 > ema200,
    };
});

console.log('EMA50:', result.ema50);
console.log('EMA200:', result.ema200);
console.log('Bullish signals:', result.bullish);

}

runWithDateRange(); ```

Example 4: Custom Data

```typescript import { PineTS } from 'pinets';

async function runWithCustomData() { const customData = [ { open: 100, high: 105, low: 99, close: 103, volume: 1000, openTime: Date.now() - 86400000 * 99, closeTime: Date.now() - 86400000 * 98 }, { open: 103, high: 108, low: 102, close: 107, volume: 1200, openTime: Date.now() - 86400000 * 98, closeTime: Date.now() - 86400000 * 97 }, // ... more data ];

const pineTS = new PineTS(customData);

const { result } = await pineTS.run((context) => {
    const { ta } = context;
    const { close } = context.data;

    const sma10 = ta.sma(close, 10);
    return { sma10 };
});

console.log('SMA(10):', result.sma10);

}

runWithCustomData(); ```

Example 5: Processing Last N Periods Only

```typescript import { PineTS, Provider } from 'pinets';

async function runLastNPeriods() { // Fetch 1000 candles const pineTS = new PineTS(Provider.Binance, 'BTCUSDT', 'D', 1000);

// But only process the last 100
const { result } = await pineTS.run((context) => {
    const { ta } = context;
    const { close } = context.data;

    const rsi = ta.rsi(close, 14);
    return { rsi };
}, 100); // Only process last 100 periods

console.log('RSI (last 100 periods):', result.rsi);

}

runLastNPeriods(); ```

Example 6: Using TA Cache for Performance

```typescript import { PineTS, Provider } from 'pinets';

async function runWithCache() { const pineTS = new PineTS(Provider.Binance, 'BTCUSDT', '1h', 5000);

// Enable TA cache for better performance on large datasets
const { result } = await pineTS.run(
    (context) => {
        const { ta } = context;
        const { close } = context.data;

        const ema20 = ta.ema(close, 20);
        const ema50 = ta.ema(close, 50);

        return { ema20, ema50 };
    },
    undefined,
    true
); // Enable cache

console.log('Results computed with caching enabled');

}

runWithCache(); ```

Example 7: Complex Strategy

```typescript import { PineTS, Provider } from 'pinets';

async function runComplexStrategy() { const pineTS = new PineTS(Provider.Binance, 'BTCUSDT', 'D', 365);

const context = await pineTS.run((ctx) => {
    const { ta, math } = ctx;
    const { close, high, low, volume } = ctx.data;

    // Multiple indicator calculation
    const rsi = ta.rsi(close, 14);
    const [macd, signal, _] = ta.macd(close, 12, 26, 9);
    const atr = ta.atr(high, low, close, 14);
    const volumeSMA = ta.sma(volume, 20);

    // Generate signals
    const buySignal = rsi < 30 && macd > signal && volume > volumeSMA;
    const sellSignal = rsi > 70 && macd < signal;

    // Calculate stop loss and take profit levels
    const stopLoss = close - atr * 2;
    const takeProfit = close + atr * 3;

    return {
        rsi,
        macd,
        signal,
        atr,
        buySignal,
        sellSignal,
        stopLoss,
        takeProfit,
        price: close,
    };
});

// Access results
const { result } = context;

// Find trading opportunities
console.log('Last RSI:', result.rsi[result.rsi.length - 1]);
console.log('Last MACD:', result.macd[result.macd.length - 1]);

// Count signals
const buyCount = result.buySignal.filter(Boolean).length;
const sellCount = result.sellSignal.filter(Boolean).length;
console.log(`Buy signals: ${buyCount}, Sell signals: ${sellCount}`);

}

runComplexStrategy(); ```


Tips and Best Practices

Waiting for Data to Load

Always use await with pineTS.run() since data fetching is asynchronous:

```typescript // ✅ Correct const { result } = await pineTS.run((context) => { ... });

// ❌ Wrong - will not work properly const { result } = pineTS.run((context) => { ... }); // Missing await ```

Destructuring for Cleaner Code

Destructure the context for more readable code:

```typescript const { result } = await pineTS.run((context) => { // Destructure for cleaner access const { ta, math } = context; const { close, open, high, low } = context.data;

// Now you can use them directly
const sma = ta.sma(close, 20);
return sma;

}); ```

Return Objects for Multiple Values

When calculating multiple indicators, return them as an object:

```typescript // ✅ Return multiple values as object return { sma, ema, rsi };

// ❌ Less convenient - only returns one value return sma; ```

Performance Optimization

For large datasets or complex calculations:

```typescript // Enable TA cache const { result } = await pineTS.run(indicatorFn, undefined, true);

// Or process fewer periods const { result } = await pineTS.run(indicatorFn, 100); // Last 100 periods only ```

Error Handling

Always wrap your PineTS code in try-catch blocks:

```typescript try { const pineTS = new PineTS(Provider.Binance, 'BTCUSDT', 'D', 100); const { result } = await pineTS.run((context) => { // Your indicator logic }); console.log(result); } catch (error) { console.error('Error running indicator:', error); } ```


Next Steps


layout: default title: Syntax Guide nav_order: 3

PineTS Syntax Guide

This guide explains how to write PineTS code that is equivalent to Pine Script. PineTS is designed to be written in JavaScript/TypeScript but behaves like Pine Script's runtime execution model.

Variable Declarations

PineTS distinguishes between let and var declarations to mimic Pine Script's behavior. This is a critical difference from standard JavaScript.

let vs var

FeaturePine ScriptPineTS (JS/TS)Behavior
Re-initializationfloat x = closelet x = closeVariable is re-initialized/calculated on every bar.
State Persistencevar float x = 0.0var x = 0.0Variable is initialized only once (first bar) and retains its value across bars.

⚠️ Important for JS Developers: In PineTS, var does not behave like standard JavaScript var. It adopts Pine Script's var semantics (persistent state). If you need standard JS function-scoped variables that reset every time, use let.

Example: State Persistence

Pine Script:

```javascript // 'sum' retains its value across bars var float sum = 0.0 sum := sum + close ```

PineTS:

```javascript // 'sum' retains its value across bars var sum = 0.0; sum = sum + close; ```

Loops

PineTS supports standard JavaScript loops, which map to Pine Script's loops.

FeaturePine ScriptPineTS (JS/TS)
For Loopfor i = 0 to 10for (let i = 0; i <= 10; i++)
While Loopwhile i < 10while (i < 10)

Example: For Loop

Pine Script:

```javascript float sum = 0.0 for i = 0 to 9 sum := sum + close[i] ```

PineTS:

```javascript let sum = 0.0; for (let i = 0; i < 10; i++) { sum += close[i]; } ```

Control Structures

Switch Statement

PineTS supports the JavaScript switch statement, which is equivalent to Pine Script's switch.

Pine Script:

```javascript switch type "ema" => ta.ema(close, len) "sma" => ta.sma(close, len) => ta.rma(close, len) ```

PineTS:

```javascript switch (type) { case 'ema': return ta.ema(close, len); case 'sma': return ta.sma(close, len); default: return ta.rma(close, len); } ```

Functions

User-defined functions in PineTS are written as standard JavaScript functions.

Pine Script:

```javascript f_ma(source, length) => ta.sma(source, length) ```

PineTS:

```javascript function f_ma(source, length) { return ta.sma(source, length); } ```

Tuples and Multiple Return Values

Pine Script allows functions to return multiple values (tuples). PineTS handles this using array destructuring.

Pine Script:

```javascript [macdLine, signalLine, histLine] = ta.macd(close, 12, 26, 9) ```

PineTS:

```javascript const [macdLine, signalLine, histLine] = ta.macd(close, 12, 26, 9); ```

Series and History Access

Accessing historical values is done using the [] operator in Pine Script. In PineTS, array access syntax is supported and transpiled to safe series access.

FeaturePine ScriptPineTS (JS/TS)Notes
Current ValueclosecloseReferences the current bar's value.
Previous Valueclose[1]close[1]References the value 1 bar ago.
History Accessclose[10]close[10]References the value 10 bars ago.

PineTS:

```javascript // Calculate momentum let mom = close - close[10]; ```

Conditional Logic

PineTS supports standard JavaScript control flow, which maps to Pine Script's execution model.

FeaturePine ScriptPineTS (JS/TS)Notes
If Statementif condition    ...if (condition) {    ...}Standard JS syntax.
Ternarycond ? val1 : val2cond ? val1 : val2Standard JS syntax.

Example: Trend Direction

Pine Script:

```javascript if close > open direction := 1 else direction := -1 ```

PineTS:

```javascript if (close > open) { direction = 1; } else { direction = -1; } ```

Built-in Variables

PineTS exposes Pine Script's built-in variables through the context object, but usually, you destructure them for easier access.

VariablePine ScriptPineTS (JS/TS)
Close Pricecloseclose (from context.data)
Open Priceopenopen (from context.data)
High Pricehighhigh (from context.data)
Low Pricelowlow (from context.data)
Volumevolumevolume (from context.data)
Bar Indexbar_indexbar_index (from context.pine)

PineTS Setup:

```javascript const { close, high, low } = context.data; const { bar_index } = context.pine; ```

Functions and Namespaces

PineTS organizes built-in functions into namespaces similar to Pine Script v5.

NamespacePine ScriptPineTS (JS/TS)Example
Technical Analysista.*ta.*ta.sma(close, 14)
Mathmath.*math.*math.max(high, low)
Requestrequest.*request.*request.security(...)

PineTS Setup:

```javascript const { ta, math } = context.pine; // Usage const sma = ta.sma(close, 14); ```

Full Example: Parabolic SAR

This example demonstrates var for state, if/else logic, and history access.

Pine Script:

```javascript pine_sar(start, inc, max) => var float result = na var float maxMin = na var float acceleration = na var bool isBelow = false bool isFirstTrendBar = false

if bar_index == 1
    if close > close[1]
        isBelow := true
        maxMin := high
        result := low[1]
    else
        isBelow := false
        maxMin := low
        result := high[1]
    isFirstTrendBar := true
    acceleration := start

// ... logic continues ...
result

```

PineTS:

```javascript function pine_sar(start, inc, max) { // Use 'var' for state variables (persistent) var result = na; var maxMin = na; var acceleration = na; var isBelow = false;

// Use 'let' for temporary variables (reset every bar)
let isFirstTrendBar = false;

if (bar_index == 1) {
    if (close > close[1]) {
        isBelow = true;
        maxMin = high;
        result = low[1];
    } else {
        isBelow = false;
        maxMin = low;
        result = high[1];
    }
    isFirstTrendBar = true;
    acceleration = start;
}

// ... logic continues ...

return result;

} ```

Stocks
Predict
Watch
Copy
Portfolio
Settings