Support and Resistance Shouldn't Depend on Whoever Is Drawing the Chart
Ask five traders to mark support and resistance on the same BTC chart and you'll get five different sets of lines. Some anchor on wicks, some on closes, some on "the level that felt important last month." None of it is reproducible, which makes it useless as an input to anything automated — a trading bot, a screener, an LLM agent deciding whether to flag a coin.
That's the gap GET /api/v1/indicators/technical closes. It ships an sr block per symbol — up to 3 support and 3 resistance levels, computed the same way every time from swing-high/low pivots on the daily series, no discretion involved. Feed it to a bot and it makes the same call you would, minus the hindsight bias.
This post covers how the levels are actually calculated, what strength and dist_pct mean, and how to combine sr with the other structure fields on the same endpoint — ma, bollinger, range_state, rsi — to build a simple resistance-approach screener.
How Are Support and Resistance Levels Calculated Here?
Three steps, all on the daily candle series, no manual input:
- Find swing pivots. A bar is a swing high if it's the highest high within 3 bars on each side (a "fractal" — the standard, simplest swing-point rule); a swing low is the mirror case on lows. This alone produces dozens of raw touch points per coin.
- Cluster them. Raw pivots within 1.5% of each other are merged into a single level, averaged to one price. A level with 4 pivots clustered into it has been tested 4 times — that's the
strengthfield. - Filter for relevance. Any clustered level more than 30% from the current price is dropped as not actionable, then the remaining levels are ranked nearest-to-price first and capped at 3 per side.
One detail that surprises people coming from manual chart reading: a cluster becomes support if it sits below current price and resistance if above — regardless of whether the pivots that built it were originally swing highs or swing lows. A broken resistance becomes support and vice versa, exactly like it does when you draw it by hand. The algorithm just tracks the flip automatically instead of you re-drawing the line.
Reading the Response: strength and dist_pct
Call the endpoint and each item in items[] carries an sr object alongside the other structure fields:
curl "https://cryptodataapi.com/api/v1/indicators/technical?source=binance_spot&limit=1" \
-H "X-API-Key: cdk_live_your_key"
A representative response shape:
{
"items": [
{
"symbol": "ETH",
"source": "binance_spot",
"price": 3120.45,
"sr": {
"support": [
{ "price": 3042.10, "strength": 4, "dist_pct": -2.51 },
{ "price": 2895.00, "strength": 2, "dist_pct": -7.22 },
{ "price": 2680.50, "strength": 6, "dist_pct": -14.09 }
],
"resistance": [
{ "price": 3210.75, "strength": 3, "dist_pct": 2.89 },
{ "price": 3450.00, "strength": 2, "dist_pct": 10.56 }
]
},
"range_state": { "zone": "mid", "position_pct": 61.4 },
"ma": { "above_200": true, "dist_from_200_pct": 8.3 },
"rsi": { "rsi_14_1d": 58.2, "state_1d": "neutral" }
}
],
"count": 1,
"universe_size": 214
}
Two fields do all the interpretive work:
dist_pctis the signed % distance from current price. Negative always means support (below price), positive always means resistance (above). No need to check which array you're in if you're scanning all levels at once.strengthis the pivot-touch count clustered into that level. Astrength: 6level has failed to break 6 separate times — treat it as considerably harder to clear than a freshstrength: 1level nobody has tested twice.
In the example above, ETH's nearest resistance at 3210.75 is only 2.89% away and has been touched 3 times — a real level actively containing price, not chart noise.
Support vs Resistance: Quick Reference
Both sides come from the identical pivot-clustering algorithm — only their position relative to price differs:
| Support | Resistance | |
|---|---|---|
| Position | Below current price | Above current price |
dist_pct sign | Negative | Positive |
| Sort order | Nearest (least negative) first | Nearest (smallest positive) first |
| Max levels | 3 | 3 |
| Interpretation | Price has bounced here before | Price has stalled here before |
| On a clean break | Becomes resistance if price falls back | Becomes support if price falls back |
That last row is the role-reversal behavior from the previous section — it's a property of the clustering, not a separate rule, so it shows up in the data automatically once price crosses a level and later retests it.
sr Is One Block — the Rest of the Structure Overlay
/indicators/technical returns sr alongside three other fields on the same per-symbol payload, all computed off the same universe of Binance spot pairs and Hyperliquid perps:
ma— SMA 50/100/200, distance from each in %, and the direction + age of the last golden/death cross.bollinger— 20-period/2σ bandwidth, a 90-day squeeze percentile, and whether the band is currently expanding.range_state— position within the trailing 20-day high/low, bucketed intonear_low/mid/near_high.rsi— 14-period RSI on both daily and 1h timeframes, with overbought/oversold/extreme flags and how many bars an extreme has persisted.
sr is the sharpest tool for "where exactly is price likely to react," but it reads best paired with the others — range_state and ma tell you the broader trend context a level is sitting inside.
Worked Example: Flag Coins Approaching Resistance in an Uptrend
A single level in isolation is weak signal. Combine sr with the built-in filters and it becomes a screener. The endpoint takes ma_state, bb, range_zone, rsi, source, sort, order and limit, all AND-combined server-side:
curl "https://cryptodataapi.com/api/v1/indicators/technical?range_zone=near_high&ma_state=above_200" \
-H "X-API-Key: cdk_live_your_key"
That query alone returns coins sitting near the top of their 20-day range while above their 200-day SMA — price approaching resistance inside an established uptrend, not a random spike. Client-side, add one more filter: keep only items whose nearest resistance[0].dist_pct is under 2% and whose strength is 2 or higher, to exclude untested levels.
Two more screener queries straight from the endpoint's own filters:
?bb=in_squeeze&sort=squeeze_days&order=desc— coins compressed the longest, i.e. building energy near a level rather than drifting into it.?rsi=oversold&min_days_in_state=2— sustained oversold readings, useful for cross-checking a support bounce isn't just noise.
None of this requires plotting a single candle. It's three HTTP filters and a two-field client-side check.
When to Use This (and Its Limits)
Use it for: setting bot stop-loss / take-profit levels off real structure instead of a fixed %, screening for coins approaching a well-tested level, and confirming a breakout by checking whether price has cleared a strength-3+ level rather than a throwaway one.
Don't use it for: intraday scalping — the pivots are computed on daily bars, so levels update once a day, not tick by tick. And a level with strength: 1 is barely more than a single wick; weight it accordingly rather than trading it like a strength: 5 level.
The endpoint is Pro tier, covers both binance_spot and hyperliquid_perp sources, and returns the full universe (200+ symbols) in one call — no per-symbol looping required for a screener.



