Skip to content

Technical Indicators

Calculate technical indicators (MACD, RSI, Bollinger Bands, EMA, etc.) with customizable parameters. Results are cached for 15 minutes.

MethodEndpointAuthDescription
GET/indicators/{symbol}NoGet indicators for a symbol
POST/indicators/batchNoGet indicators for multiple symbols

Calculate technical indicators for a single symbol.

GET /api/v1/indicators/AAPL?interval=1d&limit=500&rsi_period=14&macd_fast=12&macd_slow=26&ema_periods=20,50
ParameterTypeDescription
symbolstringStock ticker symbol
ParameterTypeDefaultRangeDescription
intervalstring1d-Data interval (1m, 5m, 15m, 30m, 1h, 1d)
limitinteger5001-10000Max data points
start_datedate--Start date filter
end_datedate--End date filter
rsi_periodinteger145-50RSI calculation period
macd_fastinteger125-100MACD fast EMA period
macd_slowinteger265-100MACD slow EMA period
macd_signalinteger95-50MACD signal line period
bb_periodinteger205-100Bollinger Bands period
bb_stdfloat2.01.0-3.0Bollinger Bands std deviation
ema_periodsstring20,50-Comma-separated EMA periods
chandelier_periodinteger225-50Chandelier Exit ATR period
chandelier_multiplierfloat3.01.0-5.0Chandelier Exit multiplier

MACD (Moving Average Convergence Divergence)

Section titled “MACD (Moving Average Convergence Divergence)”

MACD

Momentum oscillator showing relationship between two EMAs.

Fields: macd, macd_signal, macd_histogram

Parameters: macd_fast (12), macd_slow (26), macd_signal (9)

Signals:

  • Bullish: MACD crosses above signal line
  • Bearish: MACD crosses below signal line

RSI

Momentum oscillator measuring speed and magnitude of price changes.

Field: rsi (0-100 scale)

Parameter: rsi_period (default: 14)

Signals:

  • Oversold: RSI < 30 (potential buy)
  • Overbought: RSI > 70 (potential sell)
  • Neutral: 30 < RSI < 70

Bollinger Bands

Volatility bands placed above and below a moving average.

Fields: bb_upper, bb_middle, bb_lower

Parameters: bb_period (20), bb_std (2.0)

Signals:

  • Price near upper band: Potentially overbought
  • Price near lower band: Potentially oversold
  • Band squeeze: Low volatility, potential breakout

EMA

Weighted moving average giving more weight to recent prices.

Fields: ema_{period} (e.g., ema_20, ema_50)

Parameter: ema_periods (comma-separated, e.g., “20,50,200”)

Signals:

  • Golden Cross: Short EMA crosses above long EMA (bullish)
  • Death Cross: Short EMA crosses below long EMA (bearish)

Momentum

Rate of change indicator showing price velocity.

Field: momentum

Signals:

  • Positive: Upward momentum
  • Negative: Downward momentum
  • Divergence: Price and momentum moving opposite directions

Chandelier Exit

Volatility-based trailing stop indicator using ATR.

Fields: chandelier_long, chandelier_short

Parameters: chandelier_period (22), chandelier_multiplier (3.0)

Signals:

  • Long exit: Price drops below chandelier_long
  • Short exit: Price rises above chandelier_short

The response includes a signal_summary object with aggregated signals:

{
"signal_summary": {
"current_signal": "bullish",
"signal_details": {
"macd": "bullish",
"rsi": "neutral",
"bb": "neutral"
}
}
}
SignalDescription
bullishBuy signal - positive momentum indicators
bearishSell signal - negative momentum indicators
neutralNo clear signal - mixed or sideways indicators

Get indicators for multiple symbols in one request.

POST /api/v1/indicators/batch
Content-Type: application/json
{
"symbols": ["AAPL", "MSFT", "GOOGL"],
"interval": "1d",
"limit": 500,
"rsi_period": 14,
"macd_fast": 12,
"macd_slow": 26,
"macd_signal": 9,
"bb_period": 20,
"bb_std": 2.0,
"ema_periods": "20,50"
}

