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

# Technical indicators: RSI, EMA, MACD, Bollinger Bands and VWAP

> Get RSI, EMA, MACD, Bollinger Bands and VWAP for any DEX pool or token from one DexPaprika call, computed server-side from OHLCV candles. RSI, EMA and MACD on pools work without a key.

## What you'll build

A screen that reads RSI and MACD for a pool straight from the API, without downloading candles and computing the indicator yourself. The server computes it from the same OHLCV candles that [pool OHLCV](/tutorials/retrieve-historical-data) returns, so the numbers line up with the charts you already draw.

By the end you will have:

* A curl that returns hourly RSI for a pool, with no key
* A Python script that flags overbought and oversold pools and MACD crosses
* A clear picture of which indicator needs which plan

***

## Which plan you need

| | Keyless and free key | Dev, Pro, Enterprise |
| - | - | - |
| Pool RSI, EMA, MACD | Yes, on candles of `10m` and up and the last 7 days | Every interval, no history limit |
| Pool Bollinger Bands, VWAP | No, `403` | Yes |
| Token RSI, EMA, MACD, Bollinger Bands, VWAP | No, `403` | Yes |

Paid plans call `https://api-pro.dexpaprika.com` with the key as the entire `Authorization` header. Compare plans on [pricing](https://dexpaprika.com/api/pricing) and get a key in [console.dexpaprika.com](https://console.dexpaprika.com).

***

## The call

Hourly RSI for the USDC/WETH pool on Uniswap v3, last six hours, no key:

```bash theme={null}
curl "https://api.dexpaprika.com/networks/ethereum/pools/0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640/indicators/rsi?interval=1h&start=-6h"
```

```json theme={null}
{
  "network": "ethereum",
  "pool_address": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
  "indicator": "rsi",
  "interval": "1h",
  "parameters": {"period": 14},
  "data": [
    {"timestamp": "2026-10-12T05:00:00Z", "value": 64.33426700982189},
    {"timestamp": "2026-10-12T06:00:00Z", "value": 66.54753114766311},
    {"timestamp": "2026-10-12T07:00:00Z", "value": 61.156181549269995},
    {"timestamp": "2026-10-12T08:00:00Z", "value": 54.96220386541894},
    {"timestamp": "2026-10-12T09:00:00Z", "value": 57.865403918793895}
  ],
  "has_next_page": false,
  "next_cursor": ""
}
```

Values come oldest first, one per candle. `timestamp` is the candle's open time, and only completed candles count, so the candle that is still open has no value yet. `parameters` echoes what was used, defaults included.

Set `interval` every time. It defaults to `24h`, and on the free tier a daily series cut to the last 7 days is six values.

***

## The five indicators

Replace `rsi` in the path with the indicator you want. Pools use `/networks/{network}/pools/{pool_address}/indicators/{name}`, tokens use `/networks/{network}/tokens/{token_address}/indicators/{name}`.

| Indicator | Path | Parameters (default) | Each value carries |
| - | - | - | - |
| Relative Strength Index | `rsi` | `period` (14) | `value`, 0 to 100 |
| Exponential moving average | `ema` | `period` (20) | `value`, on the same price as the candles |
| MACD | `macd` | `fast_period` (12), `slow_period` (26), `signal_period` (9) | `macd`, `signal`, `histogram` |
| Bollinger Bands | `bbands` | `period` (20), `std_dev` (2) | `upper`, `middle`, `lower` |
| Rolling VWAP | `vwap` | `period` (14) | `value` |

Every indicator also takes:

| Parameter | What it does |
| - | - |
| `interval` | `1m`, `5m`, `10m`, `15m`, `30m`, `1h`, `6h`, `12h`, `24h` (default) or `1d`, which is the same as `24h` |
| `limit` | Values per response, 1 to 1000, default 100 |
| `start` | First candle: `-24h`, `-7d`, Unix seconds, RFC3339 or a date. Without it you get the last `limit` candles |
| `end` | End of the range, exclusive, same formats. Defaults to now |
| `cursor` | `next_cursor` from the previous page. Not combined with `start` |

With `start`, `limit` counts forward from it. When the range holds more candles than `limit`, `has_next_page` is `true` and `next_cursor` continues it.

***

## Screen a pool in Python

RSI over 70 is commonly read as overbought and under 30 as oversold. A MACD histogram that changes sign means MACD crossed its signal line. This script checks both on the last completed hourly candle:

```python theme={null}
import requests

API = "https://api.dexpaprika.com"


def indicator(network, pool, name, **params):
    r = requests.get(
        f"{API}/networks/{network}/pools/{pool}/indicators/{name}",
        params={"interval": "1h", "start": "-24h", **params},
        timeout=30,
    )
    r.raise_for_status()
    return r.json()["data"]


pool = "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640"  # USDC/WETH, Uniswap v3

rsi = indicator("ethereum", pool, "rsi")[-1]
macd = indicator("ethereum", pool, "macd")[-2:]

state = "overbought" if rsi["value"] > 70 else "oversold" if rsi["value"] < 30 else "neutral"
print(f"RSI(14) at {rsi['timestamp']}: {rsi['value']:.1f} ({state})")

prev, last = macd
if prev["histogram"] < 0 <= last["histogram"]:
    print(f"MACD crossed above its signal line at {last['timestamp']}")
elif prev["histogram"] > 0 >= last["histogram"]:
    print(f"MACD crossed below its signal line at {last['timestamp']}")
else:
    print(f"No MACD cross in the last candle (histogram {last['histogram']:.2f})")
```

```
RSI(14) at 2026-10-12T09:00:00Z: 60.4 (neutral)
No MACD cross in the last candle (histogram 0.71)
```

Two requests, two credits. A screen over many pools reaches the keyless [rate limit](/knowledge-base/rate-limits) quickly; a [free key](https://console.dexpaprika.com) raises it.

***

## Four things that will surprise you

**The same candle can get a different value from a different `start`.** RSI, EMA and MACD are smoothed: each value carries some weight from every candle before it. The API reads only the candles each indicator strictly needs before your `start`, 14 for RSI(14), so a short range starts the smoothing late. Hourly RSI(14) for one 09:00 candle on the pool above, measured on 12 October:

| `start` | RSI at 09:00 |
| - | - |
| `-6h` | 52.47 |
| `-24h` | 60.52 |
| `-3d` | 61.29 |
| `-7d` and earlier | 61.18, the same as from 30 days of candles |

Start at least ten periods before the first value you use, 140 candles for RSI(14), and keep the tail. On the free tier the 7-day window holds 168 hourly candles, which is enough at `1h` and shorter intervals, but only seven daily ones, so daily RSI and EMA need a paid plan to settle. The same effect explains differences from a charting site that has years of history behind each point.

**A short range on a quiet pool can fail.** The warm-up is measured in time, `period` intervals back, so minutes without a trade leave it short of candles. `interval=1m&limit=2` on the pool above answered `400` with `insufficient data: rsi needs at least 15 candles. Received 12`, and `limit=50` worked. Ask for more values than you need.

**Quiet intervals have no candle, so they have no value.** Indicators are computed over the candles that exist. On a thinly traded pool at `5m`, the period of an RSI spans more wall-clock time than you would expect.

**Pool indicators follow the pool's OHLCV price, with no way to flip it.** An EMA, Bollinger Band or VWAP on a pool is on the same price as [pool OHLCV](/tutorials/retrieve-historical-data) with its default `inversed=false`, and the indicator endpoints take no `inversed`. For one USD series across every pool a token trades in, use the token indicators, built on [token OHLCV](/tutorials/token-ohlcv).

***

## Errors

| Status | `error` | What happened |
| - | - | - |
| `403` | `plan_required`, no `param` | The endpoint needs Dev or higher: pool Bollinger Bands and VWAP, every token indicator |
| `403` | `plan_required`, `"param": "interval"` | An interval below `10m` without a paid plan |
| `403` | `plan_required`, `"param": "start"` | History before the last 7 days without a paid plan |
| `400` | `invalid_param` | A parameter out of range, named in `param`. For example `fast_period` must be below `slow_period` |
| `400` | `invalid_param`, no `param` | `insufficient data`: the range holds too few candles to compute the indicator. Widen it |
| `429` | `rate_limited` | Too many requests; wait `Retry-After` seconds |

A paid-only request without a paid key looks like this:

```json theme={null}
{"error": "plan_required", "tier": "keyless", "message": "this endpoint requires a Dev or Pro plan", "required_tier": "dev"}
```

More on [error handling](/knowledge-base/error-handling).

***

## Where to go next

* [Indicators reference](/api-reference/pools/get-rsi-for-a-pool): every endpoint, parameter and response code
* [Pool OHLCV](/tutorials/retrieve-historical-data): the candles behind the pool indicators
* [Token OHLCV](/tutorials/token-ohlcv): the USD candles behind the token indicators
* [Pricing](https://dexpaprika.com/api/pricing) and [console.dexpaprika.com](https://console.dexpaprika.com): plans and your key


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.