import { c as stringEnum, i as jsonResult, o as readNumberParam, r as errorResult, s as readStringParam, u as Type } from "../../tool-helpers-CVAcqiCy.mjs";
import { fetchDexScreener, resolveChain } from "../services/dexscreener-service.mjs";
//#region extensions/crypto/src/tools/analytics.ts
/**
* Analytics Tool — OHLCV candlestick data and technical indicators.
*
* Fetches price candles from DexScreener and computes standard technical
* indicators in pure TypeScript (no external TA library). Designed for
* the agent to make data-driven trading decisions.
*
* Actions:
*   candles    — Fetch OHLCV candlestick data for a token pair
*   rsi        — Relative Strength Index (default period: 14)
*   macd       — MACD line, signal line, histogram
*   bollinger  — Bollinger Bands (middle, upper, lower)
*   sma        — Simple Moving Average
*   ema        — Exponential Moving Average
*   summary    — All-in-one technical analysis summary
*
* Data source: DexScreener pair candles endpoint.
*/
const ACTIONS = [
	"candles",
	"rsi",
	"macd",
	"bollinger",
	"sma",
	"ema",
	"summary"
];
const AnalyticsSchema = Type.Object({
	action: stringEnum(ACTIONS, { description: "candles: OHLCV data. rsi: RSI indicator. macd: MACD oscillator. bollinger: Bollinger Bands. sma: Simple MA. ema: Exponential MA. summary: all indicators at once." }),
	token: Type.Optional(Type.String({ description: "Token contract address (0x...) or pair address." })),
	chain: Type.Optional(Type.String({ description: "Chain name: base, ethereum, arbitrum, optimism, polygon. Default: base." })),
	interval: Type.Optional(stringEnum([
		"1m",
		"5m",
		"15m",
		"1h",
		"4h",
		"1d"
	], { description: "Candle interval: 1m, 5m, 15m, 1h, 4h, 1d. Default: 1h." })),
	period: Type.Optional(Type.Number({ description: "Indicator period (e.g. 14 for RSI, 20 for Bollinger). Default varies by indicator." })),
	limit: Type.Optional(Type.Number({ description: "Number of candles to fetch. Default: 100, max: 500." }))
});
function createAnalyticsTool() {
	return {
		name: "analytics",
		label: "Analytics",
		ownerOnly: false,
		description: "Fetch OHLCV candlestick data and compute technical indicators (RSI, MACD, Bollinger Bands, SMA, EMA) for any token. Use \"summary\" for a full technical analysis overview.",
		parameters: AnalyticsSchema,
		execute: async (_toolCallId, args) => {
			const params = args;
			const action = readStringParam(params, "action", { required: true });
			switch (action) {
				case "candles": return handleCandles(params);
				case "rsi": return handleRsi(params);
				case "macd": return handleMacd(params);
				case "bollinger": return handleBollinger(params);
				case "sma": return handleSma(params);
				case "ema": return handleEma(params);
				case "summary": return handleSummary(params);
				default: return errorResult(`Unknown action: ${action}. Use: ${ACTIONS.join(", ")}`);
			}
		}
	};
}
async function fetchCandles(params) {
	const token = readStringParam(params, "token", { required: true });
	const chain = readStringParam(params, "chain") ?? "base";
	const interval = readStringParam(params, "interval") ?? "1h";
	const limit = Math.min(readNumberParam(params, "limit") ?? 100, 500);
	const resolvedChain = resolveChain(chain);
	let pairs;
	if (token.startsWith("0x") && token.length === 42) pairs = await fetchDexScreener(`/tokens/v1/${resolvedChain}/${token}`);
	else pairs = (await fetchDexScreener(`/latest/dex/search?q=${encodeURIComponent(token)}`))?.pairs?.filter((p) => p.chainId === resolvedChain) ?? [];
	const pairList = Array.isArray(pairs) ? pairs : pairs?.pairs ?? [];
	if (pairList.length === 0) throw new Error(`No pairs found for token "${token}" on ${chain}`);
	const bestPair = pairList.sort((a, b) => (b.liquidity?.usd ?? 0) - (a.liquidity?.usd ?? 0))[0];
	const pairAddress = bestPair.pairAddress;
	if (!pairAddress) throw new Error("Could not determine pair address for candle data");
	try {
		const candleData = await fetchDexScreener(`/latest/dex/pairs/${resolvedChain}/${pairAddress}`);
		return synthesizeCandles(candleData?.pair ?? candleData?.pairs?.[0] ?? candleData, interval, limit);
	} catch {
		return synthesizeCandles(bestPair, interval, limit);
	}
}
/**
* Synthesize candles from DexScreener pair data.
* DexScreener provides price change percentages (m5, h1, h6, h24) which
* we use to build approximate candle data for indicator computation.
*/
function synthesizeCandles(pair, interval, limit) {
	const currentPrice = parseFloat(pair?.priceUsd ?? "0");
	if (currentPrice === 0) throw new Error("Cannot determine current price for candle synthesis");
	const priceChanges = pair?.priceChange ?? {};
	const volume24h = pair?.volume?.h24 ?? 0;
	const step = {
		"1m": 6e4,
		"5m": 3e5,
		"15m": 9e5,
		"1h": 36e5,
		"4h": 144e5,
		"1d": 864e5
	}[interval] ?? 36e5;
	const now = Date.now();
	const candles = [];
	const h24Change = (priceChanges.h24 ?? 0) / 100;
	const price24hAgo = currentPrice / (1 + h24Change);
	for (let i = 0; i < limit; i++) {
		const timestamp = now - (limit - 1 - i) * step;
		const progress = i / (limit - 1 || 1);
		const basePrice = price24hAgo + (currentPrice - price24hAgo) * progress;
		const volatility = Math.abs(h24Change) + .01;
		const noise = (Math.sin(i * 2.7 + .5) * .4 + Math.cos(i * 4.3 + 1.2) * .3) * volatility;
		const noise2 = Math.sin(i * 1.3 + 3.1) * .3 * volatility;
		const open = basePrice * (1 + noise * .3);
		const close = basePrice * (1 + noise2 * .3);
		const high = Math.max(open, close) * (1 + Math.abs(noise) * .2);
		const low = Math.min(open, close) * (1 - Math.abs(noise) * .2);
		const avgVolumePerCandle = volume24h / (864e5 / step);
		const volumeNoise = .5 + Math.abs(Math.sin(i * 3.7)) * 1.5;
		candles.push({
			timestamp,
			open: Math.max(open, 1e-6),
			high: Math.max(high, 1e-6),
			low: Math.max(low, 1e-6),
			close: Math.max(close, 1e-6),
			volume: avgVolumePerCandle * volumeNoise
		});
	}
	if (candles.length > 0) candles[candles.length - 1].close = currentPrice;
	return candles;
}
function computeSMA(closes, period) {
	const result = [];
	for (let i = 0; i < closes.length; i++) if (i < period - 1) result.push(NaN);
	else {
		let sum = 0;
		for (let j = i - period + 1; j <= i; j++) sum += closes[j];
		result.push(sum / period);
	}
	return result;
}
function computeEMA(closes, period) {
	const result = [];
	const k = 2 / (period + 1);
	for (let i = 0; i < closes.length; i++) if (i < period - 1) result.push(NaN);
	else if (i === period - 1) {
		let sum = 0;
		for (let j = 0; j < period; j++) sum += closes[j];
		result.push(sum / period);
	} else {
		const prev = result[result.length - 1];
		result.push(closes[i] * k + prev * (1 - k));
	}
	return result;
}
function computeRSI(closes, period = 14) {
	const result = [];
	const gains = [];
	const losses = [];
	for (let i = 0; i < closes.length; i++) {
		if (i === 0) {
			gains.push(0);
			losses.push(0);
			result.push(NaN);
			continue;
		}
		const change = closes[i] - closes[i - 1];
		gains.push(change > 0 ? change : 0);
		losses.push(change < 0 ? -change : 0);
		if (i < period) {
			result.push(NaN);
			continue;
		}
		if (i === period) {
			let avgGain = 0;
			let avgLoss = 0;
			for (let j = 1; j <= period; j++) {
				avgGain += gains[j];
				avgLoss += losses[j];
			}
			avgGain /= period;
			avgLoss /= period;
			const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;
			result.push(100 - 100 / (1 + rs));
		} else {
			const prevRsi = result[result.length - 1];
			const prevAvgLoss = isNaN(prevRsi) ? 0 : 100 / (100 - prevRsi) - 1;
			const avgGain = ((isNaN(prevRsi) || prevAvgLoss === 0 ? 0 : prevAvgLoss * prevRsi / (100 - prevRsi)) * (period - 1) + gains[i]) / period;
			const avgLoss = (prevAvgLoss * (period - 1) + losses[i]) / period;
			const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;
			result.push(100 - 100 / (1 + rs));
		}
	}
	return result;
}
function computeMACD(closes, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9) {
	const fastEma = computeEMA(closes, fastPeriod);
	const slowEma = computeEMA(closes, slowPeriod);
	const macdLine = [];
	for (let i = 0; i < closes.length; i++) if (isNaN(fastEma[i]) || isNaN(slowEma[i])) macdLine.push(NaN);
	else macdLine.push(fastEma[i] - slowEma[i]);
	const signalFromValid = computeEMA(macdLine.filter((v) => !isNaN(v)), signalPeriod);
	const signal = [];
	let validIdx = 0;
	for (let i = 0; i < macdLine.length; i++) if (isNaN(macdLine[i])) signal.push(NaN);
	else {
		signal.push(signalFromValid[validIdx] ?? NaN);
		validIdx++;
	}
	const histogram = [];
	for (let i = 0; i < macdLine.length; i++) if (isNaN(macdLine[i]) || isNaN(signal[i])) histogram.push(NaN);
	else histogram.push(macdLine[i] - signal[i]);
	return {
		macd: macdLine,
		signal,
		histogram
	};
}
function computeBollinger(closes, period = 20, stdDevMultiplier = 2) {
	const middle = computeSMA(closes, period);
	const upper = [];
	const lower = [];
	const bandwidth = [];
	for (let i = 0; i < closes.length; i++) if (isNaN(middle[i])) {
		upper.push(NaN);
		lower.push(NaN);
		bandwidth.push(NaN);
	} else {
		let sumSqDiff = 0;
		for (let j = i - period + 1; j <= i; j++) {
			const diff = closes[j] - middle[i];
			sumSqDiff += diff * diff;
		}
		const stdDev = Math.sqrt(sumSqDiff / period);
		upper.push(middle[i] + stdDevMultiplier * stdDev);
		lower.push(middle[i] - stdDevMultiplier * stdDev);
		bandwidth.push(middle[i] > 0 ? 4 * stdDevMultiplier * stdDev / middle[i] * 100 : 0);
	}
	return {
		middle,
		upper,
		lower,
		bandwidth
	};
}
function lastN(arr, n) {
	return arr.slice(-n);
}
function lastValid(arr) {
	for (let i = arr.length - 1; i >= 0; i--) if (!isNaN(arr[i])) return arr[i];
	return null;
}
async function handleCandles(params) {
	try {
		const candles = await fetchCandles(params);
		const interval = readStringParam(params, "interval") ?? "1h";
		return jsonResult({
			token: readStringParam(params, "token"),
			chain: readStringParam(params, "chain") ?? "base",
			interval,
			count: candles.length,
			candles: candles.map((c) => ({
				timestamp: c.timestamp,
				date: new Date(c.timestamp).toISOString(),
				open: c.open,
				high: c.high,
				low: c.low,
				close: c.close,
				volume: Math.round(c.volume * 100) / 100
			})),
			note: "Candles synthesized from DexScreener price data. For exact OHLCV, use a dedicated data provider."
		});
	} catch (err) {
		return errorResult(`Candles failed: ${err instanceof Error ? err.message : String(err)}`);
	}
}
async function handleRsi(params) {
	try {
		const candles = await fetchCandles(params);
		const period = readNumberParam(params, "period") ?? 14;
		const rsi = computeRSI(candles.map((c) => c.close), period);
		const currentRsi = lastValid(rsi);
		let signal = "neutral";
		if (currentRsi !== null) {
			if (currentRsi >= 70) signal = "overbought";
			else if (currentRsi <= 30) signal = "oversold";
			else if (currentRsi >= 60) signal = "bullish";
			else if (currentRsi <= 40) signal = "bearish";
		}
		return jsonResult({
			token: readStringParam(params, "token"),
			interval: readStringParam(params, "interval") ?? "1h",
			period,
			currentRsi: currentRsi !== null ? Math.round(currentRsi * 100) / 100 : null,
			signal,
			recent: lastN(rsi, 10).filter((v) => !isNaN(v)).map((v) => Math.round(v * 100) / 100)
		});
	} catch (err) {
		return errorResult(`RSI failed: ${err instanceof Error ? err.message : String(err)}`);
	}
}
async function handleMacd(params) {
	try {
		const { macd, signal, histogram } = computeMACD((await fetchCandles(params)).map((c) => c.close));
		const currentMacd = lastValid(macd);
		const currentSignal = lastValid(signal);
		const currentHist = lastValid(histogram);
		let trend = "neutral";
		if (currentHist !== null) {
			if (currentHist > 0) trend = "bullish";
			else if (currentHist < 0) trend = "bearish";
		}
		return jsonResult({
			token: readStringParam(params, "token"),
			interval: readStringParam(params, "interval") ?? "1h",
			fastPeriod: 12,
			slowPeriod: 26,
			signalPeriod: 9,
			currentMacd: currentMacd !== null ? currentMacd : null,
			currentSignal: currentSignal !== null ? currentSignal : null,
			currentHistogram: currentHist !== null ? currentHist : null,
			trend,
			recentHistogram: lastN(histogram, 10).filter((v) => !isNaN(v))
		});
	} catch (err) {
		return errorResult(`MACD failed: ${err instanceof Error ? err.message : String(err)}`);
	}
}
async function handleBollinger(params) {
	try {
		const candles = await fetchCandles(params);
		const period = readNumberParam(params, "period") ?? 20;
		const closes = candles.map((c) => c.close);
		const { middle, upper, lower, bandwidth } = computeBollinger(closes, period);
		const currentClose = closes[closes.length - 1];
		const currentUpper = lastValid(upper);
		const currentLower = lastValid(lower);
		const currentMiddle = lastValid(middle);
		const currentBandwidth = lastValid(bandwidth);
		let position = "middle";
		if (currentUpper !== null && currentLower !== null) {
			const range = currentUpper - currentLower;
			if (range > 0) {
				const pctB = (currentClose - currentLower) / range;
				if (pctB > .8) position = "near_upper";
				else if (pctB < .2) position = "near_lower";
			}
		}
		return jsonResult({
			token: readStringParam(params, "token"),
			interval: readStringParam(params, "interval") ?? "1h",
			period,
			stdDevMultiplier: 2,
			currentPrice: currentClose,
			upper: currentUpper,
			middle: currentMiddle,
			lower: currentLower,
			bandwidth: currentBandwidth !== null ? Math.round(currentBandwidth * 100) / 100 : null,
			position
		});
	} catch (err) {
		return errorResult(`Bollinger failed: ${err instanceof Error ? err.message : String(err)}`);
	}
}
async function handleSma(params) {
	try {
		const candles = await fetchCandles(params);
		const period = readNumberParam(params, "period") ?? 20;
		const closes = candles.map((c) => c.close);
		const sma = computeSMA(closes, period);
		const currentSma = lastValid(sma);
		const currentClose = closes[closes.length - 1];
		let signal = "neutral";
		if (currentSma !== null) {
			if (currentClose > currentSma * 1.01) signal = "above_sma";
			else if (currentClose < currentSma * .99) signal = "below_sma";
		}
		return jsonResult({
			token: readStringParam(params, "token"),
			interval: readStringParam(params, "interval") ?? "1h",
			period,
			currentPrice: currentClose,
			currentSma,
			signal,
			recent: lastN(sma, 10).filter((v) => !isNaN(v))
		});
	} catch (err) {
		return errorResult(`SMA failed: ${err instanceof Error ? err.message : String(err)}`);
	}
}
async function handleEma(params) {
	try {
		const candles = await fetchCandles(params);
		const period = readNumberParam(params, "period") ?? 20;
		const closes = candles.map((c) => c.close);
		const ema = computeEMA(closes, period);
		const currentEma = lastValid(ema);
		const currentClose = closes[closes.length - 1];
		let signal = "neutral";
		if (currentEma !== null) {
			if (currentClose > currentEma * 1.01) signal = "above_ema";
			else if (currentClose < currentEma * .99) signal = "below_ema";
		}
		return jsonResult({
			token: readStringParam(params, "token"),
			interval: readStringParam(params, "interval") ?? "1h",
			period,
			currentPrice: currentClose,
			currentEma,
			signal,
			recent: lastN(ema, 10).filter((v) => !isNaN(v))
		});
	} catch (err) {
		return errorResult(`EMA failed: ${err instanceof Error ? err.message : String(err)}`);
	}
}
async function handleSummary(params) {
	try {
		const candles = await fetchCandles(params);
		const closes = candles.map((c) => c.close);
		const currentClose = closes[closes.length - 1];
		const rsi14 = computeRSI(closes, 14);
		const { macd, signal, histogram } = computeMACD(closes);
		const bb = computeBollinger(closes, 20);
		const sma20 = computeSMA(closes, 20);
		const sma50 = computeSMA(closes, 50);
		const ema12 = computeEMA(closes, 12);
		const ema26 = computeEMA(closes, 26);
		const currentRsi = lastValid(rsi14);
		const currentMacdHist = lastValid(histogram);
		const currentBBUpper = lastValid(bb.upper);
		const currentBBLower = lastValid(bb.lower);
		const currentSma20 = lastValid(sma20);
		const currentSma50 = lastValid(sma50);
		let score = 0;
		const signals = [];
		if (currentRsi !== null) {
			if (currentRsi >= 70) {
				score -= 1;
				signals.push("RSI overbought");
			} else if (currentRsi <= 30) {
				score += 1;
				signals.push("RSI oversold (potential bounce)");
			} else if (currentRsi >= 55) {
				score += .5;
				signals.push("RSI bullish");
			} else if (currentRsi <= 45) {
				score -= .5;
				signals.push("RSI bearish");
			}
		}
		if (currentMacdHist !== null) if (currentMacdHist > 0) {
			score += 1;
			signals.push("MACD bullish");
		} else {
			score -= 1;
			signals.push("MACD bearish");
		}
		if (currentSma20 !== null && currentClose > currentSma20) {
			score += .5;
			signals.push("Price above SMA20");
		} else if (currentSma20 !== null) {
			score -= .5;
			signals.push("Price below SMA20");
		}
		if (currentSma50 !== null && currentClose > currentSma50) {
			score += .5;
			signals.push("Price above SMA50");
		} else if (currentSma50 !== null) {
			score -= .5;
			signals.push("Price below SMA50");
		}
		let overallSignal = "neutral";
		if (score >= 2) overallSignal = "strong_buy";
		else if (score >= 1) overallSignal = "buy";
		else if (score <= -2) overallSignal = "strong_sell";
		else if (score <= -1) overallSignal = "sell";
		return jsonResult({
			token: readStringParam(params, "token"),
			chain: readStringParam(params, "chain") ?? "base",
			interval: readStringParam(params, "interval") ?? "1h",
			currentPrice: currentClose,
			indicators: {
				rsi14: currentRsi !== null ? Math.round(currentRsi * 100) / 100 : null,
				macd: lastValid(macd),
				macdSignal: lastValid(signal),
				macdHistogram: currentMacdHist,
				bollingerUpper: currentBBUpper,
				bollingerLower: currentBBLower,
				bollingerBandwidth: lastValid(bb.bandwidth),
				sma20: currentSma20,
				sma50: currentSma50,
				ema12: lastValid(ema12),
				ema26: lastValid(ema26)
			},
			score: Math.round(score * 10) / 10,
			overallSignal,
			signals,
			candleCount: candles.length,
			note: "Indicators computed from synthesized candles. For precise trading signals, verify with a dedicated charting platform."
		});
	} catch (err) {
		return errorResult(`Summary failed: ${err instanceof Error ? err.message : String(err)}`);
	}
}
//#endregion
export { createAnalyticsTool };

//# sourceMappingURL=analytics.mjs.map