Skip to content

Developing Indicators & Strategy Logic

Guide to testing indicator expressions and iterating on strategy logic.

Indicator Playground

Test indicator calculations without running a full backtest.

Quick Indicator Test

tradai indicator test "ta.RSI(df['close'], 14)"

Output:

Testing indicator on BTC/USDT:USDT
Period: 2024-11-22 to 2024-12-22

┌──────────────────────────────────────────────────┐
│                    RSI Stats                      │
├────────────┬─────────────────────────────────────┤
│ Count      │ 720                                 │
│ Min        │ 23.41                               │
│ Max        │ 78.23                               │
│ Mean       │ 52.18                               │
│ Current    │ 45.67                               │
└────────────┴─────────────────────────────────────┘

Last 50 values: ▃▄▅▆▇▇▆▅▄▃▂▃▄▅▆▇▆▅▄▃▂▁▂▃▄▅▆▅▄▃▂▃▄▅▆▇▆▅▄▃▂▃▄▅▆▇▆▅

Test with Different Symbols/Timeframes

# Different symbol
tradai indicator test "ta.RSI(df['close'], 14)" --symbol ETH/USDT:USDT

# Different timeframe
tradai indicator test "ta.MACD(df['close'])" --timeframe 4h

# Custom period
tradai indicator test "ta.EMA(df['close'], 20)" --period 7d

Test Complex Expressions

# MACD histogram
tradai indicator test "ta.MACD(df['close'])[2]"

# Bollinger Bands width
tradai indicator test "(ta.BBANDS(df['close'])[0] - ta.BBANDS(df['close'])[2]) / ta.BBANDS(df['close'])[1]"

# Custom calculations
tradai indicator test "df['close'].pct_change().rolling(20).std()"

Use Different Data Sources

# From Binance (default)
tradai indicator test "ta.RSI(df['close'])" --source binance

# From ArcticDB (if data synced)
tradai indicator test "ta.RSI(df['close'])" --source arctic

# From local file
tradai indicator test "ta.RSI(df['close'])" --source file --file ./data.csv

Available Indicators

View all available TA-Lib indicators:

tradai indicator list

Output shows categorized indicators:

Trend Indicators

Indicator Expression Description
SMA ta.SMA(df['close'], 20) Simple Moving Average
EMA ta.EMA(df['close'], 20) Exponential Moving Average
MACD ta.MACD(df['close']) MACD (macd, signal, hist)
ADX ta.ADX(df['high'], df['low'], df['close']) Average Directional Index

Momentum Indicators

Indicator Expression Description
RSI ta.RSI(df['close'], 14) Relative Strength Index
STOCH ta.STOCH(df['high'], df['low'], df['close']) Stochastic (slowk, slowd)
CCI ta.CCI(df['high'], df['low'], df['close']) Commodity Channel Index
MOM ta.MOM(df['close'], 10) Momentum

Volatility Indicators

Indicator Expression Description
BBANDS ta.BBANDS(df['close']) Bollinger Bands (upper, mid, lower)
ATR ta.ATR(df['high'], df['low'], df['close']) Average True Range
NATR ta.NATR(df['high'], df['low'], df['close']) Normalized ATR

Volume Indicators

Indicator Expression Description
OBV ta.OBV(df['close'], df['volume']) On Balance Volume
MFI ta.MFI(df['high'], df['low'], df['close'], df['volume']) Money Flow Index

Interactive REPL

For exploratory analysis, use the interactive REPL:

tradai indicator repl

This opens an IPython session with pre-loaded data:

# Data already loaded as 'df'
>>> df.tail()
                          date      open      high       low     close    volume
2024-12-22 09:00:00  97500.12  98200.45  97400.00  97850.23  1234567.8

# TA-Lib available as 'ta'
>>> rsi = ta.RSI(df['close'], 14)
>>> rsi.tail()

# Pandas/NumPy available
>>> df['returns'] = df['close'].pct_change()
>>> df['volatility'] = df['returns'].rolling(20).std()

Syncing Market Data

Before testing indicators, ensure you have data synced:

# Check data availability
tradai data check-freshness BTC/USDT:USDT

# Sync data if needed
tradai data sync BTC/USDT:USDT \
  --start 2024-01-01 \
  --end 2024-12-22 \
  --timeframe 1h

Strategy Linting

Check your strategy for common issues:

tradai strategy lint MyStrategy

Detected Issues

Look-Ahead Bias

strategies/my_strategy/strategy.py:45: error: Potential look-ahead bias
  df.shift(-1) accesses future data

Missing Warmup Period

strategies/my_strategy/strategy.py:1: warning: Missing startup_candle_count
  Strategy uses indicators but doesn't set startup_candle_count

Invalid Timeframe/Category Combination

warning: Scalping strategies typically use short timeframes (1m, 5m, 15m)
  Current: 4h

Development Workflow

1. Write Indicator Code

def populate_indicators(self, dataframe, metadata):
    dataframe["rsi"] = ta.RSI(dataframe["close"], timeperiod=14)
    return dataframe

2. Test Indicator Quickly

tradai indicator test "ta.RSI(df['close'], 14)" --symbol BTC/USDT:USDT

3. Lint Strategy

tradai strategy lint MyStrategy

4. Run Unit Tests

just test-package strategies/my_strategy

5. Quick Backtest

tradai backtest quick MyStrategy --period 7d

Common Patterns

RSI Oversold/Overbought

# Entry: RSI < 30 (oversold)
dataframe.loc[dataframe["rsi"] < 30, "enter_long"] = 1

# Exit: RSI > 70 (overbought)
dataframe.loc[dataframe["rsi"] > 70, "exit_long"] = 1

Moving Average Crossover

# Entry: Fast EMA crosses above slow EMA
dataframe.loc[
    (dataframe["ema_fast"] > dataframe["ema_slow"]) &
    (dataframe["ema_fast"].shift(1) <= dataframe["ema_slow"].shift(1)),
    "enter_long"
] = 1

Bollinger Band Squeeze

# Entry: Price below lower band
lower_band = ta.BBANDS(dataframe["close"])[2]
dataframe.loc[dataframe["close"] < lower_band, "enter_long"] = 1

Quick Reference

Command Description
tradai indicator test EXPR Test indicator expression
tradai indicator list List all indicators
tradai indicator repl Interactive REPL
tradai strategy lint NAME Check for issues
tradai data check-freshness SYMBOL Check data availability
tradai data sync SYMBOL Sync market data