Pine Script Runner

Link to the source code

Pine Script execution and backtesting system using @backtest-kit/pinets and real market data via CCXT.

Demonstrates Pine Script integration capabilities for:

  • Running Pine Script indicators against live market data
  • Multi-symbol data via request.security calls
  • Markdown report generation from plot outputs
  • Exchange-agnostic candle data sourcing through CCXT
  • Pine Script Execution: Run .pine indicator files directly from Node.js
  • request.security Support: Fetch higher-timeframe or cross-symbol data inside Pine Script
  • CCXT Integration: Fetch candles from any supported exchange (Binance spot by default)
  • Markdown Output: Render plot results as a formatted markdown table
  • Candle Dump Cache: Local JSON cache of historical candles for offline/repeated runs
  • Runtime: Node.js (ES Modules)
  • Framework: backtest-kit 6.4.0
  • Pine Runner: @backtest-kit/pinets 6.4.0
  • Utilities: functools-kit 1.0.95
  • Data Source: ccxt 4.5.24 (Binance spot)
demo/pinets/
├── math/
│ └── test_request_security.pine # Example Pine Script indicator
├── src/
│ └── index.mjs # Main runner configuration
├── dump/ # Cached candle data (auto-generated)
├── package.json # Dependencies and scripts
└── README.md # This file
# Navigate to project directory
cd demo/pinets

# Install dependencies
npm install

# Run the Pine Script
npm start

The runner is pre-configured in src/index.mjs:

  • Symbol: ETHUSDT
  • Timeframe: 15m
  • Limit: 180 candles
  • Start Date: 2025-09-24T12:00:00.000Z
  • Exchange: Binance spot (via CCXT)
const SIGNAL_SCHEMA = {
position: "Position",
close: "Close",
btcClose: "BTC Close",
};

Maps Pine Script plot names to markdown column headers.

Run the indicator and print markdown output:

npm start

Output:

| Time | Position | Close | BTC Close |
|------|----------|-------|-----------|
| ... | 0 | ... | ... |

Edit src/index.mjs:

const plots = await run(
File.fromPath("test_request_security.pine", "./math"),
{
symbol: "BTCUSDT", // Change symbol
timeframe: "1h", // Change timeframe
limit: 100, // Change candle count
},
"ccxt-exchange",
new Date("2025-10-01T00:00:00.000Z"),
);

Create a new .pine file in ./math/ and reference it in src/index.mjs:

const plots = await run(
File.fromPath("my_indicator.pine", "./math"),
{ symbol: "SOLUSDT", timeframe: "5m", limit: 200 },
"ccxt-exchange",
new Date("2025-10-01T00:00:00.000Z"),
);

addExchangeSchema registers a named exchange that fetches OHLCV candles via CCXT:

addExchangeSchema({
exchangeName: "ccxt-exchange",
getCandles: async (symbol, interval, since, limit) => { ... },
});

run() loads the .pine file, feeds it candles from the registered exchange, and resolves all request.security calls using the same exchange.

toMarkdown() converts the returned plot arrays into a markdown table, keyed by SIGNAL_SCHEMA.

MIT © tripolskypetr