ta_summary
Calculate RSI and Bollinger Bands simultaneously for crypto market analysis. Input price data to get technical indicators for evaluating token performance.
Instructions
Return both RSI and Bollinger in one call. Inputs: values:number[] (oldest→newest), rsiPeriod?:number(14), bbPeriod?:number(20), bbMult?:number(2).
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| values | Yes | ||
| rsiPeriod | No | ||
| bbPeriod | No | ||
| bbMult | No |
Implementation Reference
- mcp-server.js:250-261 (handler)Handler function for the 'ta_summary' tool. Validates input, calls RSI and Bollinger helpers, and returns combined results."ta_summary": async (args) => { const values = Array.isArray(args?.values) ? args.values : null; const rsiPeriod = Number.isFinite(Number(args?.rsiPeriod)) ? Number(args.rsiPeriod) : 14; const bbPeriod = Number.isFinite(Number(args?.bbPeriod)) ? Number(args.bbPeriod) : 20; const bbMult = Number.isFinite(Number(args?.bbMult)) ? Number(args.bbMult) : 2; if (!values || values.length === 0) { return { content: textContent({ error:true, message:"'values' must be a non-empty array of numbers (oldest → newest)" }), isError:true }; } const rsiVal = taRSI(values, rsiPeriod); const bbVal = taBoll(values, bbPeriod, bbMult); return { content: textContent({ ok:true, rsi: rsiVal, bollinger: bbVal, rsiPeriod, bbPeriod, bbMult }) }; }
- mcp-server.js:345-353 (registration)Tool registration entry for 'ta_summary', including input schema, description, and annotations used in tools/list response.{ name:"ta_summary", description:"Return both RSI and Bollinger in one call. Inputs: values:number[] (oldest→newest), rsiPeriod?:number(14), bbPeriod?:number(20), bbMult?:number(2).", inputSchema:{ type:"object", properties:{ values:{ type:"array", items:{ type:"number" } }, rsiPeriod:{ type:"number" }, bbPeriod:{ type:"number" }, bbMult:{ type:"number" } }, required:["values"] }, annotations:{ title:"TA: Summary", readOnlyHint:true, openWorldHint:false }
- services/ta.js:12-47 (helper)Pure RSI computation function (taRSI alias), called by ta_summary handler.export function rsi(values, period = 14) { const arr = normalize(values); if (arr.length < period + 1) return null; // Seed averages over the first `period` deltas let gains = 0, losses = 0; for (let i = 1; i <= period; i++) { const d = arr[i] - arr[i - 1]; if (d >= 0) gains += d; else losses -= d; } let avgGain = gains / period; let avgLoss = losses / period; // Wilder smoothing for the remaining deltas for (let i = period + 1; i < arr.length; i++) { const d = arr[i] - arr[i - 1]; const gain = d > 0 ? d : 0; const loss = d < 0 ? -d : 0; avgGain = (avgGain * (period - 1) + gain) / period; avgLoss = (avgLoss * (period - 1) + loss) / period; } if (!isFiniteNum(avgGain) || !isFiniteNum(avgLoss)) return null; // Handle flat / division-by-zero cases explicitly if (avgLoss === 0) { if (avgGain === 0) return 50; // perfectly flat return 100; // only gains } const rs = avgGain / avgLoss; if (!isFiniteNum(rs)) return null; const rsi = 100 - (100 / (1 + rs)); return isFiniteNum(rsi) ? clamp(rsi, 0, 100) : null; }
- services/ta.js:57-95 (helper)Pure Bollinger Bands computation function (taBoll alias), called by ta_summary handler.export function bollinger(values, period = 20, mult = 2) { const arr = normalize(values); if (arr.length < period) return null; const slice = arr.slice(-period); const mean = avg(slice); if (!isFiniteNum(mean)) return null; const variance = avg(slice.map(v => (v - mean) * (v - mean))); const stdev = Math.sqrt(variance); if (!isFiniteNum(stdev)) return null; const upper = mean + mult * stdev; const lower = mean - mult * stdev; const last = arr[arr.length - 1]; // Avoid division by zero in derived metrics const denomBands = upper - lower; const denomMean = mean; const percentB = isFiniteNum(denomBands) && denomBands !== 0 ? (last - lower) / denomBands : null; const bandwidth = isFiniteNum(denomMean) && denomMean !== 0 ? (upper - lower) / denomMean : null; return { mean, upper, lower, last, percentB: isFiniteNum(percentB) ? percentB : null, bandwidth: isFiniteNum(bandwidth) ? bandwidth : null }; }