MobChart
EN / DE / FR / RU / UA
What do we do?
Workspaces
Chart
Screeners
API for Custom Indicators

📘 API для користувацьких індикаторів

🤖 ШІ для генерації користувацьких індикаторів

Використовуйте наступний документ із ChatGPT, Claude, Gemini або іншими ШІ-моделями для генерації користувацьких індикаторів для MobChart.

👉 AI.txt

Приклад запиту:

Прочитай прикріплений файл AI.txt:
https://mobchart.com/docs/public/AI.txt
Використовуй його як єдине джерело інформації про API скриптингу MobChart.
Створи користувацький індикатор, який відображає EMA з періодами 20 і 50 на графіку. Зафарбуй свічки в зелений колір, якщо EMA20 знаходиться вище EMA50, і в червоний — в іншому випадку.
Використовуй лише документований API. Не вигадуй функції. Поверни повний код індикатора.

🔒 Принципи безпеки та поточні обмеження

  • Середовище виконання скриптів побудоване на безпечній JavaScript-пісочниці.
  • На виконання вашого скрипту виділяється 1500ms.
  • Довжина масиву повернених даних не більше 1500. Таким чином, індикатор не може поширюватися глибше ніж на 1500 свічок.
  • Доступно 8 звернення до джерела даних у межах одного індикатора.

⚒️ Розробка індикатора

Розробка індикатора ведеться всередині окремого віджета, який може розташовуватися поруч із графіком, у якому буде ввімкнено даний індикатор.


🧭 Створення індикатора

define(title, description, type, isPublic, isPublicCode)

Реєструє індикатор у системі.

ПараметрТипОпис
titlestringНазва індикатора
descriptionstringКороткий опис
type'onchart' | 'offchart'Розташування індикатора (на графіку або в окремій панелі)
isPublictrue | falseІндикатор доступний усім
isPublicCodetrue | falseВихідний код індикатора доступний усім

Приклад:

define("My Indicator", "Shows EMA line", "onchart", true, false);

Розташування індикаторів при onchart та offchart:

⚙️ Введення параметрів

Класи input та style дозволяють створювати налаштування для користувача (аналог input() у PineScript).

МетодОпис
number(title, defaultValue, min, max, step)Числове введення
range(title, defaultValue, min, max, step)Введення з діапазону
select(title, defaultValue, values)Випадний список
color(title, defaultValue)Вибір кольору
boolean(title, defaultValue)Двійкова змінна

Приклад (input) для основних параметрів:

const length = input.number("Period", 14, 1, 100, 1);
const type = input.select("Type", 'sma', ['sma', 'ema']);
const color = input.color("Line Color", "#FF0000");

Або (style) для візуальних параметрів:

const length = style.number("Size", 14, 1, 100, 1);
const color = style.select("Background Color", '#FF0000', ["#FF0000", "#AA0000", "#BB0000"]);
const color = style.color("Background Color", "#FF0000");

🧮 Джерела даних

Клас source використовується для отримання ринкових даних із серверного боку.

Ми не завжди гарантуємо повну відповідність повернених даних видимим свічкам на графіку.

Наприклад, під час виконання скрипту метод ohlcv() може повернути 400 свічок, але лише 300 лімітних ордерів (для теплової карти) від методу depths(). Використовуйте додаткові перевірки за параметром startTime у своєму коді.

Наразі довжина масиву повернених даних не більше 1500.
Таким чином, індикатор не може поширюватися глибше ніж на 1500 свічок.

Наразі дозволено 8 звернення до джерела даних у межах одного індикатора.

Параметри exchange, ticker, timeframe за замовчуванням прив’язані до поточного графіка, на якому було відкрито індикатор.
Параметр lookback (вибірка історії барів від поточної дати, але не більше 1500) задається на ваш розсуд.

