| import type { Candle, SRLevel } from './types' |
|
|
| export function findSupportResistance(candles: Candle[], numLevels = 6): SRLevel[] { |
| if (candles.length < 20) return [] |
| const levels: SRLevel[] = [] |
| const tolerance = 0.015 |
|
|
| |
| const peaks: number[] = [] |
| const troughs: number[] = [] |
| for (let i = 2; i < candles.length - 2; i++) { |
| const c = candles[i] |
| if (c.high >= candles[i - 1].high && c.high >= candles[i - 2].high && |
| c.high >= candles[i + 1].high && c.high >= candles[i + 2].high) { |
| peaks.push(c.high) |
| } |
| if (c.low <= candles[i - 1].low && c.low <= candles[i - 2].low && |
| c.low <= candles[i + 1].low && c.low <= candles[i + 2].low) { |
| troughs.push(c.low) |
| } |
| } |
|
|
| |
| function cluster(arr: number[]): { price: number; count: number }[] { |
| if (!arr.length) return [] |
| const sorted = [...arr].sort((a, b) => a - b) |
| const clusters: { prices: number[]; sum: number }[] = [] |
| for (const p of sorted) { |
| let found = false |
| for (const c of clusters) { |
| const avg = c.sum / c.prices.length |
| if (Math.abs(p - avg) / avg < tolerance) { |
| c.prices.push(p); c.sum += p; found = true; break |
| } |
| } |
| if (!found) clusters.push({ prices: [p], sum: p }) |
| } |
| return clusters |
| .map((c) => ({ price: c.sum / c.prices.length, count: c.prices.length })) |
| .sort((a, b) => b.count - a.count) |
| } |
|
|
| const lastPrice = candles[candles.length - 1].close |
|
|
| for (const { price, count } of cluster(troughs).slice(0, numLevels)) { |
| if (price < lastPrice) { |
| levels.push({ price, type: 'support', strength: Math.min(5, count), touches: count }) |
| } |
| } |
| for (const { price, count } of cluster(peaks).slice(0, numLevels)) { |
| if (price > lastPrice) { |
| levels.push({ price, type: 'resistance', strength: Math.min(5, count), touches: count }) |
| } |
| } |
|
|
| return levels.sort((a, b) => a.price - b.price).slice(0, numLevels) |
| } |
|
|