Technical Indicators
Comprehensive guide to all technical indicators available in TradeStaq custom strategies. TradeStaq uses the tulind library, providing access to 100+ professional-grade technical indicators.
Overview
Technical indicators are accessed through td.indicators. The system provides:
- Pre-calculated Indicators - Automatically computed each spin with optimal defaults
- Custom Period Indicators - Use
td.indicators.custom['ema_20']pattern for custom periods - Full Tulind Library - Access to 100+ tulind indicators
- Auto-detection - Platform detects which custom indicators you need from your code
Pre-calculated Indicators
These indicators are automatically calculated each spin with default parameters for best performance.
RSI (Relative Strength Index)
Measures momentum on a scale of 0-100. Default period: 14.
const rsi = td.indicators.rsi; // Current RSI value
const rsiArray = td.indicators.rsiArray; // Historical RSI values
// Interpretation
// < 30: Oversold (potential buy)
// > 70: Overbought (potential sell)
// 30-70: Neutral zone
Example: RSI Divergence Detection
const rsi = td.indicators.rsiArray;
const candles = td.market.candles;
// Price making higher high but RSI making lower high = bearish divergence
const priceHigh1 = candles[candles.length - 10].high;
const priceHigh2 = candles[candles.length - 1].high;
const rsiHigh1 = rsi[rsi.length - 10];
const rsiHigh2 = rsi[rsi.length - 1];
if (priceHigh2 > priceHigh1 && rsiHigh2 < rsiHigh1) {
td.utils.log('Bearish RSI divergence detected');
}
MACD (Moving Average Convergence Divergence)
Trend-following momentum indicator. Default: 12/26/9.
const macd = td.indicators.macd;
macd.line // MACD line (12 EMA - 26 EMA)
macd.signal // Signal line (9 EMA of MACD)
macd.histogram // MACD - Signal
macd.trend // 'bullish' | 'bearish' | 'neutral'
Example: MACD Crossover Strategy
const macd = td.indicators.macd;
const prevHistogram = td.state.get('prevHistogram', 0);
// Detect crossover
const bullishCross = prevHistogram <= 0 && macd.histogram > 0;
const bearishCross = prevHistogram >= 0 && macd.histogram < 0;
td.state.set('prevHistogram', macd.histogram);
if (bullishCross && !td.position.hasPosition) {
td.trade.buy({ reason: 'MACD bullish crossover' });
}
Bollinger Bands
Volatility-based bands around a moving average. Default: 20 period, 2 std dev.
const bb = td.indicators.bbands;
bb.upper // Upper band (middle + 2 std dev)
bb.middle // Middle band (20 SMA)
bb.lower // Lower band (middle - 2 std dev)
bb.width // Band width (volatility measure)
bb.percentB // Price position within bands (0-1)
Example: Bollinger Squeeze Breakout
const bb = td.indicators.bbands;
const price = td.market.price;
// Low volatility squeeze
if (bb.width < 0.02) {
td.state.set('inSqueeze', true);
}
// Breakout from squeeze
if (td.state.get('inSqueeze') && bb.width > 0.03) {
if (price > bb.upper) {
td.trade.buy({ reason: 'BB squeeze breakout (long)' });
} else if (price < bb.lower) {
td.trade.sell({ reason: 'BB squeeze breakout (short)' });
}
td.state.set('inSqueeze', false);
}
ADX (Average Directional Index)
Measures trend strength (not direction). Default period: 14.
const adx = td.indicators.adx;
adx.value // ADX value (0-100)
adx.diPlus // +DI (bullish direction)
adx.diMinus // -DI (bearish direction)
adx.trend // 'strong' (>=25) | 'weak' (20-25) | 'none' (<20)
Example: ADX Trend Filter
const adx = td.indicators.adx;
// Only trade when trend is strong
if (adx.value < 25) {
td.utils.log('No strong trend, skipping');
return;
}
// Determine trend direction
if (adx.diPlus > adx.diMinus) {
// Bullish trend - look for long entries
} else {
// Bearish trend - look for short entries
}
ATR (Average True Range)
Measures market volatility. Default period: 14.
const atr = td.indicators.atr; // Current ATR
const atrArray = td.indicators.atrArray; // Historical ATR
Example: ATR-based Stop Loss
const atr = td.indicators.atr;
const multiplier = td.config.getNumber('ATR_MULTIPLIER', 2);
// Stop loss at 2x ATR from entry
const stopLoss = td.market.price - (atr * multiplier);
td.trade.buy({
amountPercent: 100,
stopLoss: stopLoss,
reason: 'Entry with ATR stop'
});
Supertrend
Trend-following indicator that provides dynamic support/resistance. Default: period 10, multiplier 3.
const supertrend = td.indicators.supertrend;
supertrend.value // Supertrend line value
supertrend.direction // 'up' | 'down'
supertrend.trend // 'bullish' | 'bearish'
supertrend.stopLoss // Same as value (can use as trailing stop)
Example: Supertrend Trend Following
const st = td.indicators.supertrend;
const price = td.market.price;
if (!td.position.hasPosition) {
// Enter long when price crosses above Supertrend
if (st.trend === 'bullish') {
td.trade.buy({
stopLoss: st.stopLoss,
reason: 'Supertrend bullish'
});
}
// Enter short when price crosses below Supertrend
if (st.trend === 'bearish') {
td.trade.sell({
stopLoss: st.stopLoss,
reason: 'Supertrend bearish'
});
}
}
Example: Multi-Timeframe Supertrend Filter
// Use higher timeframe Supertrend as trend filter
const htfSupertrend = td.mtf.indicators(1)?.supertrend;
const ltfRsi = td.indicators.rsi;
if (htfSupertrend?.trend === 'bullish' && ltfRsi < 30) {
td.trade.buy({ reason: 'HTF bullish + RSI oversold' });
}
if (htfSupertrend?.trend === 'bearish' && ltfRsi > 70) {
td.trade.sell({ reason: 'HTF bearish + RSI overbought' });
}
Stochastic Oscillator
Momentum indicator comparing closing price to price range. Default: 14/3.
const stoch = td.indicators.stochastic;
stoch.k // %K line (fast, 0-100)
stoch.d // %D line (slow, 3-period SMA of %K)
stoch.zone // 'overbought' (>=80) | 'oversold' (<=20) | 'neutral'
Example: Stochastic Crossover
const stoch = td.indicators.stochastic;
const prevK = td.state.get('prevK', stoch.k);
const prevD = td.state.get('prevD', stoch.d);
// Bullish crossover in oversold zone
if (stoch.zone === 'oversold' && prevK < prevD && stoch.k > stoch.d) {
td.trade.buy({ reason: 'Stochastic bullish crossover' });
}
td.state.set('prevK', stoch.k);
td.state.set('prevD', stoch.d);
MFI (Money Flow Index)
Volume-weighted RSI. Default period: 14.
const mfi = td.indicators.mfi; // 0-100 scale
// < 20: Oversold
// > 80: Overbought
Pivot Points
Support and resistance levels calculated from previous candle.
const pivots = td.indicators.pivots;
pivots.pivot // Pivot point
pivots.r1 // Resistance 1
pivots.r2 // Resistance 2
pivots.r3 // Resistance 3
pivots.s1 // Support 1
pivots.s2 // Support 2
pivots.s3 // Support 3
Example: Pivot Point Bounce
const pivots = td.indicators.pivots;
const price = td.market.price;
const tolerance = 0.001; // 0.1%
// Buy at S1 support
if (Math.abs(price - pivots.s1) / pivots.s1 < tolerance) {
td.trade.buy({
stopLoss: pivots.s2,
takeProfit: pivots.pivot,
reason: 'S1 support bounce'
});
}
VWAP (Volume Weighted Average Price)
Volume-weighted average price with bands.
const vwap = td.indicators.vwap;
vwap.value // VWAP value
vwap.upperBand // VWAP + 1 standard deviation
vwap.lowerBand // VWAP - 1 standard deviation
vwap.deviation // Current price deviation from VWAP
Example: VWAP Mean Reversion
const vwap = td.indicators.vwap;
const price = td.market.price;
// Buy when price touches lower VWAP band
if (price <= vwap.lowerBand && !td.position.hasPosition) {
td.trade.buy({
takeProfit: vwap.value,
reason: 'VWAP lower band touch'
});
}
Ichimoku Cloud
Comprehensive trend indicator with multiple components.
const ichimoku = td.indicators.ichimoku;
ichimoku.tenkanSen // Conversion Line (9-period)
ichimoku.kijunSen // Base Line (26-period)
ichimoku.senkouSpanA // Leading Span A
ichimoku.senkouSpanB // Leading Span B
ichimoku.chikouSpan // Lagging Span
ichimoku.cloudTop // Higher of Senkou A/B
ichimoku.cloudBottom // Lower of Senkou A/B
ichimoku.trend // 'bullish' | 'bearish' | 'neutral'
ichimoku.priceVsCloud // 'above' | 'below' | 'inside'
Example: Ichimoku Cloud Breakout
const ichimoku = td.indicators.ichimoku;
if (ichimoku.priceVsCloud === 'above' && ichimoku.trend === 'bullish') {
td.trade.buy({ reason: 'Price above bullish cloud' });
}
Donchian Channels
Price channel based on highest high and lowest low.
const donchian = td.indicators.donchian;
donchian.upper // Highest high over period
donchian.lower // Lowest low over period
donchian.middle // (upper + lower) / 2
donchian.width // Channel width as percentage
Keltner Channels
Volatility-based envelope around EMA.
const keltner = td.indicators.keltner;
keltner.upper // EMA + ATR * multiplier
keltner.middle // EMA
keltner.lower // EMA - ATR * multiplier
keltner.width // Channel width as percentage
Chandelier Exit
Trailing stop indicator based on ATR.
const chandelier = td.indicators.chandelier;
chandelier.longStop // Exit for long positions
chandelier.shortStop // Exit for short positions
chandelier.direction // 'long' | 'short'
Example: Chandelier Trailing Stop
const chandelier = td.indicators.chandelier;
if (td.position.side === 'long') {
td.trade.setStopLoss(chandelier.longStop);
}
Heikin Ashi
Smoothed candlestick representation.
const ha = td.indicators.heikinAshi;
ha.open // Heikin Ashi open
ha.high // Heikin Ashi high
ha.low // Heikin Ashi low
ha.close // Heikin Ashi close
ha.trend // 'bullish' | 'bearish' | 'doji'
Squeeze Momentum
Detects low volatility squeezes (BB inside KC).
const squeeze = td.indicators.squeezeMomentum;
squeeze.value // Momentum value
squeeze.squeeze // true if in squeeze (low volatility)
squeeze.momentum // 'increasing' | 'decreasing'
squeeze.histogram // For visualization
Example: Squeeze Breakout
const squeeze = td.indicators.squeezeMomentum;
const prevSqueeze = td.state.get('prevSqueeze', false);
// Breakout from squeeze
if (prevSqueeze && !squeeze.squeeze && squeeze.momentum === 'increasing') {
td.trade.buy({ reason: 'Squeeze breakout' });
}
td.state.set('prevSqueeze', squeeze.squeeze);
Elder Ray
Measures buying and selling pressure.
const elderRay = td.indicators.elderRay;
elderRay.bullPower // High - EMA (buying pressure)
elderRay.bearPower // Low - EMA (selling pressure)
elderRay.trend // 'bullish' | 'bearish' | 'neutral'
Parabolic SAR
Trend-following stop and reverse indicator.
const psar = td.indicators.psar;
psar.value // Current PSAR value
psar.trend // 'bullish' | 'bearish'
psar.reversal // true if trend just reversed
Example: PSAR Trend Following
const psar = td.indicators.psar;
if (psar.reversal && psar.trend === 'bullish') {
td.trade.buy({ stopLoss: psar.value, reason: 'PSAR bullish reversal' });
}
Williams %R
Momentum indicator similar to Stochastic.
const williamsR = td.indicators.williamsR;
williamsR.value // -100 to 0
williamsR.zone // 'overbought' | 'oversold' | 'neutral'
CCI (Commodity Channel Index)
Measures price deviation from average.
const cci = td.indicators.cci;
cci.value // CCI value (typically -200 to +200)
cci.zone // 'overbought' | 'oversold' | 'neutral'
OBV (On-Balance Volume)
Volume-based trend confirmation.
const obv = td.indicators.obv;
obv.value // OBV value
obv.trend // 'accumulation' | 'distribution' | 'neutral'
obv.divergence // 'bullish' | 'bearish' | 'none'
Example: OBV Divergence
const obv = td.indicators.obv;
if (obv.divergence === 'bullish' && td.indicators.rsi < 40) {
td.trade.buy({ reason: 'Bullish OBV divergence' });
}
Market Sentiment Indicators
TradeStaq provides access to market sentiment data through td.market.sentiment.
Fear & Greed Index
The Crypto Fear & Greed Index measures market sentiment on a scale of 0-100.
const sentiment = td.market.sentiment;
const fearGreed = sentiment?.fearGreed;
if (fearGreed) {
fearGreed.value // Current value (0-100)
fearGreed.classification // 'extreme_fear' | 'fear' | 'neutral' | 'greed' | 'extreme_greed'
fearGreed.timestamp // Data timestamp
fearGreed.previousValue // Yesterday's value
fearGreed.change // Change from previous day
fearGreed.weekAverage // 7-day average
fearGreed.monthAverage // 30-day average
}
Classification Ranges
| Range | Classification | Market Sentiment |
|---|---|---|
| 0-24 | extreme_fear | Very bearish, potential buying opportunity |
| 25-44 | fear | Bearish sentiment |
| 45-55 | neutral | Balanced market |
| 56-74 | greed | Bullish sentiment |
| 75-100 | extreme_greed | Very bullish, potential top |
Example: Fear & Greed Strategy
const fearGreed = td.market.sentiment?.fearGreed;
const rsi = td.indicators.rsi;
if (!fearGreed) {
td.utils.log('Fear & Greed data not available');
return;
}
// Buy on extreme fear with oversold RSI (contrarian)
if (!td.position.hasPosition) {
if (fearGreed.classification === 'extreme_fear' && rsi < 30) {
td.trade.buy({
amountPercent: 50,
reason: `Extreme fear (${fearGreed.value}) + RSI oversold`
});
}
}
// Take profits on extreme greed
if (td.position.hasPosition && td.position.side === 'long') {
if (fearGreed.classification === 'extreme_greed' && rsi > 70) {
td.trade.close(`Extreme greed (${fearGreed.value}) + RSI overbought`);
}
}
// Log sentiment
td.utils.log('Market Sentiment', {
value: fearGreed.value,
classification: fearGreed.classification,
change: fearGreed.change,
weekAvg: fearGreed.weekAverage
});
Example: Sentiment Trend Analysis
const fearGreed = td.market.sentiment?.fearGreed;
if (fearGreed && fearGreed.weekAverage && fearGreed.monthAverage) {
// Sentiment improving (short-term above long-term)
const sentimentImproving = fearGreed.weekAverage > fearGreed.monthAverage;
// Sentiment deteriorating
const sentimentDeteriorating = fearGreed.weekAverage < fearGreed.monthAverage;
// Current vs average (momentum)
const sentimentMomentum = fearGreed.value - fearGreed.weekAverage;
td.utils.log('Sentiment Analysis', {
current: fearGreed.value,
weekAvg: fearGreed.weekAverage,
monthAvg: fearGreed.monthAverage,
improving: sentimentImproving,
momentum: sentimentMomentum
});
// Use sentiment as a filter
if (!td.position.hasPosition && sentimentImproving && td.indicators.rsi < 40) {
td.trade.buy({
amountPercent: 25,
reason: 'Sentiment improving + RSI favorable'
});
}
}
Sentiment Score Helper
Convert Fear & Greed to a -1 to 1 scale:
const fearGreed = td.market.sentiment?.fearGreed;
// Convert 0-100 to -1 to 1 scale
// -1 = extreme fear, 0 = neutral, 1 = extreme greed
function getSentimentScore(fg) {
if (!fg) return 0;
return (fg.value - 50) / 50;
}
const score = getSentimentScore(fearGreed);
// Use in position sizing
// Reduce size in extreme sentiment
const baseSize = 50; // 50% of balance
const sentimentMultiplier = 1 - Math.abs(score) * 0.5; // 0.5 to 1.0
const adjustedSize = baseSize * sentimentMultiplier;
td.utils.log('Position sizing', { score, baseSize, adjustedSize });
Data Availability
- Fear & Greed Index updates once per day
- Data is cached for 1 hour to reduce API calls
- Always check if data exists before using:
td.market.sentiment?.fearGreed - Historical averages require sufficient data (7/30 days)
News Sentiment (td.news)
TradeStaq provides real-time AI-powered news sentiment analysis through td.news. News data is aggregated from multiple sources, classified by impact level, and scored for sentiment — giving your strategies an information edge.
Tier Requirement: News sentiment requires a subscription tier with
allowNewsTradingenabled (Pro and above).
Available Properties
const news = td.news;
news.sentiment // Aggregate sentiment score (-1 to 1)
news.isBullish // true if sentiment > 0.2
news.isBearish // true if sentiment < -0.2
news.hasHighImpact // true if high-impact articles exist
news.articleCount // Total articles in lookback window
news.bullishCount // Number of bullish articles
news.bearishCount // Number of bearish articles
news.neutralCount // Number of neutral articles
news.highImpactCount // Number of high/critical impact articles
news.impactWeightedSentiment // Sentiment weighted by article impact
news.latestHeadline // Most recent headline string
news.latestSentiment // Sentiment of the latest article
news.updatedAt // Timestamp of last news update
Sentiment Scale
| Range | Classification | Meaning |
|---|---|---|
| 0.5 to 1.0 | Very Bullish | Strong positive news flow |
| 0.2 to 0.5 | Bullish | Positive sentiment |
| -0.2 to 0.2 | Neutral | Mixed or no significant news |
| -0.5 to -0.2 | Bearish | Negative sentiment |
| -1.0 to -0.5 | Very Bearish | Strong negative news flow |
Example: News Sentiment Filter
Use news as a confirmation filter alongside technical indicators:
const rsi = td.indicators.rsi;
const news = td.news;
if (!td.position.hasPosition) {
// Only buy when both technicals AND news are favorable
if (rsi < 30 && news.isBullish) {
td.trade.buy({
reason: `RSI oversold (${rsi.toFixed(1)}) + bullish news (${news.sentiment.toFixed(2)})`
});
}
}
// Exit on strongly bearish news even if technicals look ok
if (td.position.hasPosition && td.position.side === 'long') {
if (news.sentiment < -0.5 && news.hasHighImpact) {
td.trade.close(`Strongly bearish news: ${news.latestHeadline}`);
}
}
Example: News-Weighted Position Sizing
Adjust position size based on news confidence:
const baseSize = 50; // 50% of balance
const news = td.news;
// Scale position size based on sentiment alignment
let sizeMultiplier = 1.0;
if (news.isBullish && news.hasHighImpact) {
sizeMultiplier = 1.5; // Increase size on strong bullish news
} else if (news.isBearish) {
sizeMultiplier = 0.5; // Reduce size on bearish news
}
const adjustedSize = Math.min(baseSize * sizeMultiplier, 100);
td.trade.buy({ amountPercent: adjustedSize, reason: 'News-adjusted entry' });
Example: News Momentum Strategy
Trade breakouts confirmed by news flow:
const news = td.news;
const macd = td.indicators.macd;
const prevSentiment = td.state.get('prevSentiment', 0);
// Detect sentiment shift
const sentimentImproving = news.sentiment > prevSentiment + 0.1;
const sentimentDeclining = news.sentiment < prevSentiment - 0.1;
td.state.set('prevSentiment', news.sentiment);
if (!td.position.hasPosition) {
// Enter on improving sentiment + MACD confirmation
if (sentimentImproving && macd.trend === 'bullish' && news.highImpactCount >= 2) {
td.trade.buy({ reason: 'News momentum + MACD bullish' });
}
}
td.utils.log('News State', {
sentiment: news.sentiment,
articles: news.articleCount,
highImpact: news.highImpactCount,
headline: news.latestHeadline
});
Visual Builder Support
News Sentiment is available in the No-Code Strategy Builder under the Sentiment category. You can add:
- News Sentiment — The aggregate sentiment score (-1 to 1). Use comparisons like
> 0.2(bullish) or< -0.2(bearish). - News Impact Count — Number of high-impact articles. Use
> 0to check for significant news. - News Article Count — Total articles in the lookback window.
These can be combined with any technical indicator in your entry/exit conditions using AND/OR logic.
Data Availability
- News sentiment updates every 5-15 minutes depending on source refresh rates
- Data is asset-specific — sentiment is computed for the trading pair's base asset
- Always check if data exists:
if (td.news) { ... } - If no news is available,
td.news.sentimentdefaults to0(neutral)
Custom Period Indicators
For indicators with custom periods, use td.indicators.custom. The platform auto-detects which indicators you need from your code by parsing td.indicators.custom['indicator_period'] patterns.
Direct Access Pattern
// Direct access (works for scalar values)
const ema20 = td.indicators.custom['ema_20']; // 20-period EMA
const sma50 = td.indicators.custom['sma_50']; // 50-period SMA
const rsi7 = td.indicators.custom['rsi_7']; // 7-period RSI
const atr10 = td.indicators.custom['atr_10']; // 10-period ATR
Recommended: Safe Accessor Pattern
Custom indicators may return arrays or scalar values. Use this helper function to safely access the current value:
// Helper function (include at top of your strategy)
function getIndicator(key) {
const val = td.indicators.custom[key];
if (val === undefined || val === null) return 0;
if (Array.isArray(val)) return val[val.length - 1];
return val;
}
// Usage with helper (recommended - handles both arrays and scalars)
const ema20 = getIndicator('ema_20'); // 20-period EMA
const sma50 = getIndicator('sma_50'); // 50-period SMA
const rsi7 = getIndicator('rsi_7'); // 7-period RSI
const atr10 = getIndicator('atr_10'); // 10-period ATR
Available Custom Indicators
| Pattern | Description |
|---|---|
ema_N | Exponential Moving Average (N period) |
sma_N | Simple Moving Average (N period) |
wma_N | Weighted Moving Average (N period) |
rsi_N | RSI (N period) |
atr_N | ATR (N period) |
bbands_N_M | Bollinger Bands (N period, M stddev) |
Example: Multiple EMA Crossover
// Helper function for safe indicator access
function getIndicator(key) {
const val = td.indicators.custom[key];
if (val === undefined || val === null) return 0;
if (Array.isArray(val)) return val[val.length - 1];
return val;
}
const ema9 = getIndicator('ema_9');
const ema21 = getIndicator('ema_21');
const ema50 = getIndicator('ema_50');
// Track previous values for crossover detection
const prevEma9 = td.state.get('prevEma9', ema9);
const prevEma21 = td.state.get('prevEma21', ema21);
// Golden cross: fast EMA crosses above slow EMA
const goldenCross = prevEma9 <= prevEma21 && ema9 > ema21;
if (goldenCross && td.market.price > ema50) {
td.trade.buy({ reason: 'EMA golden cross above 50 EMA' });
}
// Save for next spin
td.state.set('prevEma9', ema9);
td.state.set('prevEma21', ema21);
Full Tulind Indicator Reference
TradeStaq provides access to all 100+ tulind indicators through the custom indicator system. Configure these in your bot settings or use td.indicators.custom.
Moving Averages
| Indicator | Name | Options | Description |
|---|---|---|---|
ema | Exponential MA | [period] | Exponential moving average |
sma | Simple MA | [period] | Simple moving average |
wma | Weighted MA | [period] | Weighted moving average |
dema | Double EMA | [period] | Double exponential moving average |
tema | Triple EMA | [period] | Triple exponential moving average |
trima | Triangular MA | [period] | Triangular moving average |
kama | Kaufman AMA | [period] | Kaufman adaptive moving average |
mama | MESA Adaptive | [fast, slow] | MESA adaptive moving average |
t3 | T3 | [period, factor] | T3 moving average |
zlema | Zero-Lag EMA | [period] | Zero-lag exponential moving average |
hma | Hull MA | [period] | Hull moving average (smooth, responsive) |
wilders | Wilder's Smooth | [period] | Wilder's smoothing |
vwma | Volume Weighted | [period] | Volume-weighted moving average |
vidya | Variable Index | [short, long, alpha] | Variable index dynamic average |
Momentum Indicators
| Indicator | Name | Options | Description |
|---|---|---|---|
rsi | RSI | [period] | Relative strength index (0-100) |
stochrsi | Stochastic RSI | [period] | Stochastic RSI oscillator |
roc | Rate of Change | [period] | Rate of change |
rocr | ROC Ratio | [period] | Rate of change ratio |
mom | Momentum | [period] | Price momentum |
cmo | Chande Momentum | [period] | Chande momentum oscillator |
stoch | Stochastic | [k, slowing, d] | Stochastic oscillator |
willr | Williams %R | [period] | Williams %R (0 to -100) |
ultosc | Ultimate Osc | [short, med, long] | Ultimate oscillator |
ao | Awesome Osc | - | Awesome oscillator |
trix | TRIX | [period] | Triple EXP smoothed price ROC |
apo | Absolute Price | [short, long] | Absolute price oscillator |
ppo | Percentage Price | [short, long] | Percentage price oscillator |
fosc | Forecast Osc | [period] | Forecast oscillator |
bop | Balance of Power | - | Balance of power |
Trend Indicators
| Indicator | Name | Options | Description |
|---|---|---|---|
macd | MACD | [fast, slow, signal] | Moving average convergence divergence |
adx | ADX | [period] | Average directional index (trend strength) |
adxr | ADXR | [period] | ADX rating |
dx | DX | [period] | Directional movement index |
di | DI | [period] | Directional indicator (+DI) |
dm | DM | [period] | Directional movement |
aroon | Aroon | [period] | Aroon indicator (up/down) |
aroonosc | Aroon Osc | [period] | Aroon oscillator |
psar | Parabolic SAR | [accel, max] | Parabolic SAR |
supertrend | Supertrend | [period, mult] | Dynamic support/resistance trend indicator |
vhf | VHF | [period] | Vertical horizontal filter |
dpo | DPO | [period] | Detrended price oscillator |
Volatility Indicators
| Indicator | Name | Options | Description |
|---|---|---|---|
atr | ATR | [period] | Average true range |
natr | NATR | [period] | Normalized ATR |
tr | True Range | - | True range (single value) |
bbands | Bollinger | [period, stddev] | Bollinger bands (lower, middle, upper) |
volatility | Volatility | [period] | Annualized volatility |
cci | CCI | [period] | Commodity channel index |
mass | Mass Index | [period] | Mass index |
Volume Indicators
| Indicator | Name | Options | Description |
|---|---|---|---|
mfi | MFI | [period] | Money flow index (volume-weighted RSI) |
ad | Accum/Dist | - | Accumulation/distribution line |
adosc | A/D Oscillator | [short, long] | A/D oscillator |
obv | OBV | - | On-balance volume |
nvi | NVI | - | Negative volume index |
pvi | PVI | - | Positive volume index |
kvo | Klinger | [short, long] | Klinger volume oscillator |
emv | EMV | - | Ease of movement |
marketfi | Market Fac | - | Market facilitation index |
vosc | Volume Osc | [short, long] | Volume oscillator |
wad | W. Accum/Dist | - | Williams accumulation/distribution |
Statistical & Math
| Indicator | Name | Options | Description |
|---|---|---|---|
linreg | Linear Reg | [period] | Linear regression |
linregslope | LinReg Slope | [period] | Linear regression slope |
linregintercept | LinReg Int | [period] | Linear regression intercept |
tsf | Time Series | [period] | Time series forecast |
stddev | Std Deviation | [period] | Standard deviation |
stderr | Std Error | [period] | Standard error |
var | Variance | [period] | Variance |
md | Mean Deviation | [period] | Mean deviation |
Price Transforms
| Indicator | Name | Options | Description |
|---|---|---|---|
typprice | Typical Price | - | (H+L+C)/3 |
wcprice | Weighted Close | - | (H+L+2C)/4 |
medprice | Median Price | - | (H+L)/2 |
avgprice | Average Price | - | (O+H+L+C)/4 |
fisher | Fisher Transform | [period] | Fisher transform |
qstick | QStick | [period] | QStick indicator |
Custom Indicator Configuration
Bot Settings Configuration
Pre-compute custom indicators by configuring them in your bot settings:
{
"customIndicators": [
{ "name": "hma", "options": [20] },
{ "name": "kama", "options": [10] },
{ "name": "tema", "options": [14] },
{ "name": "aroon", "options": [25] },
{ "name": "psar", "options": [0.02, 0.2] }
]
}
Accessing Custom Indicators
Use this helper function to safely access custom indicators:
// Helper to get custom indicator value safely
function getIndicator(key) {
const val = td.indicators.custom[key];
if (val === undefined || val === null) return 0;
if (Array.isArray(val)) return val[val.length - 1];
return val;
}
// Access pre-computed custom indicators
const hma20 = getIndicator('hma_20');
const kama10 = getIndicator('kama_10');
const tema14 = getIndicator('tema_14');
// Multi-output indicators (like aroon returns up/down)
const aroonUp = getIndicator('aroon_25'); // First output
const aroonDown = getIndicator('aroon_25_1'); // Second output
// Parabolic SAR with multiple options
const psar = getIndicator('psar_0.02_0.2');
Naming Convention
Custom indicator keys follow this pattern:
{indicator_name}_{option1}_{option2}... // Array or value
{indicator_name}_{option1}_{option2}..._{n} // Additional outputs (0-indexed)
The getIndicator helper automatically handles both array and scalar values.
Using Any Tulind Indicator
Configure custom indicators in your bot or strategy settings, then access them using the helper:
// Helper to get custom indicator value safely
function getIndicator(key) {
const val = td.indicators.custom[key];
if (val === undefined || val === null) return 0;
if (Array.isArray(val)) return val[val.length - 1];
return val;
}
// Access any tulind indicator
const hma20 = getIndicator('hma_20');
const kama10 = getIndicator('kama_10');
const tema14 = getIndicator('tema_14');
const zlema30 = getIndicator('zlema_30');
For indicators with multiple options (e.g., PSAR with step and max), the key uses underscores: psar_0.02_0.2.
Combining Multiple Indicators
Confluence Strategy
// Multi-indicator confirmation system
let bullScore = 0;
let bearScore = 0;
// RSI
if (td.indicators.rsi < 35) bullScore++;
if (td.indicators.rsi > 65) bearScore++;
// MACD
if (td.indicators.macd.histogram > 0) bullScore++;
if (td.indicators.macd.histogram < 0) bearScore++;
// ADX trend direction
if (td.indicators.adx.value > 25) {
if (td.indicators.adx.diPlus > td.indicators.adx.diMinus) bullScore++;
else bearScore++;
}
// Bollinger position
if (td.indicators.bbands.percentB < 0.2) bullScore++;
if (td.indicators.bbands.percentB > 0.8) bearScore++;
// Require minimum confluence
const minScore = td.config.getNumber('MIN_CONFLUENCE', 3);
if (bullScore >= minScore && !td.position.hasPosition) {
td.trade.buy({ reason: `Bull confluence: ${bullScore} signals` });
} else if (bearScore >= minScore && td.position.hasPosition) {
td.trade.close(`Bear confluence: ${bearScore} signals`);
}
Advanced Custom Indicator Example
// Using Hull Moving Average for trend + RSI for timing
// Helper to get custom indicator value safely
function getIndicator(key) {
const val = td.indicators.custom[key];
if (val === undefined || val === null) return 0;
if (Array.isArray(val)) return val[val.length - 1];
return val;
}
// Helper to get full array for trend analysis
function getIndicatorArray(key) {
const val = td.indicators.custom[key];
if (Array.isArray(val)) return val;
return [];
}
const hma = getIndicator('hma_20');
const hmaArray = getIndicatorArray('hma_20');
const price = td.market.price;
const rsi = td.indicators.rsi;
// HMA trend direction
let hmaTrend = 'neutral';
if (hmaArray.length >= 2) {
const prevHMA = hmaArray[hmaArray.length - 2];
if (hma > prevHMA) hmaTrend = 'bullish';
else if (hma < prevHMA) hmaTrend = 'bearish';
}
// Price above/below HMA
const priceAboveHMA = price > hma;
const priceBelowHMA = price < hma;
// Entry conditions
if (!td.position.hasPosition) {
// Long: Price above rising HMA + RSI oversold
if (priceAboveHMA && hmaTrend === 'bullish' && rsi < 35) {
td.trade.buy({ reason: 'HMA bullish + RSI oversold' });
}
// Short: Price below falling HMA + RSI overbought
if (priceBelowHMA && hmaTrend === 'bearish' && rsi > 65) {
td.trade.sell({ reason: 'HMA bearish + RSI overbought' });
}
}
Parabolic SAR Trailing Stop
// Using Parabolic SAR for dynamic trailing stop
// Configure: { "customIndicators": [{ "name": "psar", "options": [0.02, 0.2] }] }
const psar = getIndicator('psar_0.02_0.2_last');
const price = td.market.price;
if (td.position.hasPosition) {
const side = td.position.side;
// Long position: PSAR below price = stay, above = exit
if (side === 'long' && price < psar) {
td.trade.close('PSAR stop hit');
}
// Short position: PSAR above price = stay, below = exit
if (side === 'short' && price > psar) {
td.trade.close('PSAR stop hit');
}
}
Klinger Volume Oscillator
// Volume-based trend confirmation
// Helpers
function getIndicator(key) {
const val = td.indicators.custom[key];
if (val === undefined || val === null) return 0;
if (Array.isArray(val)) return val[val.length - 1];
return val;
}
function getIndicatorArray(key) {
const val = td.indicators.custom[key];
if (Array.isArray(val)) return val;
return [];
}
const kvo = getIndicator('kvo_34_55');
const kvoArray = getIndicatorArray('kvo_34_55');
const macd = td.indicators.macd;
// KVO crossover detection
let kvoCrossUp = false;
let kvoCrossDown = false;
if (kvoArray.length >= 2) {
const prevKVO = kvoArray[kvoArray.length - 2];
kvoCrossUp = prevKVO <= 0 && kvo > 0;
kvoCrossDown = prevKVO >= 0 && kvo < 0;
}
// Combine with MACD for stronger signal
if (!td.position.hasPosition) {
if (kvoCrossUp && macd.trend === 'bullish') {
td.trade.buy({ reason: 'KVO bullish crossover + MACD bullish' });
}
if (kvoCrossDown && macd.trend === 'bearish') {
td.trade.sell({ reason: 'KVO bearish crossover + MACD bearish' });
}
}
Best Practices
1. Don't Rely on Single Indicators
Use multiple indicators for confirmation. A single indicator can generate false signals.
2. Consider Market Conditions
- Trend indicators (MACD, ADX) work best in trending markets
- Oscillators (RSI, Stochastic) work best in ranging markets
- Use ADX to determine market type first
3. Use Appropriate Timeframes
- Higher timeframes reduce noise but lag more
- Lower timeframes are more responsive but noisier
- Consider multi-timeframe analysis for best results
4. Backtest Thoroughly
- Test indicator combinations on historical data
- Verify signals work across different market conditions
- Check for sufficient trade count for statistical significance
5. Avoid Over-Optimization
- Too many indicators can lead to curve fitting
- Stick to 2-4 complementary indicators
- Simpler strategies often outperform complex ones
6. Use Pre-computed Indicators
- Configure frequently-used custom indicators in bot settings
- This improves performance vs calculating on-the-fly
- Cache is shared across strategy spins
Performance Considerations
Indicator Performance
| Type | Performance | Use Case |
|---|---|---|
| Pre-calculated (rsi, macd, etc.) | Fastest | Use for common indicators with default periods |
| Auto-detected custom (ema_20, sma_50) | Fast | Platform detects from your code and pre-computes |
| Bot-configured custom (hma, kama) | Fast | Configure in bot settings for advanced indicators |
Optimization Tips
- Configure custom indicators in bot settings rather than calculating in strategy code
- Access arrays once and store in variables rather than repeated calls
- Use pre-calculated indicators when defaults are acceptable
- Limit custom indicator count to what you actually need
Next Steps
- Advanced Signals - DCA, trailing, grid trading
- Multi-Timeframe - MTF analysis
- Trade Execution - Executing trades
- Best Practices - Strategy guidelines