> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getelyra.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Quant Agent: RSI and EMA technical analysis signals

> Compute RSI and EMA trend signals for any Binance trading pair. Returns a bullish, bearish, or neutral verdict with a human-readable trading signal.

The Quant Agent downloads OHLC candlestick data from Binance and applies two indicators — Wilder RSI and an exponential moving average — to produce a directional verdict for any trading pair. Stage 2/6 in the full Elyra pipeline runs it against BTCUSDT, but you can point it at any symbol Binance supports.

## CLI usage

Pass the trading pair as a positional argument:

```bash theme={null}
python3 agents/quant_agent.py BTCUSDT
python3 agents/quant_agent.py ETHUSDT
python3 agents/quant_agent.py SOLUSDT
```

If you omit the argument, the agent defaults to `BTCUSDT`.

## Python usage

```python theme={null}
from agents.quant_agent import analyze_market

result = analyze_market(symbol="BTCUSDT", interval="1d", limit=100)
# Returns: {"trend": "bullish", "rsi": 58, "signal": "possible breakout"}
```

## `analyze_market()`

Downloads up to `limit` candlesticks for `symbol` at the given `interval`, computes RSI and EMA, and returns a structured signal dictionary.

**Signature**

```python theme={null}
def analyze_market(
    symbol: str = "BTCUSDT",
    interval: str = "1d",
    limit: int = 100,
    rsi_period: int = 14,
    ema_period: int = 20,
) -> dict[str, str | int]
```

### Parameters

<ParamField path="symbol" type="string" default="BTCUSDT">
  Binance trading pair in uppercase (e.g. `"BTCUSDT"`, `"ETHUSDT"`, `"SOLUSDT"`). Any valid Binance spot or futures symbol is accepted.
</ParamField>

<ParamField path="interval" type="string" default="1d">
  Candlestick interval. Accepts any Binance kline interval string — common values are `"1m"`, `"5m"`, `"1h"`, `"4h"`, `"1d"`, `"1w"`.
</ParamField>

<ParamField path="limit" type="number" default="100">
  Number of candlesticks to fetch from Binance (maximum 1000). Must be greater than `max(rsi_period, ema_period) + 1`; otherwise the function returns `"insufficient data"`.
</ParamField>

<ParamField path="rsi_period" type="number" default="14">
  Lookback window for the Wilder RSI calculation.
</ParamField>

<ParamField path="ema_period" type="number" default="20">
  Lookback window for the exponential moving average. Trend is determined by comparing the last close price against the last EMA value.
</ParamField>

### Return value

Returns `dict[str, str | int]`.

<ResponseField name="trend" type="string" required>
  Directional bias derived by comparing the most recent close against the EMA. One of `"bullish"` (close ≥ EMA) or `"bearish"` (close \< EMA). Returns `"neutral"` when there is insufficient data.
</ResponseField>

<ResponseField name="rsi" type="number" required>
  Most recent RSI value rounded to the nearest integer, in the range 0–100. Returns `50` when there is insufficient data.
</ResponseField>

<ResponseField name="signal" type="string" required>
  Human-readable trading signal derived from RSI and trend. Possible values:

  | Value                  | Condition                                |
  | ---------------------- | ---------------------------------------- |
  | `"overbought"`         | RSI ≥ 70                                 |
  | `"oversold"`           | RSI ≤ 30                                 |
  | `"possible breakout"`  | Trend is bullish and 50 \< RSI \< 70     |
  | `"possible breakdown"` | Trend is bearish and 30 \< RSI \< 50     |
  | `"uptrend"`            | Trend is bullish and RSI ≤ 50            |
  | `"downtrend"`          | Trend is bearish and RSI ≥ 50            |
  | `"insufficient data"`  | Not enough candles to compute indicators |
</ResponseField>

### Example response

```json theme={null}
{
  "trend": "bullish",
  "rsi": 58,
  "signal": "possible breakout"
}
```

### Insufficient data response

If `limit` is smaller than `max(rsi_period, ema_period) + 1`, the function returns safe defaults instead of raising an exception:

```json theme={null}
{
  "trend": "neutral",
  "rsi": 50,
  "signal": "insufficient data"
}
```

## Signal logic reference

The signal is computed in two steps: first determine trend from price vs. EMA, then apply RSI thresholds.

```python theme={null}
# Trend: last close vs. last EMA value
trend = "bullish" if last_close >= last_ema else "bearish"

# Signal: RSI thresholds take priority
if rsi >= 70:   signal = "overbought"
elif rsi <= 30: signal = "oversold"
elif trend == "bullish" and 50 < rsi < 70: signal = "possible breakout"
elif trend == "bearish" and 30 < rsi < 50: signal = "possible breakdown"
elif trend == "bullish": signal = "uptrend"
else:           signal = "downtrend"
```

<Note>
  No API key is required. Binance kline data is publicly accessible.
</Note>