Метод "ohlcv"Опис
ohlcv(exchange, ticker, timeframe, lookback?)Дані свічок
[
{
"open": 115886.17,
"high": 115911.96,
"low": 115764.27,
"close": 115815.16,
"volume": 228.41528,
"startTime": 1757699100000
},
{...},
...
]
Метод "depths"Опис
depths(exchange, ticker, timeframe, lookback?)Лімітні заявки
[
{
"data": {
"asks": {
"109425": 5.467,
"109495": 3.564,
...
},
"bids": {
"33000": 3.746,
"35000": 16.49,
...
}
},
"startTime": 1757699100000
},
{...},
...
]
Метод "clusters"Опис
clusters(exchange, ticker, timeframe, lookback?)Кластерні дані
[
{
"data": {
"totalBuy": 16053385,
"totalSell": 20490989,
"0.8654": { "buy": 286845, "sell": 336689 },
"0.8653": { "buy": 271848, "sell": 259167 },
"0.8652": { "buy": 318814, "sell": 373497 },
...
},
"startTime": 1757699100000
},
{...},
...
]
Метод "liquidations"Опис
liquidations(exchange, ticker, timeframe, lookback?)Ліквідації
[
{
"data": {
"totalBuy": 16053385,
"totalSell": 20490989,
"0.8654": { "buy": 286845, "sell": 336689 },
"0.8653": { "buy": 271848, "sell": 259167 },
"0.8652": { "buy": 318814, "sell": 373497 },
...
},
"startTime": 1757699100000
},
{...},
...
]
Метод "moreData"Опис
moreData(exchange, ticker, timeframe, lookback?)Додаткові дані
[
{
"data": {
"FR": 0.00003777, // Funding Rate
"OI": { // Open Interest Candle
"open": 85645.708,
"close": 83496.225,
"high": 85801.04,
"low": 83397.918
},
"LS": { "l": 0.5426, "s": 0.4574 }, // Long/Short Ratio
"taLS": { "l": 0.552, "s": 0.448 }, // Top Traders Account Ratio
"tpLS": { "l": 0.5996, "s": 0.4004 } // Top Traders Position Ratio
},
"startTime": 1757699100000
},
{...},
...
]

Приклад:

const candles = source.ohlcv(); // Параметри exchange, ticker, timeframe за замовчуванням прив’язані до поточного графіка.
const closes = candles.map(c => c.close);

🌐 Глобальні змінні

ЗміннаОписПриклад
currentExchangeПоточна біржа на графікуbinance, binanceFutures, coinbase, ...
currentTickerПоточний тикер на графіку (формат залежить від біржі)BTCUSDT, ADA-USD, BTC/USDC, ...
currentTimeframeПоточний таймфрейм на графіку1m, 5m, 15m, ...

Приклад:

const candles = source.ohlcv(currentExchange, currentTicker, currentTimeframe);
const closes = candles.map(c => c.close);

🧾 Логування

Клас logger використовується для виведення інформації та налагодження.

МетодОпис
log(...args)Додає запис до логу (з обмеженням довжини та кількості)

Приклад:

const candles = source.ohlcv();
logger.log("First candle:", candles?.[0]);

📈 Візуалізація

Клас plot відповідає за відображення графічних елементів і серій даних.

🔹 Геометричні фігури

МетодОпис
box(title, date1, price1, date2, price2, fill, opacity, stroke, strokeOpacity, strokeWidth)Прямокутник
square(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)Квадрат
diamond(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)Ромб
triangle(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)Трикутник
circle(title, date1, price1, radius = 10, fill, opacity, stroke, strokeOpacity, strokeWidth)Коло
text(title, value, date1, price1, fontSize, fill, opacity)Текст на графіку
straightLine(title, date1, price1, date2, price2, stroke, strokeOpacity, strokeWidth, strokeDasharray)Пряма лінія
ПараметрТип данихОпис
titlestringНазва елемента (унікальний ідентифікатор на графіку)
date1number (timestamp, ms)Початкова часова мітка
price1numberПочаткова ціна (координата по осі Y)
date2number (timestamp, ms)Кінцева часова мітка (для ліній і прямокутників)
price2numberКінцева ціна (для ліній і прямокутників)
sizenumberРозмір фігури (у пікселях)
radiusnumberРадіус кола (за замовчуванням 10)
fillstring (hex, наприклад "#FF0000")Колір заливки фігури
opacitynumber (0–1)Прозорість заливки
strokestring (hex, наприклад "#000000")Колір обвідки
strokeOpacitynumber (0–1)Прозорість обвідки
strokeWidthnumberТовщина лінії обвідки (у пікселях)
strokeDasharrayarray (наприклад [5,5])Стиль пунктирної лінії
fontSizenumberРозмір тексту (у пікселях)
valuestringТекстове значення (для методу text)

Приклад:

plot.text("Text object", "Hello world!", 1757699100000, 115000, 10, "#00C8FF", 0.5);
plot.straightLine(`${namePrefix} Open`, level.timeStart, level.open, level.timeEnd, level.open, color);
plot.circle(`${namePrefix} High`, level.timeStart, level.high, 3, color);

На графіку можна відобразити не більше ніж 3000 фігур.


🔹 Серії даних

