Herramienta de Webhook de indicadores técnicos de Binance
Este es unFinance, AIflujo de automatización del dominio deautomatización que contiene 69 nodos.Utiliza principalmente nodos como Code, Merge, Webhook, HttpRequest, RespondToWebhook, combinando tecnología de inteligencia artificial para lograr automatización inteligente. Herramienta de Webhook de indicadores técnicos de Binance
- •Punto final de HTTP Webhook (n8n generará automáticamente)
- •Pueden requerirse credenciales de autenticación para la API de destino
Nodos utilizados (69)
Categoría
{
"id": "HrTD222kWpvKsy2j",
"meta": {
"instanceId": "a5283507e1917a33cc3ae615b2e7d5ad2c1e50955e6f831272ddd5ab816f3fb6"
},
"name": "Binance SM Indicators Webhook Tool",
"tags": [],
"nodes": [
{
"id": "61cb3bd7-60ba-4dcf-a080-146b7612a99b",
"name": "Solicitud HTTP",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1080,
0
],
"parameters": {
"url": "https://api.binance.com/api/v3/klines",
"options": {},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "symbol",
"value": "={{$json.body.symbol}}"
},
{
"name": "interval",
"value": "15m"
},
{
"name": "limit",
"value": "40"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "b372f57e-917a-42d2-964c-25a296ea982d",
"name": "Indicadores Disparador Webhook 15m",
"type": "n8n-nodes-base.webhook",
"position": [
-1460,
0
],
"webhookId": "39cc366c-af5f-472a-9d48-bbe30a4fe3ea",
"parameters": {
"path": "39cc366c-af5f-472a-9d48-bbe30a4fe3ea",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "46b937d5-7338-457f-b2f0-eb85ac44a8bb",
"name": "Combinar en 1 Array",
"type": "n8n-nodes-base.code",
"position": [
-740,
0
],
"parameters": {
"jsCode": "const klines = $input.all().map(item => item.json);\nreturn [{ json: { klines } }];"
},
"typeVersion": 2
},
{
"id": "5b8c1049-bcf4-41d4-bba3-5f76e940bd3e",
"name": "Calcular Bandas de Bollinger",
"type": "n8n-nodes-base.code",
"position": [
-280,
-460
],
"parameters": {
"jsCode": "// Get raw klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20;\nconst stdMultiplier = 2;\n\n// Validate type\nif (!Array.isArray(klines)) {\n throw new Error(\"klines is not an array\");\n}\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Ensure enough data\nif (closes.length < period) {\n throw new Error(`Not enough data: got ${closes.length}, expected at least ${period}`);\n}\n\n// BB calculation logic\nfunction calculateBB(prices, period) {\n const result = [];\n for (let i = period - 1; i < prices.length; i++) {\n const slice = prices.slice(i - period + 1, i + 1);\n const mean = slice.reduce((sum, val) => sum + val, 0) / period;\n const variance = slice.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / period;\n const stdDev = Math.sqrt(variance);\n\n result.push({\n close: prices[i],\n basis: mean,\n upper: mean + stdMultiplier * stdDev,\n lower: mean - stdMultiplier * stdDev,\n timestamp: klines[i][0]\n });\n }\n return result;\n}\n\n// Calculate bands\nconst bands = calculateBB(closes, period);\n\n// Format output\nreturn bands.map(b => ({\n json: {\n timestamp: b.timestamp,\n close: b.close,\n bb_basis: b.basis,\n bb_upper: b.upper,\n bb_lower: b.lower\n }\n}));"
},
"typeVersion": 2
},
{
"id": "b0391e28-03a3-40f0-8182-72df0928ca2c",
"name": "Calcular RSI",
"type": "n8n-nodes-base.code",
"position": [
-280,
-240
],
"parameters": {
"jsCode": "// Pull klines array from JSON\nconst klines = $input.first().json.klines;\n\n// === CONFIGURATION ===\nconst period = 14; // RSI period\n\n// === Extract closing prices ===\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// === Ensure enough data ===\nif (closes.length < period + 1) {\n throw new Error(`Not enough data for RSI. Need at least ${period + 1}, got ${closes.length}`);\n}\n\n// === RSI Calculation ===\nfunction calculateRSI(prices, period) {\n const result = [];\n\n for (let i = period; i < prices.length; i++) {\n let gains = 0;\n let losses = 0;\n\n for (let j = i - period + 1; j <= i; j++) {\n const change = prices[j] - prices[j - 1];\n if (change >= 0) gains += change;\n else losses -= change;\n }\n\n const avgGain = gains / period;\n const avgLoss = losses / period;\n\n const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;\n const rsi = avgLoss === 0 ? 100 : 100 - (100 / (1 + rs));\n\n result.push({\n timestamp: klines[i][0],\n close: prices[i],\n rsi: rsi\n });\n }\n\n return result;\n}\n\n// === Run RSI ===\nconst rsiSeries = calculateRSI(closes, period);\n\n// === Return formatted RSI output ===\nreturn rsiSeries.map(r => ({\n json: {\n timestamp: r.timestamp,\n close: r.close,\n rsi: r.rsi\n }\n}));"
},
"typeVersion": 2
},
{
"id": "2c598960-630c-4687-91c0-bfae10da1943",
"name": "Calcular MACD",
"type": "n8n-nodes-base.code",
"position": [
-280,
-40
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Parameters\nconst fastPeriod = 12;\nconst slowPeriod = 26;\nconst signalPeriod = 9;\n\n// Validate data length\nconst minRequired = slowPeriod + signalPeriod;\nif (closes.length < minRequired) {\n throw new Error(`Not enough data for MACD. Need at least ${minRequired}, got ${closes.length}`);\n}\n\n// === Helper: EMA function ===\nfunction calculateEMA(prices, period) {\n const k = 2 / (period + 1);\n const ema = [prices.slice(0, period).reduce((a, b) => a + b, 0) / period];\n\n for (let i = period; i < prices.length; i++) {\n ema.push(prices[i] * k + ema[ema.length - 1] * (1 - k));\n }\n\n return ema;\n}\n\n// === MACD Core Calculation ===\nconst slowEMA = calculateEMA(closes, slowPeriod);\nconst fastEMA = calculateEMA(closes.slice(slowPeriod - fastPeriod), fastPeriod);\n\n// Align lengths\nconst alignedFastEMA = fastEMA.slice(fastEMA.length - slowEMA.length);\nconst macdLine = alignedFastEMA.map((val, i) => val - slowEMA[i]);\n\n// Signal line\nconst signalLine = calculateEMA(macdLine, signalPeriod);\n\n// Histogram\nconst histogram = macdLine.slice(signalPeriod - 1).map((macd, i) => macd - signalLine[i]);\n\n// Final output start index\nconst startIndex = closes.length - histogram.length;\n\nconst result = [];\n\nfor (let i = 0; i < histogram.length; i++) {\n const idx = startIndex + i;\n result.push({\n timestamp: klines[idx]?.[0] || null,\n close: closes[idx],\n macd: macdLine[i + signalPeriod - 1],\n signal: signalLine[i],\n histogram: histogram[i]\n });\n}\n\nreturn result.map(r => ({\n json: r\n}));"
},
"typeVersion": 2
},
{
"id": "c50f7fa5-2707-47a4-9b32-1d582bf5d600",
"name": "Calcular SMA",
"type": "n8n-nodes-base.code",
"position": [
-280,
200
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20; // Change to 50, 100, 200, etc. as needed\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Check for sufficient data\nif (closes.length < period) {\n throw new Error(`Not enough data to compute SMA. Need at least ${period}, got ${closes.length}`);\n}\n\n// Calculate SMA values\nconst result = [];\n\nfor (let i = period - 1; i < closes.length; i++) {\n const slice = closes.slice(i - period + 1, i + 1);\n const sum = slice.reduce((a, b) => a + b, 0);\n const average = sum / period;\n\n result.push({\n timestamp: klines[i][0],\n close: closes[i],\n sma: average\n });\n}\n\n// Return formatted output\nreturn result.map(r => ({\n json: r\n}));"
},
"typeVersion": 2
},
{
"id": "25ef2964-c9b1-4b9e-b6ce-3766b215d163",
"name": "Calcular EMA",
"type": "n8n-nodes-base.code",
"position": [
-280,
420
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20; // Change to 9, 12, 26, 50, etc. as needed\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Check for sufficient data\nif (closes.length < period) {\n throw new Error(`Not enough data to compute EMA. Need at least ${period}, got ${closes.length}`);\n}\n\n// EMA Calculation\nconst k = 2 / (period + 1);\nconst ema = [];\n\n// Start with SMA of first period\nlet sma = closes.slice(0, period).reduce((a, b) => a + b, 0) / period;\nema.push({\n timestamp: klines[period - 1][0],\n close: closes[period - 1],\n ema: sma\n});\n\n// Continue EMA calculation\nfor (let i = period; i < closes.length; i++) {\n const value = closes[i] * k + ema[ema.length - 1].ema * (1 - k);\n ema.push({\n timestamp: klines[i][0],\n close: closes[i],\n ema: value\n });\n}\n\n// Return result\nreturn ema.map(e => ({\n json: e\n}));"
},
"typeVersion": 2
},
{
"id": "df6546be-3778-4fba-801a-870c0fe883c3",
"name": "Calcular ADX",
"type": "n8n-nodes-base.code",
"position": [
-280,
660
],
"parameters": {
"jsCode": "// Get kline array from merged item\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 14;\n\n// Parse high, low, close arrays\nconst highs = klines.map(k => parseFloat(k[2]));\nconst lows = klines.map(k => parseFloat(k[3]));\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Validation\nif (closes.length < period + 1) {\n throw new Error(`Not enough data for ADX. Need at least ${period + 1}, got ${closes.length}`);\n}\n\n// Initialize arrays\nconst tr = [];\nconst plusDM = [];\nconst minusDM = [];\n\n// Step 1: Calculate TR, +DM, -DM\nfor (let i = 1; i < klines.length; i++) {\n const highDiff = highs[i] - highs[i - 1];\n const lowDiff = lows[i - 1] - lows[i];\n const upMove = highDiff > 0 && highDiff > lowDiff ? highDiff : 0;\n const downMove = lowDiff > 0 && lowDiff > highDiff ? lowDiff : 0;\n\n const trueRange = Math.max(\n highs[i] - lows[i],\n Math.abs(highs[i] - closes[i - 1]),\n Math.abs(lows[i] - closes[i - 1])\n );\n\n tr.push(trueRange);\n plusDM.push(upMove);\n minusDM.push(downMove);\n}\n\n// Step 2: Smooth TR, +DM, -DM and calculate DI\nconst smoothedTR = [tr.slice(0, period).reduce((a, b) => a + b, 0)];\nconst smoothedPlusDM = [plusDM.slice(0, period).reduce((a, b) => a + b, 0)];\nconst smoothedMinusDM = [minusDM.slice(0, period).reduce((a, b) => a + b, 0)];\n\nfor (let i = period; i < tr.length; i++) {\n smoothedTR.push(smoothedTR[smoothedTR.length - 1] - smoothedTR[smoothedTR.length - 1] / period + tr[i]);\n smoothedPlusDM.push(smoothedPlusDM[smoothedPlusDM.length - 1] - smoothedPlusDM[smoothedPlusDM.length - 1] / period + plusDM[i]);\n smoothedMinusDM.push(smoothedMinusDM[smoothedMinusDM.length - 1] - smoothedMinusDM[smoothedMinusDM.length - 1] / period + minusDM[i]);\n}\n\nconst plusDI = smoothedPlusDM.map((val, i) => 100 * val / smoothedTR[i]);\nconst minusDI = smoothedMinusDM.map((val, i) => 100 * val / smoothedTR[i]);\n\n// Step 3: Calculate DX\nconst dx = plusDI.map((val, i) => {\n const diff = Math.abs(plusDI[i] - minusDI[i]);\n const sum = plusDI[i] + minusDI[i];\n return sum === 0 ? 0 : 100 * (diff / sum);\n});\n\n// Step 4: Smooth DX into ADX\nconst adx = [];\nconst firstADX = dx.slice(0, period).reduce((a, b) => a + b, 0) / period;\nadx.push(firstADX);\n\nfor (let i = period; i < dx.length; i++) {\n const newADX = (adx[adx.length - 1] * (period - 1) + dx[i]) / period;\n adx.push(newADX);\n}\n\n// Step 5: Final result formatting\nconst output = [];\n\nfor (let i = 0; i < adx.length; i++) {\n const index = i + (2 * period); // account for offset\n if (klines[index]) {\n output.push({\n timestamp: klines[index][0],\n close: closes[index],\n adx: adx[i],\n plusDI: plusDI[i + period],\n minusDI: minusDI[i + period]\n });\n }\n}\n\nreturn output.map(r => ({ json: r }));"
},
"typeVersion": 2
},
{
"id": "5ea4756f-a20a-444c-8471-57d209457823",
"name": "Combinar Indicadores 15 min",
"type": "n8n-nodes-base.merge",
"position": [
180,
-80
],
"parameters": {
"numberInputs": 6
},
"typeVersion": 3.1
},
{
"id": "0a46ea7c-a85d-4fc6-b20c-7e65ab962ea6",
"name": "Responder a Disparador Webhook 15m",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
560,
-20
],
"parameters": {
"options": {},
"respondWith": "allIncomingItems"
},
"typeVersion": 1.3
},
{
"id": "40fcbba9-489b-4452-baf8-9a41ef0f9b07",
"name": "Indicadores Disparador Webhook 1h",
"type": "n8n-nodes-base.webhook",
"position": [
-3220,
1760
],
"webhookId": "78948764-5cdb-4808-8ef9-2155f10dd721",
"parameters": {
"path": "78948764-5cdb-4808-8ef9-2155f10dd721",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "39e6b058-d800-4751-b75b-5e62be379c61",
"name": "Responder a Disparador Webhook 1h",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
-1060,
1740
],
"parameters": {
"options": {},
"respondWith": "allIncomingItems"
},
"typeVersion": 1.3
},
{
"id": "af471a36-1107-4ccd-be14-efa06ba27330",
"name": "Combinar Indicadores 1h",
"type": "n8n-nodes-base.merge",
"position": [
-1460,
1680
],
"parameters": {
"numberInputs": 6
},
"typeVersion": 3.1
},
{
"id": "d7d9bb31-6986-42e6-9f0c-7d7f00d66ee1",
"name": "Combinar en 1 Array 1h",
"type": "n8n-nodes-base.code",
"position": [
-2540,
1760
],
"parameters": {
"jsCode": "const klines = $input.all().map(item => item.json);\nreturn [{ json: { klines } }];"
},
"typeVersion": 2
},
{
"id": "a2e9d933-47d7-47f5-8d49-224860d8600a",
"name": "Calcular Bandas de Bollinger(1h)",
"type": "n8n-nodes-base.code",
"position": [
-2060,
1220
],
"parameters": {
"jsCode": "// Get raw klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20;\nconst stdMultiplier = 2;\n\n// Validate type\nif (!Array.isArray(klines)) {\n throw new Error(\"klines is not an array\");\n}\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Ensure enough data\nif (closes.length < period) {\n throw new Error(`Not enough data: got ${closes.length}, expected at least ${period}`);\n}\n\n// BB calculation logic\nfunction calculateBB(prices, period) {\n const result = [];\n for (let i = period - 1; i < prices.length; i++) {\n const slice = prices.slice(i - period + 1, i + 1);\n const mean = slice.reduce((sum, val) => sum + val, 0) / period;\n const variance = slice.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / period;\n const stdDev = Math.sqrt(variance);\n\n result.push({\n close: prices[i],\n basis: mean,\n upper: mean + stdMultiplier * stdDev,\n lower: mean - stdMultiplier * stdDev,\n timestamp: klines[i][0]\n });\n }\n return result;\n}\n\n// Calculate bands\nconst bands = calculateBB(closes, period);\n\n// Format output\nreturn bands.map(b => ({\n json: {\n timestamp: b.timestamp,\n close: b.close,\n bb_basis: b.basis,\n bb_upper: b.upper,\n bb_lower: b.lower\n }\n}));"
},
"typeVersion": 2
},
{
"id": "702e8bc8-d8f0-4fb4-b44f-fd19479c8b03",
"name": "Calcular RSI(1h)",
"type": "n8n-nodes-base.code",
"position": [
-2060,
1500
],
"parameters": {
"jsCode": "// Pull klines array from JSON\nconst klines = $input.first().json.klines;\n\n// === CONFIGURATION ===\nconst period = 14; // RSI period\n\n// === Extract closing prices ===\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// === Ensure enough data ===\nif (closes.length < period + 1) {\n throw new Error(`Not enough data for RSI. Need at least ${period + 1}, got ${closes.length}`);\n}\n\n// === RSI Calculation ===\nfunction calculateRSI(prices, period) {\n const result = [];\n\n for (let i = period; i < prices.length; i++) {\n let gains = 0;\n let losses = 0;\n\n for (let j = i - period + 1; j <= i; j++) {\n const change = prices[j] - prices[j - 1];\n if (change >= 0) gains += change;\n else losses -= change;\n }\n\n const avgGain = gains / period;\n const avgLoss = losses / period;\n\n const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;\n const rsi = avgLoss === 0 ? 100 : 100 - (100 / (1 + rs));\n\n result.push({\n timestamp: klines[i][0],\n close: prices[i],\n rsi: rsi\n });\n }\n\n return result;\n}\n\n// === Run RSI ===\nconst rsiSeries = calculateRSI(closes, period);\n\n// === Return formatted RSI output ===\nreturn rsiSeries.map(r => ({\n json: {\n timestamp: r.timestamp,\n close: r.close,\n rsi: r.rsi\n }\n}));"
},
"typeVersion": 2
},
{
"id": "d16b7829-59ca-45ca-a5ae-4e315168c96d",
"name": "Calcular MACD(1h)",
"type": "n8n-nodes-base.code",
"position": [
-2060,
1720
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Parameters\nconst fastPeriod = 12;\nconst slowPeriod = 26;\nconst signalPeriod = 9;\n\n// Validate data length\nconst minRequired = slowPeriod + signalPeriod;\nif (closes.length < minRequired) {\n throw new Error(`Not enough data for MACD. Need at least ${minRequired}, got ${closes.length}`);\n}\n\n// === Helper: EMA function ===\nfunction calculateEMA(prices, period) {\n const k = 2 / (period + 1);\n const ema = [prices.slice(0, period).reduce((a, b) => a + b, 0) / period];\n\n for (let i = period; i < prices.length; i++) {\n ema.push(prices[i] * k + ema[ema.length - 1] * (1 - k));\n }\n\n return ema;\n}\n\n// === MACD Core Calculation ===\nconst slowEMA = calculateEMA(closes, slowPeriod);\nconst fastEMA = calculateEMA(closes.slice(slowPeriod - fastPeriod), fastPeriod);\n\n// Align lengths\nconst alignedFastEMA = fastEMA.slice(fastEMA.length - slowEMA.length);\nconst macdLine = alignedFastEMA.map((val, i) => val - slowEMA[i]);\n\n// Signal line\nconst signalLine = calculateEMA(macdLine, signalPeriod);\n\n// Histogram\nconst histogram = macdLine.slice(signalPeriod - 1).map((macd, i) => macd - signalLine[i]);\n\n// Final output start index\nconst startIndex = closes.length - histogram.length;\n\nconst result = [];\n\nfor (let i = 0; i < histogram.length; i++) {\n const idx = startIndex + i;\n result.push({\n timestamp: klines[idx]?.[0] || null,\n close: closes[idx],\n macd: macdLine[i + signalPeriod - 1],\n signal: signalLine[i],\n histogram: histogram[i]\n });\n}\n\nreturn result.map(r => ({\n json: r\n}));"
},
"typeVersion": 2
},
{
"id": "15bf5c3b-de07-412b-988c-f5c59fa7a06f",
"name": "Calcular SMA(1h)",
"type": "n8n-nodes-base.code",
"position": [
-2060,
1960
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20; // Change to 50, 100, 200, etc. as needed\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Check for sufficient data\nif (closes.length < period) {\n throw new Error(`Not enough data to compute SMA. Need at least ${period}, got ${closes.length}`);\n}\n\n// Calculate SMA values\nconst result = [];\n\nfor (let i = period - 1; i < closes.length; i++) {\n const slice = closes.slice(i - period + 1, i + 1);\n const sum = slice.reduce((a, b) => a + b, 0);\n const average = sum / period;\n\n result.push({\n timestamp: klines[i][0],\n close: closes[i],\n sma: average\n });\n}\n\n// Return formatted output\nreturn result.map(r => ({\n json: r\n}));"
},
"typeVersion": 2
},
{
"id": "83fa487a-1a67-4059-9007-d5298d8bb105",
"name": "Calcular EMA(1h)",
"type": "n8n-nodes-base.code",
"position": [
-2060,
2220
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20; // Change to 9, 12, 26, 50, etc. as needed\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Check for sufficient data\nif (closes.length < period) {\n throw new Error(`Not enough data to compute EMA. Need at least ${period}, got ${closes.length}`);\n}\n\n// EMA Calculation\nconst k = 2 / (period + 1);\nconst ema = [];\n\n// Start with SMA of first period\nlet sma = closes.slice(0, period).reduce((a, b) => a + b, 0) / period;\nema.push({\n timestamp: klines[period - 1][0],\n close: closes[period - 1],\n ema: sma\n});\n\n// Continue EMA calculation\nfor (let i = period; i < closes.length; i++) {\n const value = closes[i] * k + ema[ema.length - 1].ema * (1 - k);\n ema.push({\n timestamp: klines[i][0],\n close: closes[i],\n ema: value\n });\n}\n\n// Return result\nreturn ema.map(e => ({\n json: e\n}));"
},
"typeVersion": 2
},
{
"id": "7301ba32-ab0c-4c80-b041-cd398f7daa2c",
"name": "Calcular ADX1",
"type": "n8n-nodes-base.code",
"position": [
-2060,
2420
],
"parameters": {
"jsCode": "// Get kline array from merged item\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 14;\n\n// Parse high, low, close arrays\nconst highs = klines.map(k => parseFloat(k[2]));\nconst lows = klines.map(k => parseFloat(k[3]));\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Validation\nif (closes.length < period + 1) {\n throw new Error(`Not enough data for ADX. Need at least ${period + 1}, got ${closes.length}`);\n}\n\n// Initialize arrays\nconst tr = [];\nconst plusDM = [];\nconst minusDM = [];\n\n// Step 1: Calculate TR, +DM, -DM\nfor (let i = 1; i < klines.length; i++) {\n const highDiff = highs[i] - highs[i - 1];\n const lowDiff = lows[i - 1] - lows[i];\n const upMove = highDiff > 0 && highDiff > lowDiff ? highDiff : 0;\n const downMove = lowDiff > 0 && lowDiff > highDiff ? lowDiff : 0;\n\n const trueRange = Math.max(\n highs[i] - lows[i],\n Math.abs(highs[i] - closes[i - 1]),\n Math.abs(lows[i] - closes[i - 1])\n );\n\n tr.push(trueRange);\n plusDM.push(upMove);\n minusDM.push(downMove);\n}\n\n// Step 2: Smooth TR, +DM, -DM and calculate DI\nconst smoothedTR = [tr.slice(0, period).reduce((a, b) => a + b, 0)];\nconst smoothedPlusDM = [plusDM.slice(0, period).reduce((a, b) => a + b, 0)];\nconst smoothedMinusDM = [minusDM.slice(0, period).reduce((a, b) => a + b, 0)];\n\nfor (let i = period; i < tr.length; i++) {\n smoothedTR.push(smoothedTR[smoothedTR.length - 1] - smoothedTR[smoothedTR.length - 1] / period + tr[i]);\n smoothedPlusDM.push(smoothedPlusDM[smoothedPlusDM.length - 1] - smoothedPlusDM[smoothedPlusDM.length - 1] / period + plusDM[i]);\n smoothedMinusDM.push(smoothedMinusDM[smoothedMinusDM.length - 1] - smoothedMinusDM[smoothedMinusDM.length - 1] / period + minusDM[i]);\n}\n\nconst plusDI = smoothedPlusDM.map((val, i) => 100 * val / smoothedTR[i]);\nconst minusDI = smoothedMinusDM.map((val, i) => 100 * val / smoothedTR[i]);\n\n// Step 3: Calculate DX\nconst dx = plusDI.map((val, i) => {\n const diff = Math.abs(plusDI[i] - minusDI[i]);\n const sum = plusDI[i] + minusDI[i];\n return sum === 0 ? 0 : 100 * (diff / sum);\n});\n\n// Step 4: Smooth DX into ADX\nconst adx = [];\nconst firstADX = dx.slice(0, period).reduce((a, b) => a + b, 0) / period;\nadx.push(firstADX);\n\nfor (let i = period; i < dx.length; i++) {\n const newADX = (adx[adx.length - 1] * (period - 1) + dx[i]) / period;\n adx.push(newADX);\n}\n\n// Step 5: Final result formatting\nconst output = [];\n\nfor (let i = 0; i < adx.length; i++) {\n const index = i + (2 * period); // account for offset\n if (klines[index]) {\n output.push({\n timestamp: klines[index][0],\n close: closes[index],\n adx: adx[i],\n plusDI: plusDI[i + period],\n minusDI: minusDI[i + period]\n });\n }\n}\n\nreturn output.map(r => ({ json: r }));"
},
"typeVersion": 2
},
{
"id": "9ec777b1-eb23-43b0-8bb3-726adcc3418f",
"name": "Solicitud HTTP 1h",
"type": "n8n-nodes-base.httpRequest",
"position": [
-2880,
1760
],
"parameters": {
"url": "https://api.binance.com/api/v3/klines",
"options": {},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "symbol",
"value": "={{$json.body.symbol}}"
},
{
"name": "interval",
"value": "1h"
},
{
"name": "limit",
"value": "40"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "c4a718f8-f2d6-464b-8120-1e4067d760ad",
"name": "Indicadores Disparador Webhook 4h",
"type": "n8n-nodes-base.webhook",
"position": [
-40,
1680
],
"webhookId": "55fd9665-ed4a-4e1a-8062-890cad0fb6ac",
"parameters": {
"path": "55fd9665-ed4a-4e1a-8062-890cad0fb6ac",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "bbb81a2a-b1c4-4c1e-80e9-a4990c45fae8",
"name": "Solicitud HTTP 4h",
"type": "n8n-nodes-base.httpRequest",
"position": [
300,
1680
],
"parameters": {
"url": "https://api.binance.com/api/v3/klines",
"options": {},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "symbol",
"value": "={{$json.body.symbol}}"
},
{
"name": "interval",
"value": "4h"
},
{
"name": "limit",
"value": "40"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "20e58706-035f-46ef-b235-78fe468875bc",
"name": "Combinar en 1 Array 4h",
"type": "n8n-nodes-base.code",
"position": [
640,
1680
],
"parameters": {
"jsCode": "const klines = $input.all().map(item => item.json);\nreturn [{ json: { klines } }];"
},
"typeVersion": 2
},
{
"id": "1675168b-97ab-4be4-92d2-734d075e2222",
"name": "Calcular Bandas de Bollinger(4h)",
"type": "n8n-nodes-base.code",
"position": [
1120,
1180
],
"parameters": {
"jsCode": "// Get raw klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20;\nconst stdMultiplier = 2;\n\n// Validate type\nif (!Array.isArray(klines)) {\n throw new Error(\"klines is not an array\");\n}\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Ensure enough data\nif (closes.length < period) {\n throw new Error(`Not enough data: got ${closes.length}, expected at least ${period}`);\n}\n\n// BB calculation logic\nfunction calculateBB(prices, period) {\n const result = [];\n for (let i = period - 1; i < prices.length; i++) {\n const slice = prices.slice(i - period + 1, i + 1);\n const mean = slice.reduce((sum, val) => sum + val, 0) / period;\n const variance = slice.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / period;\n const stdDev = Math.sqrt(variance);\n\n result.push({\n close: prices[i],\n basis: mean,\n upper: mean + stdMultiplier * stdDev,\n lower: mean - stdMultiplier * stdDev,\n timestamp: klines[i][0]\n });\n }\n return result;\n}\n\n// Calculate bands\nconst bands = calculateBB(closes, period);\n\n// Format output\nreturn bands.map(b => ({\n json: {\n timestamp: b.timestamp,\n close: b.close,\n bb_basis: b.basis,\n bb_upper: b.upper,\n bb_lower: b.lower\n }\n}));"
},
"typeVersion": 2
},
{
"id": "d1c2fcc7-65ac-446c-8f59-c4cd8ac7d795",
"name": "Calcular RSI(4h)",
"type": "n8n-nodes-base.code",
"position": [
1120,
1420
],
"parameters": {
"jsCode": "// Pull klines array from JSON\nconst klines = $input.first().json.klines;\n\n// === CONFIGURATION ===\nconst period = 14; // RSI period\n\n// === Extract closing prices ===\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// === Ensure enough data ===\nif (closes.length < period + 1) {\n throw new Error(`Not enough data for RSI. Need at least ${period + 1}, got ${closes.length}`);\n}\n\n// === RSI Calculation ===\nfunction calculateRSI(prices, period) {\n const result = [];\n\n for (let i = period; i < prices.length; i++) {\n let gains = 0;\n let losses = 0;\n\n for (let j = i - period + 1; j <= i; j++) {\n const change = prices[j] - prices[j - 1];\n if (change >= 0) gains += change;\n else losses -= change;\n }\n\n const avgGain = gains / period;\n const avgLoss = losses / period;\n\n const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;\n const rsi = avgLoss === 0 ? 100 : 100 - (100 / (1 + rs));\n\n result.push({\n timestamp: klines[i][0],\n close: prices[i],\n rsi: rsi\n });\n }\n\n return result;\n}\n\n// === Run RSI ===\nconst rsiSeries = calculateRSI(closes, period);\n\n// === Return formatted RSI output ===\nreturn rsiSeries.map(r => ({\n json: {\n timestamp: r.timestamp,\n close: r.close,\n rsi: r.rsi\n }\n}));"
},
"typeVersion": 2
},
{
"id": "df32e55c-2dbc-44d6-8161-f70db651cfcd",
"name": "Calcular MACD(4h)",
"type": "n8n-nodes-base.code",
"position": [
1120,
1660
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Parameters\nconst fastPeriod = 12;\nconst slowPeriod = 26;\nconst signalPeriod = 9;\n\n// Validate data length\nconst minRequired = slowPeriod + signalPeriod;\nif (closes.length < minRequired) {\n throw new Error(`Not enough data for MACD. Need at least ${minRequired}, got ${closes.length}`);\n}\n\n// === Helper: EMA function ===\nfunction calculateEMA(prices, period) {\n const k = 2 / (period + 1);\n const ema = [prices.slice(0, period).reduce((a, b) => a + b, 0) / period];\n\n for (let i = period; i < prices.length; i++) {\n ema.push(prices[i] * k + ema[ema.length - 1] * (1 - k));\n }\n\n return ema;\n}\n\n// === MACD Core Calculation ===\nconst slowEMA = calculateEMA(closes, slowPeriod);\nconst fastEMA = calculateEMA(closes.slice(slowPeriod - fastPeriod), fastPeriod);\n\n// Align lengths\nconst alignedFastEMA = fastEMA.slice(fastEMA.length - slowEMA.length);\nconst macdLine = alignedFastEMA.map((val, i) => val - slowEMA[i]);\n\n// Signal line\nconst signalLine = calculateEMA(macdLine, signalPeriod);\n\n// Histogram\nconst histogram = macdLine.slice(signalPeriod - 1).map((macd, i) => macd - signalLine[i]);\n\n// Final output start index\nconst startIndex = closes.length - histogram.length;\n\nconst result = [];\n\nfor (let i = 0; i < histogram.length; i++) {\n const idx = startIndex + i;\n result.push({\n timestamp: klines[idx]?.[0] || null,\n close: closes[idx],\n macd: macdLine[i + signalPeriod - 1],\n signal: signalLine[i],\n histogram: histogram[i]\n });\n}\n\nreturn result.map(r => ({\n json: r\n}));"
},
"typeVersion": 2
},
{
"id": "93a115f7-e876-43f0-8ecb-70a47a06f41c",
"name": "Calcular SMA(4h)",
"type": "n8n-nodes-base.code",
"position": [
1120,
1880
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20; // Change to 50, 100, 200, etc. as needed\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Check for sufficient data\nif (closes.length < period) {\n throw new Error(`Not enough data to compute SMA. Need at least ${period}, got ${closes.length}`);\n}\n\n// Calculate SMA values\nconst result = [];\n\nfor (let i = period - 1; i < closes.length; i++) {\n const slice = closes.slice(i - period + 1, i + 1);\n const sum = slice.reduce((a, b) => a + b, 0);\n const average = sum / period;\n\n result.push({\n timestamp: klines[i][0],\n close: closes[i],\n sma: average\n });\n}\n\n// Return formatted output\nreturn result.map(r => ({\n json: r\n}));"
},
"typeVersion": 2
},
{
"id": "17bf4e9f-7053-4a04-b439-3e23fe5cb7f9",
"name": "Calcular EMA(4h)",
"type": "n8n-nodes-base.code",
"position": [
1120,
2100
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20; // Change to 9, 12, 26, 50, etc. as needed\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Check for sufficient data\nif (closes.length < period) {\n throw new Error(`Not enough data to compute EMA. Need at least ${period}, got ${closes.length}`);\n}\n\n// EMA Calculation\nconst k = 2 / (period + 1);\nconst ema = [];\n\n// Start with SMA of first period\nlet sma = closes.slice(0, period).reduce((a, b) => a + b, 0) / period;\nema.push({\n timestamp: klines[period - 1][0],\n close: closes[period - 1],\n ema: sma\n});\n\n// Continue EMA calculation\nfor (let i = period; i < closes.length; i++) {\n const value = closes[i] * k + ema[ema.length - 1].ema * (1 - k);\n ema.push({\n timestamp: klines[i][0],\n close: closes[i],\n ema: value\n });\n}\n\n// Return result\nreturn ema.map(e => ({\n json: e\n}));"
},
"typeVersion": 2
},
{
"id": "d61db420-9def-4ec1-bf8a-94afeabda186",
"name": "Calcular ADX (4h)",
"type": "n8n-nodes-base.code",
"position": [
1120,
2360
],
"parameters": {
"jsCode": "// Get kline array from merged item\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 14;\n\n// Parse high, low, close arrays\nconst highs = klines.map(k => parseFloat(k[2]));\nconst lows = klines.map(k => parseFloat(k[3]));\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Validation\nif (closes.length < period + 1) {\n throw new Error(`Not enough data for ADX. Need at least ${period + 1}, got ${closes.length}`);\n}\n\n// Initialize arrays\nconst tr = [];\nconst plusDM = [];\nconst minusDM = [];\n\n// Step 1: Calculate TR, +DM, -DM\nfor (let i = 1; i < klines.length; i++) {\n const highDiff = highs[i] - highs[i - 1];\n const lowDiff = lows[i - 1] - lows[i];\n const upMove = highDiff > 0 && highDiff > lowDiff ? highDiff : 0;\n const downMove = lowDiff > 0 && lowDiff > highDiff ? lowDiff : 0;\n\n const trueRange = Math.max(\n highs[i] - lows[i],\n Math.abs(highs[i] - closes[i - 1]),\n Math.abs(lows[i] - closes[i - 1])\n );\n\n tr.push(trueRange);\n plusDM.push(upMove);\n minusDM.push(downMove);\n}\n\n// Step 2: Smooth TR, +DM, -DM and calculate DI\nconst smoothedTR = [tr.slice(0, period).reduce((a, b) => a + b, 0)];\nconst smoothedPlusDM = [plusDM.slice(0, period).reduce((a, b) => a + b, 0)];\nconst smoothedMinusDM = [minusDM.slice(0, period).reduce((a, b) => a + b, 0)];\n\nfor (let i = period; i < tr.length; i++) {\n smoothedTR.push(smoothedTR[smoothedTR.length - 1] - smoothedTR[smoothedTR.length - 1] / period + tr[i]);\n smoothedPlusDM.push(smoothedPlusDM[smoothedPlusDM.length - 1] - smoothedPlusDM[smoothedPlusDM.length - 1] / period + plusDM[i]);\n smoothedMinusDM.push(smoothedMinusDM[smoothedMinusDM.length - 1] - smoothedMinusDM[smoothedMinusDM.length - 1] / period + minusDM[i]);\n}\n\nconst plusDI = smoothedPlusDM.map((val, i) => 100 * val / smoothedTR[i]);\nconst minusDI = smoothedMinusDM.map((val, i) => 100 * val / smoothedTR[i]);\n\n// Step 3: Calculate DX\nconst dx = plusDI.map((val, i) => {\n const diff = Math.abs(plusDI[i] - minusDI[i]);\n const sum = plusDI[i] + minusDI[i];\n return sum === 0 ? 0 : 100 * (diff / sum);\n});\n\n// Step 4: Smooth DX into ADX\nconst adx = [];\nconst firstADX = dx.slice(0, period).reduce((a, b) => a + b, 0) / period;\nadx.push(firstADX);\n\nfor (let i = period; i < dx.length; i++) {\n const newADX = (adx[adx.length - 1] * (period - 1) + dx[i]) / period;\n adx.push(newADX);\n}\n\n// Step 5: Final result formatting\nconst output = [];\n\nfor (let i = 0; i < adx.length; i++) {\n const index = i + (2 * period); // account for offset\n if (klines[index]) {\n output.push({\n timestamp: klines[index][0],\n close: closes[index],\n adx: adx[i],\n plusDI: plusDI[i + period],\n minusDI: minusDI[i + period]\n });\n }\n}\n\nreturn output.map(r => ({ json: r }));"
},
"typeVersion": 2
},
{
"id": "7940bc3f-c5f4-4b4b-b542-8737f17afbbf",
"name": "Combinar Indicadores 4h",
"type": "n8n-nodes-base.merge",
"position": [
1720,
1600
],
"parameters": {
"numberInputs": 6
},
"typeVersion": 3.1
},
{
"id": "8585a269-b70d-4af7-b264-db9f638c8a77",
"name": "Responder a Disparador Webhook 4h",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2120,
1660
],
"parameters": {
"options": {},
"respondWith": "allIncomingItems"
},
"typeVersion": 1.3
},
{
"id": "91a05310-bd36-4ee0-8381-b3d16c3346be",
"name": "Indicadores Disparador Webhook 1d",
"type": "n8n-nodes-base.webhook",
"position": [
-1600,
3140
],
"webhookId": "23c8ec04-5aec-49c6-9c2c-c352ccec11b4",
"parameters": {
"path": "23c8ec04-5aec-49c6-9c2c-c352ccec11b4",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "29121e2e-f6e2-4d42-8e5b-e8eea1e61ec8",
"name": "Solicitud HTTP 1d",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1260,
3140
],
"parameters": {
"url": "https://api.binance.com/api/v3/klines",
"options": {},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "symbol",
"value": "={{$json.body.symbol}}"
},
{
"name": "interval",
"value": "1d"
},
{
"name": "limit",
"value": "40"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "1be26316-3d08-4983-9d12-6bc36465e76e",
"name": "Combinar en 1 Array 1d",
"type": "n8n-nodes-base.code",
"position": [
-900,
3140
],
"parameters": {
"jsCode": "const klines = $input.all().map(item => item.json);\nreturn [{ json: { klines } }];"
},
"typeVersion": 2
},
{
"id": "6e9c7976-737b-4377-b412-633a1a67097b",
"name": "Calcular Bandas de Bollinger(1d)",
"type": "n8n-nodes-base.code",
"position": [
-440,
2620
],
"parameters": {
"jsCode": "// Get raw klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20;\nconst stdMultiplier = 2;\n\n// Validate type\nif (!Array.isArray(klines)) {\n throw new Error(\"klines is not an array\");\n}\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Ensure enough data\nif (closes.length < period) {\n throw new Error(`Not enough data: got ${closes.length}, expected at least ${period}`);\n}\n\n// BB calculation logic\nfunction calculateBB(prices, period) {\n const result = [];\n for (let i = period - 1; i < prices.length; i++) {\n const slice = prices.slice(i - period + 1, i + 1);\n const mean = slice.reduce((sum, val) => sum + val, 0) / period;\n const variance = slice.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / period;\n const stdDev = Math.sqrt(variance);\n\n result.push({\n close: prices[i],\n basis: mean,\n upper: mean + stdMultiplier * stdDev,\n lower: mean - stdMultiplier * stdDev,\n timestamp: klines[i][0]\n });\n }\n return result;\n}\n\n// Calculate bands\nconst bands = calculateBB(closes, period);\n\n// Format output\nreturn bands.map(b => ({\n json: {\n timestamp: b.timestamp,\n close: b.close,\n bb_basis: b.basis,\n bb_upper: b.upper,\n bb_lower: b.lower\n }\n}));"
},
"typeVersion": 2
},
{
"id": "ac84877a-75cf-4ef2-bad1-8d0f444ecead",
"name": "Calcular RSI(1d)",
"type": "n8n-nodes-base.code",
"position": [
-440,
2880
],
"parameters": {
"jsCode": "// Pull klines array from JSON\nconst klines = $input.first().json.klines;\n\n// === CONFIGURATION ===\nconst period = 14; // RSI period\n\n// === Extract closing prices ===\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// === Ensure enough data ===\nif (closes.length < period + 1) {\n throw new Error(`Not enough data for RSI. Need at least ${period + 1}, got ${closes.length}`);\n}\n\n// === RSI Calculation ===\nfunction calculateRSI(prices, period) {\n const result = [];\n\n for (let i = period; i < prices.length; i++) {\n let gains = 0;\n let losses = 0;\n\n for (let j = i - period + 1; j <= i; j++) {\n const change = prices[j] - prices[j - 1];\n if (change >= 0) gains += change;\n else losses -= change;\n }\n\n const avgGain = gains / period;\n const avgLoss = losses / period;\n\n const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;\n const rsi = avgLoss === 0 ? 100 : 100 - (100 / (1 + rs));\n\n result.push({\n timestamp: klines[i][0],\n close: prices[i],\n rsi: rsi\n });\n }\n\n return result;\n}\n\n// === Run RSI ===\nconst rsiSeries = calculateRSI(closes, period);\n\n// === Return formatted RSI output ===\nreturn rsiSeries.map(r => ({\n json: {\n timestamp: r.timestamp,\n close: r.close,\n rsi: r.rsi\n }\n}));"
},
"typeVersion": 2
},
{
"id": "a5da65c5-db5a-4f9d-a6cf-228f081ffb3c",
"name": "Calcular MACD(1d)",
"type": "n8n-nodes-base.code",
"position": [
-440,
3120
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Parameters\nconst fastPeriod = 12;\nconst slowPeriod = 26;\nconst signalPeriod = 9;\n\n// Validate data length\nconst minRequired = slowPeriod + signalPeriod;\nif (closes.length < minRequired) {\n throw new Error(`Not enough data for MACD. Need at least ${minRequired}, got ${closes.length}`);\n}\n\n// === Helper: EMA function ===\nfunction calculateEMA(prices, period) {\n const k = 2 / (period + 1);\n const ema = [prices.slice(0, period).reduce((a, b) => a + b, 0) / period];\n\n for (let i = period; i < prices.length; i++) {\n ema.push(prices[i] * k + ema[ema.length - 1] * (1 - k));\n }\n\n return ema;\n}\n\n// === MACD Core Calculation ===\nconst slowEMA = calculateEMA(closes, slowPeriod);\nconst fastEMA = calculateEMA(closes.slice(slowPeriod - fastPeriod), fastPeriod);\n\n// Align lengths\nconst alignedFastEMA = fastEMA.slice(fastEMA.length - slowEMA.length);\nconst macdLine = alignedFastEMA.map((val, i) => val - slowEMA[i]);\n\n// Signal line\nconst signalLine = calculateEMA(macdLine, signalPeriod);\n\n// Histogram\nconst histogram = macdLine.slice(signalPeriod - 1).map((macd, i) => macd - signalLine[i]);\n\n// Final output start index\nconst startIndex = closes.length - histogram.length;\n\nconst result = [];\n\nfor (let i = 0; i < histogram.length; i++) {\n const idx = startIndex + i;\n result.push({\n timestamp: klines[idx]?.[0] || null,\n close: closes[idx],\n macd: macdLine[i + signalPeriod - 1],\n signal: signalLine[i],\n histogram: histogram[i]\n });\n}\n\nreturn result.map(r => ({\n json: r\n}));"
},
"typeVersion": 2
},
{
"id": "5b1f34b3-e675-46b1-a754-679080680058",
"name": "Calcular SMA(1d)",
"type": "n8n-nodes-base.code",
"position": [
-440,
3340
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20; // Change to 50, 100, 200, etc. as needed\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Check for sufficient data\nif (closes.length < period) {\n throw new Error(`Not enough data to compute SMA. Need at least ${period}, got ${closes.length}`);\n}\n\n// Calculate SMA values\nconst result = [];\n\nfor (let i = period - 1; i < closes.length; i++) {\n const slice = closes.slice(i - period + 1, i + 1);\n const sum = slice.reduce((a, b) => a + b, 0);\n const average = sum / period;\n\n result.push({\n timestamp: klines[i][0],\n close: closes[i],\n sma: average\n });\n}\n\n// Return formatted output\nreturn result.map(r => ({\n json: r\n}));"
},
"typeVersion": 2
},
{
"id": "0b3278a6-5793-4d70-8954-70562c43a3eb",
"name": "Calcular EMA(1d)",
"type": "n8n-nodes-base.code",
"position": [
-440,
3580
],
"parameters": {
"jsCode": "// Get klines array\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 20; // Change to 9, 12, 26, 50, etc. as needed\n\n// Extract closing prices\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Check for sufficient data\nif (closes.length < period) {\n throw new Error(`Not enough data to compute EMA. Need at least ${period}, got ${closes.length}`);\n}\n\n// EMA Calculation\nconst k = 2 / (period + 1);\nconst ema = [];\n\n// Start with SMA of first period\nlet sma = closes.slice(0, period).reduce((a, b) => a + b, 0) / period;\nema.push({\n timestamp: klines[period - 1][0],\n close: closes[period - 1],\n ema: sma\n});\n\n// Continue EMA calculation\nfor (let i = period; i < closes.length; i++) {\n const value = closes[i] * k + ema[ema.length - 1].ema * (1 - k);\n ema.push({\n timestamp: klines[i][0],\n close: closes[i],\n ema: value\n });\n}\n\n// Return result\nreturn ema.map(e => ({\n json: e\n}));"
},
"typeVersion": 2
},
{
"id": "28dd6fb1-a161-49ed-9c14-740e88e2195d",
"name": "Calcular ADX (1d)",
"type": "n8n-nodes-base.code",
"position": [
-440,
3780
],
"parameters": {
"jsCode": "// Get kline array from merged item\nconst klines = $input.first().json.klines;\n\n// Parameters\nconst period = 14;\n\n// Parse high, low, close arrays\nconst highs = klines.map(k => parseFloat(k[2]));\nconst lows = klines.map(k => parseFloat(k[3]));\nconst closes = klines.map(k => parseFloat(k[4]));\n\n// Validation\nif (closes.length < period + 1) {\n throw new Error(`Not enough data for ADX. Need at least ${period + 1}, got ${closes.length}`);\n}\n\n// Initialize arrays\nconst tr = [];\nconst plusDM = [];\nconst minusDM = [];\n\n// Step 1: Calculate TR, +DM, -DM\nfor (let i = 1; i < klines.length; i++) {\n const highDiff = highs[i] - highs[i - 1];\n const lowDiff = lows[i - 1] - lows[i];\n const upMove = highDiff > 0 && highDiff > lowDiff ? highDiff : 0;\n const downMove = lowDiff > 0 && lowDiff > highDiff ? lowDiff : 0;\n\n const trueRange = Math.max(\n highs[i] - lows[i],\n Math.abs(highs[i] - closes[i - 1]),\n Math.abs(lows[i] - closes[i - 1])\n );\n\n tr.push(trueRange);\n plusDM.push(upMove);\n minusDM.push(downMove);\n}\n\n// Step 2: Smooth TR, +DM, -DM and calculate DI\nconst smoothedTR = [tr.slice(0, period).reduce((a, b) => a + b, 0)];\nconst smoothedPlusDM = [plusDM.slice(0, period).reduce((a, b) => a + b, 0)];\nconst smoothedMinusDM = [minusDM.slice(0, period).reduce((a, b) => a + b, 0)];\n\nfor (let i = period; i < tr.length; i++) {\n smoothedTR.push(smoothedTR[smoothedTR.length - 1] - smoothedTR[smoothedTR.length - 1] / period + tr[i]);\n smoothedPlusDM.push(smoothedPlusDM[smoothedPlusDM.length - 1] - smoothedPlusDM[smoothedPlusDM.length - 1] / period + plusDM[i]);\n smoothedMinusDM.push(smoothedMinusDM[smoothedMinusDM.length - 1] - smoothedMinusDM[smoothedMinusDM.length - 1] / period + minusDM[i]);\n}\n\nconst plusDI = smoothedPlusDM.map((val, i) => 100 * val / smoothedTR[i]);\nconst minusDI = smoothedMinusDM.map((val, i) => 100 * val / smoothedTR[i]);\n\n// Step 3: Calculate DX\nconst dx = plusDI.map((val, i) => {\n const diff = Math.abs(plusDI[i] - minusDI[i]);\n const sum = plusDI[i] + minusDI[i];\n return sum === 0 ? 0 : 100 * (diff / sum);\n});\n\n// Step 4: Smooth DX into ADX\nconst adx = [];\nconst firstADX = dx.slice(0, period).reduce((a, b) => a + b, 0) / period;\nadx.push(firstADX);\n\nfor (let i = period; i < dx.length; i++) {\n const newADX = (adx[adx.length - 1] * (period - 1) + dx[i]) / period;\n adx.push(newADX);\n}\n\n// Step 5: Final result formatting\nconst output = [];\n\nfor (let i = 0; i < adx.length; i++) {\n const index = i + (2 * period); // account for offset\n if (klines[index]) {\n output.push({\n timestamp: klines[index][0],\n close: closes[index],\n adx: adx[i],\n plusDI: plusDI[i + period],\n minusDI: minusDI[i + period]\n });\n }\n}\n\nreturn output.map(r => ({ json: r }));"
},
"typeVersion": 2
},
{
"id": "660dfcb4-ed63-4c53-806b-cba96c105fee",
"name": "Combinar Indicadores 1d",
"type": "n8n-nodes-base.merge",
"position": [
160,
3060
],
"parameters": {
"numberInputs": 6
},
"typeVersion": 3.1
},
{
"id": "939665ce-7a50-4a6d-9b37-62ad800350b0",
"name": "Responder a Disparador Webhook 1d",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
560,
3120
],
"parameters": {
"options": {},
"respondWith": "allIncomingItems"
},
"typeVersion": 1.3
},
{
"id": "2f44a150-0c5a-4b74-92b5-fe941fccb86d",
"name": "Nota Adhesiva13",
"type": "n8n-nodes-base.stickyNote",
"position": [
100,
-340
],
"parameters": {
"color": 5,
"width": 260,
"height": 620,
"content": "## Technical Indicator API Merge \n\n**Binance API** for 6 indicators:\n\n• **RSI, MACD, BBANDS, SMA, EMA, ADX**"
},
"typeVersion": 1
},
{
"id": "fbf6424d-8bfc-469b-ae56-c9824e657e75",
"name": "Nota Adhesiva",
"type": "n8n-nodes-base.stickyNote",
"position": [
1640,
1340
],
"parameters": {
"color": 5,
"width": 260,
"height": 620,
"content": "## Technical Indicator API Merge \n\n**Binance API** for 6 indicators:\n\n• **RSI, MACD, BBANDS, SMA, EMA, ADX**"
},
"typeVersion": 1
},
{
"id": "fba15cd9-e7a0-4a03-813e-444dd2cd25f7",
"name": "Nota Adhesiva14",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1540,
1380
],
"parameters": {
"color": 5,
"width": 260,
"height": 620,
"content": "## Technical Indicator API Merge \n\n**Binance API** for 6 indicators:\n\n• **RSI, MACD, BBANDS, SMA, EMA, ADX**"
},
"typeVersion": 1
},
{
"id": "ab87eb1b-3048-4717-af97-b7fa92c0f260",
"name": "Nota Adhesiva15",
"type": "n8n-nodes-base.stickyNote",
"position": [
80,
2760
],
"parameters": {
"color": 5,
"width": 260,
"height": 620,
"content": "## Technical Indicator API Merge \n\n**Binance API** for 6 indicators:\n\n• **RSI, MACD, BBANDS, SMA, EMA, ADX**"
},
"typeVersion": 1
},
{
"id": "b3abceb1-3605-4cca-8b4e-1f85f792fff2",
"name": "Nota Adhesiva1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1540,
-500
],
"parameters": {
"color": 4,
"height": 680,
"content": "## Webhooks (15minData)\n\n• **Entry point** for external workflows calling indicator batches\n\n• Orchestrates trigger for **indicator API pull + formatter nodes**\n\n• Returns **cleaned batch** back via Respond to Webhook node\n\n📎 Notes:\n\n• Must pass through correct **webhook** path\n\n• Responds after **merge with all 6 formatted outputs** per timeframe"
},
"typeVersion": 1
},
{
"id": "2143ce8a-8746-4187-bc43-c9cc294da7b8",
"name": "Nota Adhesiva2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3300,
1240
],
"parameters": {
"color": 4,
"height": 680,
"content": "## Webhooks (1hourData)\n\n• **Entry point** for external workflows calling indicator batches\n\n• Orchestrates trigger for **indicator API pull + formatter nodes**\n\n• Returns **cleaned batch** back via Respond to Webhook node\n\n📎 Notes:\n\n• Must pass through correct **webhook** path\n\n• Responds after **merge with all 6 formatted outputs** per timeframe"
},
"typeVersion": 1
},
{
"id": "d9150fb0-42b5-48e8-b123-e588672a653f",
"name": "Nota Adhesiva3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-100,
1200
],
"parameters": {
"color": 4,
"height": 680,
"content": "## Webhooks (4hourData)\n\n• **Entry point** for external workflows calling indicator batches\n\n• Orchestrates trigger for **indicator API pull + formatter nodes**\n\n• Returns **cleaned batch** back via Respond to Webhook node\n\n📎 Notes:\n\n• Must pass through correct **webhook** path\n\n• Responds after **merge with all 6 formatted outputs** per timeframe"
},
"typeVersion": 1
},
{
"id": "50737e51-ef67-42af-bf15-ac228c750f4d",
"name": "Nota Adhesiva4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1680,
2640
],
"parameters": {
"color": 4,
"height": 680,
"content": "## Webhooks (1dayData)\n\n• **Entry point** for external workflows calling indicator batches\n\n• Orchestrates trigger for **indicator API pull + formatter nodes**\n\n• Returns **cleaned batch** back via Respond to Webhook node\n\n📎 Notes:\n\n• Must pass through correct **webhook** path\n\n• Responds after **merge with all 6 formatted outputs** per timeframe"
},
"typeVersion": 1
},
{
"id": "61972dcf-2bd5-454e-880b-0d3e97c82f98",
"name": "Nota Adhesiva5",
"type": "n8n-nodes-base.stickyNote",
"position": [
480,
-480
],
"parameters": {
"color": 4,
"width": 280,
"height": 640,
"content": "## Webhooks Respond (15minData)\n\n• **Exit point** for external workflows calling indicator batches\n\n• Orchestrates trigger for **indicator API pull + formatter nodes**\n\n• Returns **cleaned batch** back via Respond to Webhook node\n\n📎 Notes:\n\n• Must pass through correct **webhook** path\n\n• Responds after **merge with all 6 formatted outputs** per timeframe"
},
"typeVersion": 1
},
{
"id": "c545e86b-8f90-4e3b-8e72-25f56de0b214",
"name": "Nota Adhesiva6",
"type": "n8n-nodes-base.stickyNote",
"position": [
2020,
1200
],
"parameters": {
"color": 4,
"width": 280,
"height": 640,
"content": "## Webhooks Respond (4hourData)\n\n• **Exit point** for external workflows calling indicator batches\n\n• Orchestrates trigger for **indicator API pull + formatter nodes**\n\n• Returns **cleaned batch** back via Respond to Webhook node\n\n📎 Notes:\n\n• Must pass through correct **webhook** path\n\n• Responds after **merge with all 6 formatted outputs** per timeframe"
},
"typeVersion": 1
},
{
"id": "9e838383-1c81-45c6-98f1-f735dc5789df",
"name": "Nota Adhesiva7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1140,
1260
],
"parameters": {
"color": 4,
"width": 280,
"height": 640,
"content": "## Webhooks Respond (1hourData)\n\n• **Exit point** for external workflows calling indicator batches\n\n• Orchestrates trigger for **indicator API pull + formatter nodes**\n\n• Returns **cleaned batch** back via Respond to Webhook node\n\n📎 Notes:\n\n• Must pass through correct **webhook** path\n\n• Responds after **merge with all 6 formatted outputs** per timeframe"
},
"typeVersion": 1
},
{
"id": "f05d2def-9593-46c5-862d-378a5d1f64d4",
"name": "Nota Adhesiva8",
"type": "n8n-nodes-base.stickyNote",
"position": [
480,
2660
],
"parameters": {
"color": 4,
"width": 280,
"height": 640,
"content": "## Webhooks Respond (1dayData)\n\n• **Exit point** for external workflows calling indicator batches\n\n• Orchestrates trigger for **indicator API pull + formatter nodes**\n\n• Returns **cleaned batch** back via Respond to Webhook node\n\n📎 Notes:\n\n• Must pass through correct **webhook** path\n\n• Responds after **merge with all 6 formatted outputs** per timeframe"
},
"typeVersion": 1
},
{
"id": "ceb5f8e0-e51f-4554-a752-a319033c14c4",
"name": "Nota Adhesiva9",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1160,
-300
],
"parameters": {
"color": 6,
"width": 260,
"height": 520,
"content": "## Binance API Calls 15m \n\n• Triggers **Binance API** for k-line data:\n\n\n• Each node pulls and returns **raw API data** for formatting"
},
"typeVersion": 1
},
{
"id": "8e1aeb88-3232-4ea7-85c3-49a75097341b",
"name": "Nota Adhesiva10",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2940,
1480
],
"parameters": {
"color": 6,
"width": 260,
"height": 500,
"content": "## Binance API Calls 1h \n\n• Triggers **Binance API** for k-line data:\n\n\n• Each node pulls and returns **raw API data** for formatting"
},
"typeVersion": 1
},
{
"id": "53996473-bdd7-44d3-9060-96a2f072077c",
"name": "Nota Adhesiva11",
"type": "n8n-nodes-base.stickyNote",
"position": [
240,
1420
],
"parameters": {
"color": 6,
"width": 260,
"height": 500,
"content": "## Binance API Calls 4h \n\n• Triggers **Binance API** for k-line data:\n\n\n• Each node pulls and returns **raw API data** for formatting"
},
"typeVersion": 1
},
{
"id": "6b138f55-5f0e-4844-a570-47919c8888b5",
"name": "Nota Adhesiva12",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1340,
2920
],
"parameters": {
"color": 6,
"width": 260,
"height": 420,
"content": "## Binance API Calls 1d \n\n• Triggers **Binance API** for k-line data:\n\n\n• Each node pulls and returns **raw API data** for formatting"
},
"typeVersion": 1
},
{
"id": "8d8bd17f-c437-4e57-a517-3b6eb44eeff7",
"name": "Nota Adhesiva16",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2120,
720
],
"parameters": {
"color": 2,
"height": 1860,
"content": "## Calculate Technical Indicators \n \n\n• Ensures consistent **downstream format for merge and reasoning**\n\n📎 Notes:\n\n• **Format logic** is customized per indicator\n\n• Essential for **standardizing multi-timeframe data ingestion**"
},
"typeVersion": 1
},
{
"id": "ee6e6788-7b9d-4d29-9cdd-0af5256289ef",
"name": "Nota Adhesiva17",
"type": "n8n-nodes-base.stickyNote",
"position": [
-360,
-860
],
"parameters": {
"color": 2,
"width": 260,
"height": 1720,
"content": "## Calculate Technical Indicators \n \n\n• Ensures consistent **downstream format for merge and reasoning**\n\n📎 Notes:\n\n• **Format logic** is customized per indicator\n\n• Essential for **standardizing multi-timeframe data ingestion**"
},
"typeVersion": 1
},
{
"id": "e53bcd92-c603-43f3-b25f-0d7dd46afca0",
"name": "Nota Adhesiva18",
"type": "n8n-nodes-base.stickyNote",
"position": [
1040,
720
],
"parameters": {
"color": 2,
"width": 260,
"height": 1820,
"content": "## Calculate Technical Indicators \n \n\n• Ensures consistent **downstream format for merge and reasoning**\n\n📎 Notes:\n\n• **Format logic** is customized per indicator\n\n• Essential for **standardizing multi-timeframe data ingestion**"
},
"typeVersion": 1
},
{
"id": "7d27698c-bbc5-4faf-aa41-4c4332abb484",
"name": "Nota Adhesiva19",
"type": "n8n-nodes-base.stickyNote",
"position": [
-520,
2180
],
"parameters": {
"color": 2,
"width": 260,
"height": 1800,
"content": "## Calculate Technical Indicators \n \n\n• Ensures consistent **downstream format for merge and reasoning**\n\n📎 Notes:\n\n• **Format logic** is customized per indicator\n\n• Essential for **standardizing multi-timeframe data ingestion**"
},
"typeVersion": 1
},
{
"id": "309f22d1-aeb2-4d48-a7c4-deaad51070e3",
"name": "Nota Adhesiva20",
"type": "n8n-nodes-base.stickyNote",
"position": [
-820,
-240
],
"parameters": {
"color": 5,
"width": 260,
"height": 460,
"content": "## API Merge \n\n**Binance API** for k-line Data to calculate:\n\n• **RSI, MACD, BBANDS, SMA, EMA, ADX**"
},
"typeVersion": 1
},
{
"id": "5a27535c-5bc9-4718-b895-5a8eccf37974",
"name": "Nota Adhesiva21",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2600,
1560
],
"parameters": {
"color": 5,
"width": 260,
"height": 420,
"content": "## API Merge \n\n**Binance API** for k-line Data to calculate:\n\n• **RSI, MACD, BBANDS, SMA, EMA, ADX**"
},
"typeVersion": 1
},
{
"id": "52180c40-a1d3-4c41-aea6-73f62f7c98ee",
"name": "Nota Adhesiva22",
"type": "n8n-nodes-base.stickyNote",
"position": [
-980,
2920
],
"parameters": {
"color": 5,
"width": 260,
"height": 460,
"content": "## API Merge \n\n**Binance API** for k-line Data to calculate:\n\n• **RSI, MACD, BBANDS, SMA, EMA, ADX**"
},
"typeVersion": 1
},
{
"id": "08697498-181c-417f-8027-8d6de1471bed",
"name": "Nota Adhesiva23",
"type": "n8n-nodes-base.stickyNote",
"position": [
560,
1480
],
"parameters": {
"color": 5,
"width": 260,
"height": 440,
"content": "## API Merge \n\n**Binance API** for k-line Data to calculate:\n\n• **RSI, MACD, BBANDS, SMA, EMA, ADX**"
},
"typeVersion": 1
},
{
"id": "773a2b4f-f716-41ab-ba18-1412e2dd50e5",
"name": "Nota Adhesiva24",
"type": "n8n-nodes-base.stickyNote",
"position": [
2800,
-60
],
"parameters": {
"width": 1460,
"height": 3020,
"content": "# 🧪 Binance SM Indicators Webhook Tool – Documentation\n\nA backend webhook processor that performs **real-time indicator calculations** for 15m, 1h, 4h, and 1d Binance candlestick data. This workflow powers all the indicator sub-agents and is essential for maintaining modular and scalable logic across timeframes.\n\n---\n\n## 🎯 Purpose\n\n* Accepts HTTP POST requests from the 15m, 1h, 4h, or 1d sub-agents\n* Pulls raw OHLCV kline data for the symbol and interval\n* Calculates technical indicators:\n\n * RSI, MACD, Bollinger Bands, SMA, EMA, ADX\n* Returns structured JSON with labeled values (e.g., `\"MACD_Cross\": \"Bullish\"`)\n\nThis tool ensures **centralized logic reuse** across all timeframe agents while improving speed and maintainability.\n\n---\n\n## ⚙️ Key Components\n\n| Node Name | Description |\n| ---------------------- | --------------------------------------------------------- |\n| `Webhook Trigger` | Handles POST at `/15m-indicators`, `/1h-indicators`, etc. |\n| `Extract Symbol` | Validates input payload (must include `symbol`) |\n| `Fetch Binance Klines` | Gets latest 100 candles using `/api/v3/klines` |\n| `RSI Calculator` | Computes 14-period RSI from closing prices |\n| `MACD Calculator` | Computes 12, 26, 9 MACD with signal and histogram |\n| `BBANDS Calculator` | Calculates 20-period bands using std. deviation |\n| `SMA/EMA Node` | Computes 20-period simple and exponential MAs |\n| `ADX Calculator` | Computes 14-period trend strength (DI+/DI− included) |\n| `Prepare Output` | Returns JSON with all labeled indicators |\n\n---\n\n## 📥 Expected Input (from sub-agent)\n\n```json\n{\n \"symbol\": \"BTCUSDT\"\n}\n```\n\nMust be a valid Binance Spot trading pair. Interval is auto-routed based on webhook endpoint:\n\n| Endpoint Path | Interval |\n| ----------------- | -------- |\n| `/15m-indicators` | 15m |\n| `/1h-indicators` | 1h |\n| `/4h-indicators` | 4h |\n| `/1d-indicators` | 1d |\n\n---\n\n## 📊 Sample Output JSON\n\n```json\n{\n \"symbol\": \"BTCUSDT\",\n \"interval\": \"4h\",\n \"rsi\": 65.1,\n \"macd\": {\n \"value\": 24.3,\n \"signal\": 21.7,\n \"histogram\": 2.6,\n \"cross\": \"Bullish\"\n },\n \"bb\": {\n \"basis\": 62600,\n \"upper\": 63500,\n \"lower\": 61700,\n \"status\": \"Expanding\"\n },\n \"sma\": 62000,\n \"ema\": 62400,\n \"adx\": {\n \"value\": 32.8,\n \"strength\": \"Strong\"\n }\n}\n```\n\n---\n\n## 🧩 Use Case Scenarios\n\n| Scenario | Result |\n| ------------------------------------------ | -------------------------------------------------------- |\n| 15m tool POSTs to `/15m-indicators` | Webhook responds with 15m indicator set |\n| Financial Analyst Tool requests 1h signals | This workflow handles the actual math for each indicator |\n| 1d tool needs RSI + MACD + ADX | Centralized logic avoids duplication across agents |\n\n---\n\n## 🛠️ Installation Instructions\n\n### 1. Import & Activate\n\n* Import JSON into n8n\n* Ensure webhook is live and accessible\n* Test each endpoint (e.g., `/1h-indicators`) via POST\n\n### 2. Connect to Binance API\n\n* Public API: no credentials required\n* Ensure the HTTP request node for klines uses:\n\n ```\n https://api.binance.com/api/v3/klines\n ```\n\n### 3. Link to Sub-Agent Workflows\n\n* 15m, 1h, 4h, 1d tools all depend on this for logic\n* Must POST `symbol` to the correct interval endpoint\n\n---\n\n## 📦 Example Workflow Integration\n\nAll the following tools rely on this:\n\n* `Binance SM 15min Indicators Tool`\n* `Binance SM 1hour Indicators Tool`\n* `Binance SM 4hour Indicators Tool`\n* `Binance SM 1day Indicators Tool`\n\nThis acts as the math engine behind each.\n\n---\n\n## 🔐 Licensing & Support\n\n🔗 **Don Jayamaha – LinkedIn**\n[http://linkedin.com/in/donjayamahajr](http://linkedin.com/in/donjayamahajr)\n\n© 2025 Treasurium Capital Limited Company. All rights reserved.\nThe design, architecture, and indicator calculation code within this system are proprietary. Reuse, resale, or modification without license is strictly prohibited.\n"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "f7032997-bb7f-4e2a-9982-7ee18c95cfbe",
"connections": {
"HTTP Request": {
"main": [
[
{
"node": "46b937d5-7338-457f-b2f0-eb85ac44a8bb",
"type": "main",
"index": 0
}
]
]
},
"df6546be-3778-4fba-801a-870c0fe883c3": {
"main": [
[
{
"node": "5ea4756f-a20a-444c-8471-57d209457823",
"type": "main",
"index": 5
}
]
]
},
"25ef2964-c9b1-4b9e-b6ce-3766b215d163": {
"main": [
[
{
"node": "5ea4756f-a20a-444c-8471-57d209457823",
"type": "main",
"index": 4
}
]
]
},
"b0391e28-03a3-40f0-8182-72df0928ca2c": {
"main": [
[
{
"node": "5ea4756f-a20a-444c-8471-57d209457823",
"type": "main",
"index": 1
}
]
]
},
"c50f7fa5-2707-47a4-9b32-1d582bf5d600": {
"main": [
[
{
"node": "5ea4756f-a20a-444c-8471-57d209457823",
"type": "main",
"index": 3
}
]
]
},
"7301ba32-ab0c-4c80-b041-cd398f7daa2c": {
"main": [
[
{
"node": "af471a36-1107-4ccd-be14-efa06ba27330",
"type": "main",
"index": 5
}
]
]
},
"2c598960-630c-4687-91c0-bfae10da1943": {
"main": [
[
{
"node": "5ea4756f-a20a-444c-8471-57d209457823",
"type": "main",
"index": 2
}
]
]
},
"HTTP Request 1d": {
"main": [
[
{
"node": "1be26316-3d08-4983-9d12-6bc36465e76e",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request 1h": {
"main": [
[
{
"node": "d7d9bb31-6986-42e6-9f0c-7d7f00d66ee1",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request 4h": {
"main": [
[
{
"node": "20e58706-035f-46ef-b235-78fe468875bc",
"type": "main",
"index": 0
}
]
]
},
"0b3278a6-5793-4d70-8954-70562c43a3eb": {
"main": [
[
{
"node": "660dfcb4-ed63-4c53-806b-cba96c105fee",
"type": "main",
"index": 4
}
]
]
},
"83fa487a-1a67-4059-9007-d5298d8bb105": {
"main": [
[
{
"node": "af471a36-1107-4ccd-be14-efa06ba27330",
"type": "main",
"index": 4
}
]
]
},
"17bf4e9f-7053-4a04-b439-3e23fe5cb7f9": {
"main": [
[
{
"node": "7940bc3f-c5f4-4b4b-b542-8737f17afbbf",
"type": "main",
"index": 4
}
]
]
},
"ac84877a-75cf-4ef2-bad1-8d0f444ecead": {
"main": [
[
{
"node": "660dfcb4-ed63-4c53-806b-cba96c105fee",
"type": "main",
"index": 1
}
]
]
},
"702e8bc8-d8f0-4fb4-b44f-fd19479c8b03": {
"main": [
[
{
"node": "af471a36-1107-4ccd-be14-efa06ba27330",
"type": "main",
"index": 1
}
]
]
},
"d1c2fcc7-65ac-446c-8f59-c4cd8ac7d795": {
"main": [
[
{
"node": "7940bc3f-c5f4-4b4b-b542-8737f17afbbf",
"type": "main",
"index": 1
}
]
]
},
"5b1f34b3-e675-46b1-a754-679080680058": {
"main": [
[
{
"node": "660dfcb4-ed63-4c53-806b-cba96c105fee",
"type": "main",
"index": 3
}
]
]
},
"15bf5c3b-de07-412b-988c-f5c59fa7a06f": {
"main": [
[
{
"node": "af471a36-1107-4ccd-be14-efa06ba27330",
"type": "main",
"index": 3
}
]
]
},
"93a115f7-e876-43f0-8ecb-70a47a06f41c": {
"main": [
[
{
"node": "7940bc3f-c5f4-4b4b-b542-8737f17afbbf",
"type": "main",
"index": 3
}
]
]
},
"28dd6fb1-a161-49ed-9c14-740e88e2195d": {
"main": [
[
{
"node": "660dfcb4-ed63-4c53-806b-cba96c105fee",
"type": "main",
"index": 5
}
]
]
},
"d61db420-9def-4ec1-bf8a-94afeabda186": {
"main": [
[
{
"node": "7940bc3f-c5f4-4b4b-b542-8737f17afbbf",
"type": "main",
"index": 5
}
]
]
},
"a5da65c5-db5a-4f9d-a6cf-228f081ffb3c": {
"main": [
[
{
"node": "660dfcb4-ed63-4c53-806b-cba96c105fee",
"type": "main",
"index": 2
}
]
]
},
"d16b7829-59ca-45ca-a5ae-4e315168c96d": {
"main": [
[
{
"node": "af471a36-1107-4ccd-be14-efa06ba27330",
"type": "main",
"index": 2
}
]
]
},
"df32e55c-2dbc-44d6-8161-f70db651cfcd": {
"main": [
[
{
"node": "7940bc3f-c5f4-4b4b-b542-8737f17afbbf",
"type": "main",
"index": 2
}
]
]
},
"46b937d5-7338-457f-b2f0-eb85ac44a8bb": {
"main": [
[
{
"node": "5b8c1049-bcf4-41d4-bba3-5f76e940bd3e",
"type": "main",
"index": 0
},
{
"node": "b0391e28-03a3-40f0-8182-72df0928ca2c",
"type": "main",
"index": 0
},
{
"node": "2c598960-630c-4687-91c0-bfae10da1943",
"type": "main",
"index": 0
},
{
"node": "c50f7fa5-2707-47a4-9b32-1d582bf5d600",
"type": "main",
"index": 0
},
{
"node": "25ef2964-c9b1-4b9e-b6ce-3766b215d163",
"type": "main",
"index": 0
},
{
"node": "df6546be-3778-4fba-801a-870c0fe883c3",
"type": "main",
"index": 0
}
]
]
},
"660dfcb4-ed63-4c53-806b-cba96c105fee": {
"main": [
[
{
"node": "Responder a Webhook 1d",
"type": "main",
"index": 0
}
]
]
},
"af471a36-1107-4ccd-be14-efa06ba27330": {
"main": [
[
{
"node": "Responder a Webhook 1h",
"type": "main",
"index": 0
}
]
]
},
"7940bc3f-c5f4-4b4b-b542-8737f17afbbf": {
"main": [
[
{
"node": "Responder a Webhook 4h",
"type": "main",
"index": 0
}
]
]
},
"1be26316-3d08-4983-9d12-6bc36465e76e": {
"main": [
[
{
"node": "6e9c7976-737b-4377-b412-633a1a67097b",
"type": "main",
"index": 0
},
{
"node": "ac84877a-75cf-4ef2-bad1-8d0f444ecead",
"type": "main",
"index": 0
},
{
"node": "a5da65c5-db5a-4f9d-a6cf-228f081ffb3c",
"type": "main",
"index": 0
},
{
"node": "5b1f34b3-e675-46b1-a754-679080680058",
"type": "main",
"index": 0
},
{
"node": "0b3278a6-5793-4d70-8954-70562c43a3eb",
"type": "main",
"index": 0
},
{
"node": "28dd6fb1-a161-49ed-9c14-740e88e2195d",
"type": "main",
"index": 0
}
]
]
},
"d7d9bb31-6986-42e6-9f0c-7d7f00d66ee1": {
"main": [
[
{
"node": "a2e9d933-47d7-47f5-8d49-224860d8600a",
"type": "main",
"index": 0
},
{
"node": "702e8bc8-d8f0-4fb4-b44f-fd19479c8b03",
"type": "main",
"index": 0
},
{
"node": "d16b7829-59ca-45ca-a5ae-4e315168c96d",
"type": "main",
"index": 0
},
{
"node": "15bf5c3b-de07-412b-988c-f5c59fa7a06f",
"type": "main",
"index": 0
},
{
"node": "83fa487a-1a67-4059-9007-d5298d8bb105",
"type": "main",
"index": 0
},
{
"node": "7301ba32-ab0c-4c80-b041-cd398f7daa2c",
"type": "main",
"index": 0
}
]
]
},
"20e58706-035f-46ef-b235-78fe468875bc": {
"main": [
[
{
"node": "1675168b-97ab-4be4-92d2-734d075e2222",
"type": "main",
"index": 0
},
{
"node": "d1c2fcc7-65ac-446c-8f59-c4cd8ac7d795",
"type": "main",
"index": 0
},
{
"node": "df32e55c-2dbc-44d6-8161-f70db651cfcd",
"type": "main",
"index": 0
},
{
"node": "93a115f7-e876-43f0-8ecb-70a47a06f41c",
"type": "main",
"index": 0
},
{
"node": "17bf4e9f-7053-4a04-b439-3e23fe5cb7f9",
"type": "main",
"index": 0
},
{
"node": "d61db420-9def-4ec1-bf8a-94afeabda186",
"type": "main",
"index": 0
}
]
]
},
"Indicadores Webhook 1d": {
"main": [
[
{
"node": "HTTP Request 1d",
"type": "main",
"index": 0
}
]
]
},
"Indicadores Webhook 1h": {
"main": [
[
{
"node": "HTTP Request 1h",
"type": "main",
"index": 0
}
]
]
},
"Indicadores Webhook 4h": {
"main": [
[
{
"node": "HTTP Request 4h",
"type": "main",
"index": 0
}
]
]
},
"Indicadores Webhook 15m": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"5ea4756f-a20a-444c-8471-57d209457823": {
"main": [
[
{
"node": "Responder a Webhook 15m",
"type": "main",
"index": 0
}
]
]
},
"5b8c1049-bcf4-41d4-bba3-5f76e940bd3e": {
"main": [
[
{
"node": "5ea4756f-a20a-444c-8471-57d209457823",
"type": "main",
"index": 0
}
]
]
},
"6e9c7976-737b-4377-b412-633a1a67097b": {
"main": [
[
{
"node": "660dfcb4-ed63-4c53-806b-cba96c105fee",
"type": "main",
"index": 0
}
]
]
},
"a2e9d933-47d7-47f5-8d49-224860d8600a": {
"main": [
[
{
"node": "af471a36-1107-4ccd-be14-efa06ba27330",
"type": "main",
"index": 0
}
]
]
},
"1675168b-97ab-4be4-92d2-734d075e2222": {
"main": [
[
{
"node": "7940bc3f-c5f4-4b4b-b542-8737f17afbbf",
"type": "main",
"index": 0
}
]
]
}
}
}¿Cómo usar este flujo de trabajo?
Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.
¿En qué escenarios es adecuado este flujo de trabajo?
Avanzado - Finanzas, Inteligencia Artificial
¿Es de pago?
Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.
Flujos de trabajo relacionados recomendados
Don Jayamaha Jr
@don-the-gem-dealerWith 12 years of experience as a Blockchain Strategist and Web3 Architect, I specialize in bridging the gap between traditional industries and decentralized technologies. My expertise spans tokenized assets, crypto payment integrations, and blockchain-driven market solutions.
Compartir este flujo de trabajo