Plugin API Reference
This page documents the technical interface for Stratosfi chart plugins. It covers plugin structure, the calculate() function, input types, output format, the ta.* technical analysis library, and server-side plugin features.
Plugin Structure
Every plugin consists of two parts:
- Manifest — metadata describing the plugin (name, category, inputs)
- Calculate function — a pure function that receives price data and returns rendering output
const manifest = {
name: 'my-indicator',
displayName: 'My Custom Indicator',
description: 'What this indicator does',
category: 'overlay', // 'overlay' | 'oscillator' | 'volume' | 'strategy' | 'special'
display: 'overlay', // 'overlay' (on chart) | 'panel' (separate panel below)
inputs: [
{ id: 'period', type: 'number', default: 14, min: 2, max: 200, label: 'Period' },
{ id: 'color', type: 'color', default: '#2196F3', label: 'Color' },
],
};
function calculate(data, inputs, context) {
// Your calculation logic here
return { lines, markers, fills, hlines, histograms };
}Input Data
The data parameter provides OHLCV price data in columnar format — each field is an array of numbers, all the same length:
| Field | Type | Description |
|---|---|---|
data.time[] | number[] | Unix timestamps (seconds) |
data.open[] | number[] | Opening prices |
data.high[] | number[] | Highest prices |
data.low[] | number[] | Lowest prices |
data.close[] | number[] | Closing prices |
data.volume[] | number[] | Trading volume |
All arrays share the same index — data.close[i] is the closing price at time data.time[i].
Input Types
Plugins declare their configurable parameters in manifest.inputs. Each input has an id, type, default, and label. The resolved values are passed as the inputs parameter to calculate().
| Type | Description | Extra Fields |
|---|---|---|
number | Numeric input with slider | min, max |
color | Color picker (hex string) | — |
boolean | Toggle switch | — |
select | Dropdown menu | options (string array) |
Example input definitions:
inputs: [
{ id: 'period', type: 'number', default: 20, min: 2, max: 500, label: 'Period' },
{ id: 'color', type: 'color', default: '#FF9800', label: 'Line Color' },
{ id: 'showTable', type: 'boolean', default: true, label: 'Show Table' },
{ id: 'method', type: 'select', default: 'standard', label: 'Method',
options: ['standard', 'fibonacci', 'woodie'] },
]Return Format
The calculate() function returns an object with any combination of these fields:
Lines
Arrays of data points drawn as continuous lines. Used for moving averages, bands, oscillator values, etc.
lines: [
{
data: [{ time: 1700000000, value: 150.5 }, ...],
color: '#2196F3',
width: 2, // optional, default: 1
label: 'SMA 20', // optional, shown in legend
style: 'dashed', // optional: 'solid' (default) | 'dashed' | 'dotted'
},
]Markers
Individual points on the chart — used for buy/sell signals, pattern markers, etc.
markers: [
{
time: 1700000000,
position: 'above', // 'above' | 'below' the candle
shape: 'arrow', // 'circle' | 'arrow'
color: '#4CAF50',
text: 'BUY', // optional label
},
]Fills
Colored regions between two lines (e.g., Bollinger Band fill, Ichimoku Cloud).
fills: [
{
upper: 0, // index into the lines array
lower: 1, // index into the lines array
color: 'rgba(33, 150, 243, 0.1)',
},
]Horizontal Lines (hlines)
Static horizontal reference lines — used for overbought/oversold levels, zero line, etc.
hlines: [
{ value: 70, color: '#EF5350', width: 1, style: 'dashed' },
{ value: 30, color: '#4CAF50', width: 1, style: 'dashed' },
]Histograms
Bar charts rendered in panels — used for MACD histogram, volume-based indicators, etc.
histograms: [
{
data: [{ time: 1700000000, value: 0.5, color: '#4CAF50' }, ...],
label: 'MACD Histogram',
},
]Tables
On-chart tables for displaying multi-value dashboards, current indicator readings, or status summaries directly on the price chart.
tables: [
{
position: 'top-right', // 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
title: 'Multi-TF Dashboard',
columns: ['Timeframe', 'RSI', 'MACD', 'Trend'],
rows: [
['1H', '45.2', 'Bullish', 'Up'],
['4H', '52.1', 'Bearish', 'Down'],
['Daily', '61.8', 'Bullish', 'Up'],
],
},
]Earnings Markers
Special markers for earnings report dates, rendered as HTML overlays at the bottom of the chart.
earningsMarkers: [
{
time: 1700000000,
type: 'beat', // 'beat' | 'miss' | 'inline'
color: '#4CAF50',
label: '$1.52',
earning: { /* full earnings data */ },
},
]Technical Analysis Library (ta.*)
All plugins have access to the ta library — a collection of financial math functions that operate on arrays of numbers. In AI-generated plugins, these functions are available as top-level globals (e.g., sma(data.close, 20) instead of ta.sma(...)).
Moving Averages
| Function | Signature | Description |
|---|---|---|
sma | sma(source, period) | Simple Moving Average |
ema | ema(source, period) | Exponential Moving Average — more responsive to recent prices |
rma | rma(source, period) | Running Moving Average (Wilder's smoothing) — used internally by RSI and ATR |
Volatility & Range
| Function | Signature | Description |
|---|---|---|
stdev | stdev(source, period) | Standard deviation over a rolling window |
trueRange | trueRange(high, low, close) | True Range — accounts for gaps |
atr | atr(high, low, close, period) | Average True Range — RMA of True Range |
Lookback
| Function | Signature | Description |
|---|---|---|
highest | highest(source, period) | Highest value in the lookback window |
lowest | lowest(source, period) | Lowest value in the lookback window |
Price Changes
| Function | Signature | Description |
|---|---|---|
diff | diff(source) | Element-wise difference: source[i] - source[i-1] |
gain | gain(source) | Positive changes only (0 for down bars) |
loss | loss(source) | Absolute negative changes (0 for up bars) |
Crossover Detection
| Function | Signature | Description |
|---|---|---|
crossover | crossover(a, b) | Returns true at indices where a crosses above b |
crossunder | crossunder(a, b) | Returns true at indices where a crosses below b |
Aggregation
| Function | Signature | Description |
|---|---|---|
sum | sum(source, period) | Rolling sum over a window |
typicalPrice | typicalPrice(high, low, close) | (High + Low + Close) / 3 |
meanDeviation | meanDeviation(source, period) | Mean absolute deviation from SMA |
Composite Indicators
These are higher-level functions that return multiple arrays:
| Function | Signature | Returns |
|---|---|---|
rsi | rsi(source, period) | number[] — RSI values (0-100) |
macd | macd(source, fast, slow, signal) | { macd, signal, histogram } — three arrays |
bollinger | bollinger(source, period, mult) | { upper, middle, lower } — three arrays |
stochastic | stochastic(high, low, close, kPeriod, dPeriod) | { k, d } — two arrays |
obv | obv(close, volume) | number[] — cumulative OBV |
vwap | vwap(high, low, close, volume) | number[] — VWAP values |
adx | adx(high, low, close, period) | number[] — ADX values (0-100) |
Usage Example
function calculate(data, inputs) {
const smaLine = sma(data.close, inputs.period);
const rsiVals = rsi(data.close, 14);
const bb = bollinger(data.close, 20, 2);
return {
lines: [
{ data: smaLine.map((v, i) => ({ time: data.time[i], value: v })),
color: inputs.color, label: `SMA ${inputs.period}` },
],
};
}Context Object
The third parameter to calculate() provides external data that goes beyond OHLCV:
function calculate(data, inputs, context) {
// context.earnings — array of earnings data (if resources.apis includes 'earnings')
// context.chart.symbol — current ticker symbol
// context.chart.range — current date range
// context.chart.interval — current candle interval
}Available Context Properties
| Property | Type | Description |
|---|---|---|
context.earnings | object[] | Earnings data (EPS actual/estimate, surprise, date) |
context.chart.symbol | string | Current chart symbol (e.g., "AAPL") |
context.chart.range | string | Current date range (e.g., "1Y", "3M") |
context.chart.interval | string | Current candle interval (e.g., "1d", "1h") |
To request external data, declare it in the manifest:
manifest: {
// ...
resources: {
apis: ['earnings'], // requests earnings data be loaded into context
},
}Server-Side Plugins
Plugins that need to fetch external data (prices for other symbols, quotes, etc.) run on the server in a sandboxed environment. Server-side plugins have access to ctx.fetch() for making proxied API calls.
When a Plugin Runs on the Server
A plugin is automatically detected as server-side if:
- The manifest includes
requires: { data: true }orrequires: { fetch: true } - The manifest includes
runtime: 'server' - The code contains
ctx.fetch(...)orctx.fetchOHLCV(...)calls
Sandbox Environment
Server-side plugins execute in a Node.js VM sandbox with:
- Full
ta.*library access Math,JSON,Array,Object(read-only)console.log/console.warnfor debuggingctx.fetch()for approved API calls- Data functions:
ctx.fetchOHLCV(),ctx.fetchQuote(),ctx.fetchEarnings(),ctx.fetchFinancials() - 5-second execution timeout
Not available in the sandbox: require, import, process, global, setTimeout, setInterval, Buffer, native fetch.
Data Functions
Server-side plugins have access to high-level data functions that fetch market data without needing to construct API URLs:
ctx.fetchOHLCV(symbol, options)
Fetches OHLCV price history for any symbol. Returns columnar data in the same format as the data parameter.
const ohlcv = await ctx.fetchOHLCV('QQQ', {
range: ctx.chart.range, // e.g. '1Y'
interval: ctx.chart.interval // e.g. '1d'
});
// Returns: { time[], open[], high[], low[], close[], volume[] }ctx.fetchQuote(symbol)
Fetches real-time quote data for any symbol.
const quote = await ctx.fetchQuote('AAPL');
// Returns: { price, change, changePct, volume, marketCap, ... }ctx.fetchEarnings(symbol)
Fetches earnings history and forward estimates.
const earnings = await ctx.fetchEarnings('TSLA');
// Returns: { history: [{ date, epsActual, epsEstimate, surprise, ... }], ... }ctx.fetchFinancials(symbol)
Fetches financial statements.
const financials = await ctx.fetchFinancials('MSFT');
// Returns: { income: [...], balance: [...], cashflow: [...], keyStats, ... }Server-Side Plugin Example
Here is a plugin that overlays another symbol's price on the chart for comparison:
const manifest = {
name: 'symbol-overlay',
displayName: 'Symbol Overlay',
category: 'special',
display: 'overlay',
runtime: 'server',
requires: { data: true },
inputs: [
{ id: 'symbol', type: 'text', default: 'QQQ', label: 'Symbol' },
{ id: 'color', type: 'color', default: '#FF9800', label: 'Color' },
],
};
async function calculate(data, inputs, ctx) {
const ohlcv = await ctx.fetchOHLCV(inputs.symbol, {
range: ctx.chart.range,
interval: ctx.chart.interval,
});
return {
lines: [{
data: ohlcv.time.map((t, i) => ({ time: t, value: ohlcv.close[i] })),
color: inputs.color,
label: inputs.symbol,
}],
};
}Complete Plugin Example
Here is a full plugin that combines RSI with a moving average and generates buy/sell signals:
const manifest = {
name: 'rsi-ma-signals',
displayName: 'RSI + MA Signal',
description: 'Buy when RSI crosses above oversold and price is above SMA',
category: 'strategy',
display: 'overlay',
inputs: [
{ id: 'rsiPeriod', type: 'number', default: 14, min: 2, max: 100, label: 'RSI Period' },
{ id: 'smaPeriod', type: 'number', default: 50, min: 5, max: 200, label: 'SMA Period' },
{ id: 'oversold', type: 'number', default: 30, min: 10, max: 50, label: 'Oversold Level' },
{ id: 'overbought', type: 'number', default: 70, min: 50, max: 90, label: 'Overbought Level' },
],
};
function calculate(data, inputs) {
const rsiVals = rsi(data.close, inputs.rsiPeriod);
const smaVals = sma(data.close, inputs.smaPeriod);
const oversoldLine = new Array(data.close.length).fill(inputs.oversold);
const buyCross = crossover(rsiVals, oversoldLine);
const overboughtLine = new Array(data.close.length).fill(inputs.overbought);
const sellCross = crossunder(rsiVals, overboughtLine);
const markers = [];
for (let i = 0; i < data.time.length; i++) {
if (buyCross[i] && smaVals[i] != null && data.close[i] > smaVals[i]) {
markers.push({
time: data.time[i], position: 'below',
shape: 'arrow', color: '#4CAF50', text: 'BUY',
});
}
if (sellCross[i]) {
markers.push({
time: data.time[i], position: 'above',
shape: 'arrow', color: '#EF5350', text: 'SELL',
});
}
}
return {
lines: [
{
data: smaVals.map((v, i) => ({ time: data.time[i], value: v })),
color: '#42A5F5', label: `SMA ${inputs.smaPeriod}`, style: 'dashed',
},
],
markers,
};
}Related Features
- Chart Plugins — browse all 40 built-in plugins and learn how to use them
- Charts & Indicators — chart configuration, drawing tools, and time frames
- AI Analysis — use AI to create custom plugins from natural language descriptions