МетодОпис
lineSeries(title, values, stroke, strokeOpacity, strokeWidth, strokeDasharray)Лінійний графік
barSeries(title, values, fill, opacity)Гістограма
candleSeries(title, openValues, closeValues, highValues, lowValues, fill, opacity)Свічки

Приклад:

plot.lineSeries("EMA", ta.ema(closes, 20), "#00C8FF");
plot.barSeries("Premium %", premiumPercents, ((d) => d > 0 ? color1 : color2), 1);
plot.candleSeries(
"Candles",
opens, closes, highs, lows,
(v, i) => {
return opens?.[i] > closes?.[i] ? colorBuy : colorSell
}
);

На графіку можна відобразити не більше ніж 10 серій даних.


📊 Технічний аналіз

Клас ta містить набір функцій, аналогічних PineScript.

🔹 Допоміжні

МетодОпис
highest(values, period)Максимум за період
lowest(values, period)Мінімум за період
variance(values, period)Дисперсія
stdev(values, period)Стандартне відхилення
crossover(series1, series2)Перетин вгору
crossunder(series1, series2)Перетин вниз
cross(series1, series2)Будь-який перетин

🔹 Рухомі середні

МетодОпис
sma(values, period)Проста рухома середня
ema(values, period)Експоненційна рухома середня
wma(values, period)Зважена рухома середня

🔹 Індикатори

МетодОпис
rsi(values, period)Індекс відносної сили
macd(values, fast, slow, signalPeriod)MACD
bollinger(values, period, mult)Смуги Боллінджера
stoch(highs, lows, closes, period, smoothK, smoothD)Стохастичний осцилятор
atr(highs, lows, closes, period)Середній істинний діапазон
adx(highs, lows, closes, period)Індекс спрямованого руху
cci(highs, lows, closes, period)Індекс товарного каналу
vwap(highs, lows, closes, volumes)Об’ємно-зважена середня ціна

Приклад:

const candles = source.ohlcv();
const closes = candles.map(c => c.close);
const rsiValues = ta.rsi(closes, 14);
plot.lineSeries("RSI", rsiValues, "#00C8FF");

🔔 Alerts

Users can create alerts for your indicator from the Alerts tab in the indicator settings on the chart. Alerts are checked on the server side every 30 seconds, notifications are sent to Telegram and/or a user defined Webhook URL.

⚙️ Alert Settings — alertInput

The alertInput class declares alert settings. It works exactly like input, but the fields are shown in the Alerts tab and every user configures their own values for their alert.

Scripts without alertInput declarations can not be used for alerts.

MethodDescription
number(title, defaultValue, min, max, step)Numeric input
range(title, defaultValue, min, max, step)Range input
select(title, defaultValue, values)Dropdown selection
color(title, defaultValue)Color picker
boolean(title, defaultValue)Boolean input

Example:

const alertVolumeThreshold = alertInput.number("Volume threshold", 1000, 0, 10000000, 1);

🚨 Firing Alerts — alert.fire

MethodDescription
fire(title, message, date)Fires an alert notification
  • All three parameters are required — a call with a missing title, message or date is skipped (a warning is written to the log).
  • Keep the alert title constant, do not generate unique titles. Each title fires only once per run (max 20 titles per run).
  • date is the candle startTime the signal belongs to: the same title notifies again only when it fires for a newer candle. Signals from candles older than the moment the user created their alert are ignored (anti-spam).

Example:

if (candle.volume > alertVolumeThreshold) {
alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);
}

📐 Shape Alerts — plot.<shape>(...).alert(...)

All geometric shapes (box, square, diamond, triangle, circle, straightLine, text) return a handle with an .alert() method. The alert fires with the shape's date1 automatically, so the anti-spam logic works without extra code — this is the recommended way for per-candle signals.

Two forms:

// simple: fires every time the shape is plotted for a new date
plot.box(...).alert("High volume", `vol ${candle.volume}`);
// callback: return nothing to skip, [title, message] to fire
plot.box(...).alert((shape) => {
if (candle.volume > alertVolumeThreshold)
alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);
});

The callback receives the shape data (date1, price1, date2, price2, ...).

📈 Series Alerts — plot.<series>(...).alert(...)

Data series (lineSeries, barSeries, candleSeries) also return the .alert() handle. The callback receives the latest data point and the latest candle date, the alert fires with that date.

  • lineSeries / barSeries — the callback receives the last value (a number)
  • candleSeries — the callback receives the last candle {open, close, high, low}