import axios from 'axios';
const api = axios.create({
baseURL: 'http://localhost:8501/api/v1'
});
// Get indicators with custom parameters
async function getIndicators(symbol, params = {}) {
const { data } = await api.get(`/indicators/${symbol}`, {
params: {
interval: '1d',
limit: 500,
rsi_period: 14,
macd_fast: 12,
macd_slow: 26,
ema_periods: '20,50,200',
...params
}
});
return data;
}
// Analyze signals
async function analyzeSymbol(symbol) {
const indicators = await getIndicators(symbol);
const latest = indicators.data[indicators.data.length - 1];
const summary = indicators.signal_summary;
console.log(`\n${symbol} Analysis:`);
console.log(` Signal: ${summary.current_signal.toUpperCase()}`);
console.log(` RSI: ${latest.rsi.toFixed(1)}`);
console.log(` MACD: ${latest.macd.toFixed(2)} (Signal: ${latest.macd_signal.toFixed(2)})`);
console.log(` Price: $${latest.close.toFixed(2)}`);
console.log(` BB: $${latest.bb_lower.toFixed(2)} - $${latest.bb_upper.toFixed(2)}`);
// Trading signals
if (latest.rsi < 30) {
console.log(' ⚠️ RSI Oversold - potential buy signal');
} else if (latest.rsi > 70) {
console.log(' ⚠️ RSI Overbought - potential sell signal');
}
if (latest.macd > latest.macd_signal && latest.macd_histogram > 0) {
console.log(' 📈 MACD bullish crossover');
}
return indicators;
}
// Screen multiple stocks
async function screenStocks(symbols) {
const { data } = await api.post('/indicators/batch', {
symbols,
interval: '1d',
limit: 100,
rsi_period: 14
});
// Find oversold stocks
const oversold = [];
const overbought = [];
for (const [symbol, result] of Object.entries(data)) {
const latest = result.data[result.data.length - 1];
if (latest.rsi < 30) {
oversold.push({ symbol, rsi: latest.rsi });
} else if (latest.rsi > 70) {
overbought.push({ symbol, rsi: latest.rsi });
}
}
console.log('Oversold stocks:', oversold);
console.log('Overbought stocks:', overbought);
return { oversold, overbought };
}
// Usage
await analyzeSymbol('AAPL');
await screenStocks(['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META']);
import requests
import pandas as pd
BASE_URL = "http://localhost:8501/api/v1"
def get_indicators(
symbol: str,
interval: str = "1d",
**kwargs
) -> dict:
"""Get technical indicators for a symbol."""
params = {
"interval": interval,
"limit": kwargs.get("limit", 500),
"rsi_period": kwargs.get("rsi_period", 14),
"macd_fast": kwargs.get("macd_fast", 12),
"macd_slow": kwargs.get("macd_slow", 26),
"macd_signal": kwargs.get("macd_signal", 9),
"bb_period": kwargs.get("bb_period", 20),
"bb_std": kwargs.get("bb_std", 2.0),
"ema_periods": kwargs.get("ema_periods", "20,50"),
}
response = requests.get(
f"{BASE_URL}/indicators/{symbol}",
params=params
)
response.raise_for_status()
return response.json()
def indicators_to_dataframe(indicators: dict) -> pd.DataFrame:
"""Convert indicators response to DataFrame."""
df = pd.DataFrame(indicators["data"])
df["time"] = pd.to_datetime(df["time"])
df.set_index("time", inplace=True)
return df
def analyze_stock(symbol: str) -> dict:
"""Perform technical analysis on a stock."""
indicators = get_indicators(symbol)
df = indicators_to_dataframe(indicators)
latest = df.iloc[-1]
summary = indicators["signal_summary"]
analysis = {
"symbol": symbol,
"signal": summary["current_signal"],
"price": latest["close"],
"rsi": latest["rsi"],
"macd": latest["macd"],
"macd_signal": latest["macd_signal"],
"macd_histogram": latest["macd_histogram"],
"bb_position": (latest["close"] - latest["bb_lower"]) /
(latest["bb_upper"] - latest["bb_lower"]) * 100,
"alerts": []
}
# Generate alerts
if latest["rsi"] < 30:
analysis["alerts"].append("RSI oversold - potential buy")
elif latest["rsi"] > 70:
analysis["alerts"].append("RSI overbought - potential sell")
if latest["macd"] > latest["macd_signal"]:
analysis["alerts"].append("MACD bullish")
else:
analysis["alerts"].append("MACD bearish")
if latest["close"] < latest["bb_lower"]:
analysis["alerts"].append("Price below lower BB")
elif latest["close"] > latest["bb_upper"]:
analysis["alerts"].append("Price above upper BB")
return analysis
def screen_stocks(symbols: list, rsi_threshold_low: float = 30, rsi_threshold_high: float = 70):
"""Screen multiple stocks for trading signals."""
response = requests.post(
f"{BASE_URL}/indicators/batch",
json={
"symbols": symbols,
"interval": "1d",
"limit": 100,
"rsi_period": 14
}
)
response.raise_for_status()
results = response.json()
signals = {"oversold": [], "overbought": [], "neutral": []}
for symbol, data in results.items():
latest = data["data"][-1]
rsi = latest["rsi"]
signal = data["signal_summary"]["current_signal"]
stock_info = {
"symbol": symbol,
"rsi": rsi,
"signal": signal,
"price": latest["close"]
}
if rsi < rsi_threshold_low:
signals["oversold"].append(stock_info)
elif rsi > rsi_threshold_high:
signals["overbought"].append(stock_info)
else:
signals["neutral"].append(stock_info)
return signals
# Usage
if __name__ == "__main__":
# Analyze single stock
analysis = analyze_stock("AAPL")
print(f"\n{analysis['symbol']} Analysis:")
print(f" Signal: {analysis['signal']}")
print(f" Price: ${analysis['price']:.2f}")
print(f" RSI: {analysis['rsi']:.1f}")
print(f" MACD: {analysis['macd']:.2f}")
print(f" BB Position: {analysis['bb_position']:.1f}%")
for alert in analysis["alerts"]:
print(f" ⚠️ {alert}")
# Screen multiple stocks
symbols = ["AAPL", "MSFT", "GOOGL", "AMZN", "META", "NVDA", "TSLA"]
signals = screen_stocks(symbols)
print("\n📉 Oversold stocks:")
for s in signals["oversold"]:
print(f" {s['symbol']}: RSI={s['rsi']:.1f}")
print("\n📈 Overbought stocks:")
for s in signals["overbought"]:
print(f" {s['symbol']}: RSI={s['rsi']:.1f}")

Parameter Tuning

Adjust indicator periods based on your trading timeframe. Shorter periods for day trading, longer for swing/position trading.

Multiple Confirmation

Don’t rely on a single indicator. Use multiple indicators that confirm each other.

Caching

Responses are cached for 15 minutes. Plan your refresh strategy accordingly.

Batch Requests

Use batch endpoint when analyzing multiple stocks to reduce API calls.