Розробка кастомних індикаторів теханалізу
Кастомний індикатор — це візуалізація власної торговельної логіки, якої немає у стандартному набірі TradingView або MetaTrader. Це може бути модифікація відомого індикатора, composite індикатор з кількох факторів, або принципово новий метрика. Розберемось як це правильно будувати.
Анатомія торгового індикатора
Індикатор приймає OHLCV дані, виробляє обчислення та повертає серії значень для відображення. Технічно — це чиста функція від даних.
from dataclasses import dataclass
import pandas as pd
import numpy as np
@dataclass
class IndicatorOutput:
values: pd.Series
signal_line: pd.Series = None
histogram: pd.Series = None
upper_band: pd.Series = None
lower_band: pd.Series = None
signals: pd.Series = None # BUY/SELL маркери
Приклад: Hull Moving Average
HMA швидше реагує на зміну тренду і менше лагує ніж EMA. Розрахунок:
def hull_ma(close: pd.Series, period: int = 20) -> pd.Series:
"""
HMA = WMA(2 * WMA(close, period/2) - WMA(close, period), sqrt(period))
"""
half_period = int(period / 2)
sqrt_period = int(np.sqrt(period))
wma_half = close.ewm(span=half_period, adjust=False).mean()
wma_full = close.ewm(span=period, adjust=False).mean()
raw_hma = 2 * wma_half - wma_full
hma = raw_hma.ewm(span=sqrt_period, adjust=False).mean()
return hma
Приклад: Composite Momentum Score
Об'єднуємо кілька моментум індикаторів в один нормалізований score:
def composite_momentum_score(df: pd.DataFrame) -> pd.Series:
"""
Composite score від -100 до +100.
Позитивний = моментум вверх, негативний = вниз.
"""
# RSI нормалізуємо до [-1, 1]
rsi = (df['close'].diff(1).apply(lambda x: max(x, 0)).rolling(14).mean() /
df['close'].diff(1).abs().rolling(14).mean()) * 2 - 1
# Rate of Change нормалізований
roc_14 = df['close'].pct_change(14)
roc_z = (roc_14 - roc_14.rolling(100).mean()) / roc_14.rolling(100).std()
roc_norm = roc_z.clip(-2, 2) / 2 # нормалізуємо до [-1, 1]
# Williams %R нормалізований
highest_high = df['high'].rolling(14).max()
lowest_low = df['low'].rolling(14).min()
williams_r = ((highest_high - df['close']) / (highest_high - lowest_low) - 0.5) * -2
# Зважена комбінація
score = (rsi * 0.35 + roc_norm * 0.40 + williams_r * 0.25) * 100
return score.round(1)
Реалізація в Pine Script (TradingView)
//@version=5
indicator("Composite Momentum Score", shorttitle="CMS", overlay=false)
rsi_length = input.int(14, "RSI Length")
roc_length = input.int(14, "ROC Length")
norm_window = input.int(100, "Normalization Window")
// RSI нормалізований
gain = math.max(ta.change(close), 0)
loss = math.abs(math.min(ta.change(close), 0))
avg_gain = ta.rma(gain, rsi_length)
avg_loss = ta.rma(loss, rsi_length)
rs = avg_gain / avg_loss
rsi_norm = (100 / (1 + rs) - 50) / 50 * -1 // до [-1, 1], перевернуто
// ROC нормалізований
roc = (close - close[roc_length]) / close[roc_length]
roc_mean = ta.sma(roc, norm_window)
roc_std = ta.stdev(roc, norm_window)
roc_z = (roc - roc_mean) / roc_std
roc_norm = math.max(-1, math.min(1, roc_z / 2))
// Composite Score
score = (rsi_norm * 0.35 + roc_norm * 0.40) * 100
// Візуалізація
hline(0, color=color.gray, linewidth=1)
hline(50, color=color.new(color.green, 70), linewidth=1)
hline(-50, color=color.new(color.red, 70), linewidth=1)
score_color = score > 0 ? color.new(color.green, 30) : color.new(color.red, 30)
plot(score, "CMS", color=score_color, linewidth=2)
Приклад: Order Flow Imbalance Indicator
Дисбаланс між bid та ask обсягом — опережаючий індикатор руху ціни:
def order_flow_imbalance(df: pd.DataFrame, window: int = 10) -> pd.Series:
"""
Використовує OHLCV дані як наближення order flow.
Більш точно — з tick data, але й так дає корисний сигнал.
"""
# Наближення buy/sell volume з тіла свічки
candle_range = df['high'] - df['low']
candle_range = candle_range.replace(0, np.nan)
# Частина обсягу пропорційна положенню close у діапазоні
close_position = (df['close'] - df['low']) / candle_range
buy_vol_approx = df['volume'] * close_position
sell_vol_approx = df['volume'] * (1 - close_position)
# OFI = (buy_vol - sell_vol) / total_vol
ofi = (buy_vol_approx - sell_vol_approx) / df['volume']
ofi_smooth = ofi.rolling(window).mean()
return ofi_smooth * 100 # у відсотках
Публікація на TradingView
Можна публікувати кастомні індикатори в TradingView Pine Script library:
- Написати на Pine Script v5
- Додати опис та приклади використання
- Publish as Public Script (безкоштовно) або Protected (скритий код)
- Користувачі додають через пошук індикаторів
Для комерційних індикаторів — TradingView не надає монетизацію напрямо. Альтернатива: продажа через власний сайт (Gumroad, Stripe) з invite-only access.
Кастомний індикатор з унікальною логікою та якісною документацією — це актив. Популярні індикатори на TradingView збирають десятки тисяч підписчиків і служать потужним каналом привлечення клієнтів для торговельних продуктів.







