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¶
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:
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:
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:
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
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¶
3. Lint Strategy¶
4. Run Unit Tests¶
5. Quick Backtest¶
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 |