This workflow corresponds to n8n.io template #17363 — we link there as the canonical source.
This workflow follows the HTTP Request → Telegram recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"meta": {
"templateCredsSetupCompleted": false
},
"name": "Binance Futures Open Interest Monitor",
"tags": [],
"nodes": [
{
"id": "53dc3463-e8ad-4468-902f-6d8f932c983e",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1008,
896
],
"parameters": {
"width": 672,
"height": 544,
"content": "## Binance Futures Open Interest Monitor\n\n### How it works\n\n1. Trigger the workflow every hour using the schedule trigger.\n2. Fetch all tickers from Binance Futures and select the top N by 24h quote volume.\n3. Loop through each symbol to fetch the last 2 OI history data points (period = 1h).\n4. Calculate the 1h OI change percentage, classify the alert level, and accumulate results.\n5. After the loop, format and send a Telegram alert if any threshold is exceeded.\n\n### Setup\n\n- [ ] Configure the schedule interval on the trigger node.\n- [ ] Add your Telegram Bot credentials and chat ID to the Telegram node.\n\n### Customization\n\nAdjust `TOP_N` in the **Sort and Select Top 20 Tickers** node and alert thresholds in the **Accumulate OI Data** node."
},
"typeVersion": 1
},
{
"id": "465f1cfb-f29d-4b7e-bcaf-5daff614f11e",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-288,
896
],
"parameters": {
"color": 7,
"width": 432,
"height": 352,
"content": "## Trigger and fetch tickers\n\nInitiates the workflow to retrieve 24h price and volume stats for all listed perpetual pairs."
},
"typeVersion": 1
},
{
"id": "1d51a0a1-cb07-49b7-b8af-08ade886a31d",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
176,
896
],
"parameters": {
"color": 7,
"width": 512,
"height": 352,
"content": "## Filter and batch processing\n\nFilters USDT perpetual pairs, excludes stablecoins and fiat pairs, then sorts by 24h quote volume and selects the top N symbols."
},
"typeVersion": 1
},
{
"id": "57033438-2669-46ac-8da6-268d1aa57312",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
752,
1088
],
"parameters": {
"color": 7,
"width": 640,
"height": 368,
"content": "## Fetch OI history and classify\n\nFetches the last 2 open interest data points per symbol. Calculates the 1h OI change percentage and classifies the alert level (normal / warning / critical)."
},
"typeVersion": 1
},
{
"id": "6be11348-e53f-4eef-9fa2-8377a1a9e71b",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
752,
688
],
"parameters": {
"color": 7,
"width": 656,
"height": 348,
"content": "## Alert processing\n\nReads accumulated OI results, splits into critical and warning tiers sorted by absolute change, then sends alerts via Telegram if necessary."
},
"typeVersion": 1
},
{
"id": "3235011a-2b27-4740-8f41-4243514f6797",
"name": "Every Hour Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-224,
1072
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "cd3be479-618c-4f6b-9632-5649d2278578",
"name": "Fetch Binance Tickers",
"type": "n8n-nodes-base.httpRequest",
"position": [
-32,
1072
],
"parameters": {
"url": "https://fapi.binance.com/fapi/v1/ticker/24hr",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"typeVersion": 4.2
},
{
"id": "95b074c9-ebf2-4272-9d97-c27ad431e4b2",
"name": "Sort and Select Top 20 Tickers",
"type": "n8n-nodes-base.code",
"position": [
256,
1072
],
"parameters": {
"jsCode": "// ============================================================\n// Sort & Slice Top N by 24h Volume\n//\n// Filters USDT perpetual pairs, excludes stablecoins and fiat\n// pairs, sorts by 24h quote volume descending, and returns\n// the top N symbols. Resets the global staticData accumulator\n// before the loop begins.\n// ============================================================\n\n// --- Configuration ---\nconst TOP_N = 20;\n\nconst BLACKLIST_SYMBOLS = new Set([\n 'USDCUSDT','BUSDUSDT','TUSDUSDT','USDPUSDT','FDUSDUSDT',\n 'DAIUSDT','USDDUSDT','FRAXUSDT','LUSDUSDT','GUSDUSDT',\n 'SUSDUSDT','USTCUSDT','EURUSDT','EUROCUSDT','EURSUSDT',\n 'AGEURUSDT','GBPTUSDT','JPYCUSDT','CNHTUSDT','XSGDUSDT',\n 'NZDSUSDT','CADCUSDT','TRYBUSDT','BRLAUSDT','IDRTUSDT','BIDRUSDT',\n]);\n\nconst FIAT_PATTERNS = [\n 'USD','EUR','JPY','GBP','AUD','CAD','CHF','CNY','CNH','KRW',\n 'TRY','BRL','IDR','SGD','NZD','HKD','SEK','NOK','DKK','PLN',\n 'CZK','MXN','ZAR','THB','PHP','INR','RUB',\n];\n\n// --- Filter ---\nconst tickers = $input.all().map(item => item.json);\n\nconst filtered = tickers.filter(t => {\n const sym = t.symbol;\n if (!sym.endsWith('USDT')) return false;\n if (BLACKLIST_SYMBOLS.has(sym)) return false;\n const base = sym.slice(0, -4);\n if (FIAT_PATTERNS.some(fiat =>\n base === fiat || base.startsWith(fiat) || base.endsWith(fiat)\n )) return false;\n return true;\n});\n\n// --- Sort by 24h quote volume (USDT) descending ---\nfiltered.sort((a, b) =>\n parseFloat(b.quoteVolume) - parseFloat(a.quoteVolume)\n);\n\nconst topN = filtered.slice(0, TOP_N);\n\n// --- Reset accumulator before loop starts ---\nconst sd = $getWorkflowStaticData('global');\nsd.oi_results = [];\n\nreturn topN.map(t => ({\n json: {\n symbol: t.symbol,\n quoteVolume: parseFloat(t.quoteVolume),\n priceChangePercent: parseFloat(t.priceChangePercent),\n lastPrice: parseFloat(t.lastPrice)\n }\n}));"
},
"typeVersion": 2
},
{
"id": "94df8d1d-4553-4302-b8df-b81f1cf8e07d",
"name": "Loop Over Ticker Batches",
"type": "n8n-nodes-base.splitInBatches",
"position": [
496,
1072
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "ef39edb4-8608-4874-8dc7-806ea8178920",
"name": "Fetch OI History",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
816,
1264
],
"parameters": {
"url": "https://fapi.binance.com/futures/data/openInterestHist",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "symbol",
"value": "={{ $json.symbol }}"
},
{
"name": "period",
"value": "1h"
},
{
"name": "limit",
"value": "2"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "1ffe5ff5-a700-4a10-a465-e06851f1b272",
"name": "Accumulate OI Data",
"type": "n8n-nodes-base.code",
"position": [
1136,
1248
],
"parameters": {
"jsCode": "// ============================================================\n// Accumulate OI Change Data\n//\n// Runs inside the loop body. Receives 2 OI history data points\n// (latest and 1h ago), calculates the percentage change in OI\n// value (USDT), classifies the alert level, and pushes the\n// result into the global staticData accumulator.\n// Output connects back to Loop Over Items for the next iteration.\n// ============================================================\n\n// --- Thresholds (adjust to taste) ---\nconst WARNING_THRESHOLD = 3.0; // 3%\nconst CRITICAL_THRESHOLD = 7.0; // 7%\n\n// --- Accumulator guard ---\nconst sd = $getWorkflowStaticData('global');\nif (!Array.isArray(sd.oi_results)) sd.oi_results = [];\n\n// openInterestHist returns an array \u2014 n8n splits each element into an item\n// limit=2 \u2192 2 items: index 0 = 1h ago, index 1 = latest\nconst items = $input.all();\n\nif (!items || items.length < 2) {\n return [{ json: { skipped: true } }];\n}\n\nconst latest = items[items.length - 1].json;\nconst prev = items[0].json;\n\nif (!latest.symbol || !latest.sumOpenInterestValue || !prev.sumOpenInterestValue) {\n return [{ json: { skipped: true } }];\n}\n\nconst symbol = latest.symbol;\nconst oiNow = parseFloat(latest.sumOpenInterestValue); // OI in USDT\nconst oiPrev = parseFloat(prev.sumOpenInterestValue);\n\n// Percentage change based on USDT notional value\nconst pctChange = ((oiNow - oiPrev) / oiPrev) * 100;\nconst absPct = Math.abs(pctChange);\nconst pctFormatted = pctChange.toFixed(2);\n\nconst direction = pctChange >= 0 ? 'increasing' : 'decreasing';\nconst dirIcon = pctChange >= 0 ? '\ud83d\udcc8' : '\ud83d\udcc9';\n\n// Format OI value with B/M suffix\nfunction formatUSD(val) {\n if (val >= 1e9) return `$${(val / 1e9).toFixed(2)}B`;\n if (val >= 1e6) return `$${(val / 1e6).toFixed(2)}M`;\n return `$${val.toFixed(0)}`;\n}\n\nlet level = 'normal';\nif (absPct >= CRITICAL_THRESHOLD) level = 'critical';\nelse if (absPct >= WARNING_THRESHOLD) level = 'warning';\n\nsd.oi_results.push({\n symbol, pctChange, pctFormatted, absPct,\n oiNow, oiNowDisplay: formatUSD(oiNow),\n direction, dirIcon, level\n});\n\nreturn [{ json: { symbol, level, pctFormatted } }];"
},
"typeVersion": 2
},
{
"id": "cd2e8cd7-e76d-4f4b-8694-35dfff079b0f",
"name": "Format Alert Messages",
"type": "n8n-nodes-base.code",
"position": [
816,
864
],
"parameters": {
"jsCode": "// ============================================================\n// Process Results + Format Telegram Message\n//\n// Runs once after the Done branch of Loop Over Items.\n// Reads all accumulated OI data from global staticData,\n// splits into critical / warning tiers sorted by absolute\n// change, builds an HTML message for Telegram, and resets\n// the accumulator for the next run.\n// ============================================================\n\n// --- Thresholds (must match Accumulate node) ---\nconst WARNING_THRESHOLD = 3.0;\nconst CRITICAL_THRESHOLD = 7.0;\n\n// --- Read and reset accumulator ---\nconst sd = $getWorkflowStaticData('global');\nconst allResults = Array.isArray(sd.oi_results) ? [...sd.oi_results] : [];\nsd.oi_results = [];\n\n// --- Classify ---\nconst criticals = allResults\n .filter(r => r.level === 'critical')\n .sort((a, b) => b.absPct - a.absPct);\n\nconst warnings = allResults\n .filter(r => r.level === 'warning')\n .sort((a, b) => b.absPct - a.absPct);\n\nconst alertCount = criticals.length + warnings.length;\n\nif (alertCount === 0) {\n return [{ json: { hasAlerts: false, message: '' } }];\n}\n\n// --- Format ---\nconst timestamp = new Date().toLocaleString('en-GB', {\n timeZone: 'Asia/Ho_Chi_Minh',\n day: '2-digit', month: '2-digit', year: 'numeric',\n hour: '2-digit', minute: '2-digit', second: '2-digit',\n hour12: false\n});\n\nfunction formatCoin(r) {\n const icon = r.level === 'critical' ? '\ud83d\udd34' : '\ud83d\udfe1';\n const sign = r.pctChange >= 0 ? '+' : '';\n return `${icon} <b>${r.symbol}</b>: <code>${sign}${r.pctFormatted}%</code> ${r.dirIcon} OI ${r.direction} | ${r.oiNowDisplay}`;\n}\n\nconst lines = [];\nlines.push(`\ud83d\udcca <b>Open Interest Monitor</b>`);\nlines.push(`\ud83d\udd50 ${timestamp} (ICT)`);\nlines.push(`\ud83d\udd0d Scanned: top ${allResults.length} USDT perps by 24h volume`);\nlines.push(`\u23f1 Lookback: 1h`);\nlines.push(``);\n\nif (criticals.length > 0) {\n lines.push(`\ud83d\udd34 <b>CRITICAL (\u2265${CRITICAL_THRESHOLD}%)</b> \u2014 ${criticals.length} coin${criticals.length > 1 ? 's' : ''}`);\n lines.push(`${'\u2500'.repeat(28)}`);\n criticals.forEach(r => lines.push(formatCoin(r)));\n lines.push(``);\n}\n\nif (warnings.length > 0) {\n lines.push(`\ud83d\udfe1 <b>WARNING (\u2265${WARNING_THRESHOLD}%)</b> \u2014 ${warnings.length} coin${warnings.length > 1 ? 's' : ''}`);\n lines.push(`${'\u2500'.repeat(28)}`);\n warnings.forEach(r => lines.push(formatCoin(r)));\n}\n\nreturn [{\n json: {\n hasAlerts: true,\n alertCount,\n message: lines.join('\\n')\n }\n}];"
},
"typeVersion": 2
},
{
"id": "f4a5829d-35f8-48c0-8bdd-b2d64231ff62",
"name": "If Alerts Present",
"type": "n8n-nodes-base.if",
"position": [
1024,
864
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "has-alerts",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.hasAlerts }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "f7721c50-b375-45c6-b418-11e627750692",
"name": "Send Telegram Alert",
"type": "n8n-nodes-base.telegram",
"position": [
1264,
848
],
"parameters": {
"text": "={{ $json.message }}",
"chatId": "YOUR_TELEGRAM_CHAT_ID",
"additionalFields": {
"parse_mode": "HTML",
"disable_web_page_preview": true
}
},
"typeVersion": 1.2
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"nodeGroups": [],
"connections": {
"Fetch OI History": {
"main": [
[
{
"node": "Accumulate OI Data",
"type": "main",
"index": 0
}
]
]
},
"If Alerts Present": {
"main": [
[
{
"node": "Send Telegram Alert",
"type": "main",
"index": 0
}
]
]
},
"Accumulate OI Data": {
"main": [
[
{
"node": "Loop Over Ticker Batches",
"type": "main",
"index": 0
}
]
]
},
"Every Hour Trigger": {
"main": [
[
{
"node": "Fetch Binance Tickers",
"type": "main",
"index": 0
}
]
]
},
"Fetch Binance Tickers": {
"main": [
[
{
"node": "Sort and Select Top 20 Tickers",
"type": "main",
"index": 0
}
]
]
},
"Format Alert Messages": {
"main": [
[
{
"node": "If Alerts Present",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Ticker Batches": {
"main": [
[
{
"node": "Format Alert Messages",
"type": "main",
"index": 0
}
],
[
{
"node": "Fetch OI History",
"type": "main",
"index": 0
}
]
]
},
"Sort and Select Top 20 Tickers": {
"main": [
[
{
"node": "Loop Over Ticker Batches",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow runs hourly to scan top-volume Binance USDT perpetual futures, calculate 1-hour open interest (OI) change percentages, and send a tiered Telegram alert (warning/critical) when OI moves exceed configured thresholds. Runs every hour on a schedule trigger. Calls the…
Source: https://n8n.io/workflows/17363/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Auto Hunt. Uses httpRequest, googleSheets, rssFeedRead, telegram. Scheduled trigger; 78 nodes.
Auto-Hunt. Uses httpRequest, googleSheets, rssFeedRead, telegram. Scheduled trigger; 78 nodes.
This workflow runs daily at 9 AM, uses Perplexity to compile vaping industry news, optionally captures article screenshots via Browserless, and generates a HeyGen avatar video from a template. It then
. Uses googleSheets, telegram, httpRequest, wise. Scheduled trigger; 36 nodes.
GNCA AI News Pipeline. Uses rssFeedRead, httpRequest, telegram, errorTrigger. Scheduled trigger; 31 nodes.