plot.lineSeries("RSI", rsiValues, color).alert((rsi, date) => {
if (rsi > alertRsiThreshold) alert.fire("RSI high", `RSI ${rsi.toFixed(1)}`, latestCandle.startTime);
});

A condition that stays true notifies once per new candle. For one-time signals use crossover-style conditions (ta.crossover).

🧩 Full Example

const title = "Volume alerts";
const description = "Shows boxes on high-volume candles";
define(title, description, "onchart", true, true);
const color = style.color("Color", "#00C8FF");
const volumeThreshold = input.number("Volume threshold", 1000, 0, 10000000, 1);
const alertVolumeThreshold = alertInput.number("Alert volume threshold", 5000, 0, 10000000, 1);
const alertCloseThreshold = alertInput.number("Alert close threshold", 100000, 0, 10000000, 1);
const candles = source.ohlcv();
const latestCandle = candles.at(-1);
const closes = candles.map(c => c.close);
// series alert: checks the latest close
plot.lineSeries("Closes", closes, color).alert((close, date) => {
if (close > alertCloseThreshold) alert.fire("Close above threshold", `close ${close}`, latestCandle.startTime);
});
for (let i = 0; i < candles.length; i++) {
const candle = candles[i];
if (candle.volume > volumeThreshold) {
const right = i < candles.length - 1 ? candles[i + 1].startTime : candle.startTime + 60000;
// shape alert: checked against the user's alert threshold
plot.box(`Volume ${i}`, candle.startTime, candle.high, right, candle.low, "#00C8FF", 0.3)
.alert(() => {
if (candle.volume > alertVolumeThreshold)
alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);
});
}
}

🧠 Приклади індикаторів

const title = "Your first indicator";
const description = "Shows closes lines on the chart";
const indicatorType = "onchart";
define(title, description, type, true, true);
const color = input.color("Line Color", "#00C8FF");
const candles = source.ohlcv();
const closes = candles.map(c => c.close);
plot.lineSeries("Closes", closes, color);
define("Example Indicator", "Demonstrates basic plotting", "onchart", true, true);
const color = input.color("Line Color", "#00FF99");
const candles = source.ohlcv();
const closes = candles.map(c => c.close);
const ema20 = ta.ema(closes, 20);
plot.lineSeries("EMA 20", ema20, color);
const title = "Colored Volume Bars";
const description = "Volumes colored based on candle direction.";
const indicatorType = "onchart";
const isPublic = true;
const isPublicCode = true;
define(title, description, indicatorType, isPublic, isPublicCode);
// Get OHLC candles
const candles = source.ohlcv();
const colorUp = style.color("Color 1", "#2BB462"); // Greenish color for rising prices
const colorDown = style.color("Color 2", "#FB4C51"); // Reddish color for falling prices
const volumes = candles.map(candle => candle.volume);
plot.barSeries("Volume", volumes, (value, index) => {
const currentCandle = candles[index];
return currentCandle.close >= currentCandle.open ? colorUp : colorDown;
});
define('Coinbase Premium Index', 'Coinbase Premium Index', 'offchart', true, false);
const color1 = style.color("Color 1", "#2BB462");
const color2 = style.color("Color 2", "#FB4C51");
// Get OHLC candles
const cbCandles = source.ohlcv('coinbase', 'BTC-USD');
const binanceCandles = source.ohlcv('binance', 'BTCUSDT');
// Extract closes
const cbCloses = cbCandles.map(c => c.close);
const binanceCloses = binanceCandles.map(c => c.close);
// --- Coinbase Premium Index calculation ---
const premiumPercent = cbCloses.map((cb, i) => {
const b = binanceCloses[i];
return ((cb - b) / b) * 100;
});
// Plot premium index
plot.barSeries("Premium %", premiumPercent, ((d) => d > 0 ? color1 : color2)) // Percentage difference
const title = "Candles";
const description = "Simple candles draw";
const indicatorType = "offchart";
const isPublic = true;
const isPublicCode = true;
define(title, description, indicatorType, isPublic, isPublicCode);
const colorBuy = style.color("Buy Color", "#2BB462");
const colorSell = style.color("Sell Color", "#7a3d3f");
const candles = source.ohlcv();
const closes = candles.map(c => c.close);
const opens = candles.map(c => c.open);
const highs = candles.map(c => c.high);
const lows = candles.map(c => c.low);
plot.candleSeries(
"Candles",
opens, closes, highs, lows,
(v, i) => {
return opens?.[i] > closes?.[i] ? colorBuy : colorSell
}
);