{
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "Binance Futures Funding Rate Monitor",
  "tags": [
    {
      "name": "crypto"
    },
    {
      "name": "binance"
    },
    {
      "name": "futures"
    },
    {
      "name": "funding-rate"
    },
    {
      "name": "telegram"
    }
  ],
  "nodes": [
    {
      "id": "9a71b861-88ed-4fc0-af5f-18bb737ece9f",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        1952
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 304,
        "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": "8d212007-3649-4ade-8657-1fb6a83cc933",
      "name": "Send Telegram Alert",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1696,
        1856
      ],
      "parameters": {
        "text": "={{ $json.message }}",
        "chatId": "YOUR_TELEGRAM_CHAT_ID",
        "additionalFields": {
          "parse_mode": "HTML",
          "disable_web_page_preview": true
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "43f54f94-ffb0-4449-bcd2-2d06b19d6871",
      "name": "If Alerts Present",
      "type": "n8n-nodes-base.if",
      "position": [
        1456,
        1872
      ],
      "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": "588484ac-02dd-48a6-9bee-c0bb6b67d5f1",
      "name": "Format Alert Messages",
      "type": "n8n-nodes-base.code",
      "position": [
        1248,
        1872
      ],
      "parameters": {
        "jsCode": "// ============================================================\n// Process Results + Format Telegram Message\n//\n// Runs once after the Done branch of Loop Over Items.\n// Reads all accumulated funding rate data from global staticData,\n// splits into critical / warning tiers, builds an HTML message\n// for Telegram, and resets the accumulator for the next run.\n// ============================================================\n\n// --- Thresholds (must match Accumulate node) ---\nconst WARNING_THRESHOLD  = 0.0010;\nconst CRITICAL_THRESHOLD = 0.0020;\n\n// --- Read and reset accumulator ---\nconst sd = $getWorkflowStaticData('global');\nconst allResults = Array.isArray(sd.fr_results) ? [...sd.fr_results] : [];\nsd.fr_results = [];\n\n// --- Classify ---\nconst criticals = allResults\n  .filter(r => r.level === 'critical')\n  .sort((a, b) => b.absFR - a.absFR);\n\nconst warnings = allResults\n  .filter(r => r.level === 'warning')\n  .sort((a, b) => b.absFR - a.absFR);\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.fundingRate >= 0 ? '+' : '';\n  const dir  = r.fundingRate >= 0\n    ? '\ud83d\udfe2 Longs pay Shorts'\n    : '\ud83d\udd34 Shorts pay Longs';\n  return `${icon} <b>${r.symbol}</b>: <code>${sign}${r.frPercent}%</code>\n    ${dir} | next in ${r.hoursLeft}h`;\n}\n\nconst lines = [];\nlines.push(`\ud83d\udce1 <b>Funding Rate Monitor</b>`);\nlines.push(`\ud83d\udd50 ${timestamp} (ICT)`);\nlines.push(`\ud83d\udcca Scanned: top ${allResults.length} USDT perps by 24h volume`);\nlines.push(``);\n\nif (criticals.length > 0) {\n  lines.push(`\ud83d\udd34 <b>CRITICAL (\u2265${(CRITICAL_THRESHOLD * 100).toFixed(2)}%)</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 * 100).toFixed(2)}%)</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": "cbacdf12-65ff-4c61-aabb-ec62fe6ad032",
      "name": "Accumulate Funding Rate Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1472,
        2192
      ],
      "parameters": {
        "jsCode": "// ============================================================\n// Accumulate Funding Rate Data\n//\n// Runs inside the loop body. Parses the premiumIndex response,\n// classifies the funding rate level (normal / warning / critical),\n// and pushes the 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  = 0.0010; // 0.10%\nconst CRITICAL_THRESHOLD = 0.0020; // 0.20%\n\n// --- Accumulator guard ---\nconst sd = $getWorkflowStaticData('global');\nif (!Array.isArray(sd.fr_results)) sd.fr_results = [];\n\nconst raw = $input.first().json;\n\n// Skip on request error (delisted symbol, timeout, etc.)\nif (!raw || !raw.symbol) {\n  return [{ json: { skipped: true } }];\n}\n\nconst symbol      = raw.symbol;\nconst fundingRate = parseFloat(raw.lastFundingRate);\nconst absFR       = Math.abs(fundingRate);\nconst frPercent   = (fundingRate * 100).toFixed(4);\nconst markPrice   = parseFloat(raw.markPrice);\nconst nextMs      = parseInt(raw.nextFundingTime);\nconst hoursLeft   = ((nextMs - Date.now()) / 3600000).toFixed(1);\n\n// FR > 0: longs pay shorts (bullish crowding)\n// FR < 0: shorts pay longs (bearish crowding)\nconst direction = fundingRate >= 0\n  ? 'Longs pay Shorts'\n  : 'Shorts pay Longs';\n\nlet level = 'normal';\nif (absFR >= CRITICAL_THRESHOLD)     level = 'critical';\nelse if (absFR >= WARNING_THRESHOLD) level = 'warning';\n\nsd.fr_results.push({\n  symbol, fundingRate, frPercent, absFR,\n  markPrice, hoursLeft, direction, level\n});\n\nreturn [{ json: { symbol, level } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "bc6c210f-a4d2-4c6a-8427-f0a32f1c52f5",
      "name": "Fetch Ticker Funding Rate",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1248,
        2192
      ],
      "parameters": {
        "url": "=https://fapi.binance.com/fapi/v1/premiumIndex",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "symbol",
              "value": "={{ $json.symbol }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "b1658958-719b-4364-90f0-764f58705c71",
      "name": "Sort and Select Top 20 Tickers",
      "type": "n8n-nodes-base.code",
      "position": [
        784,
        2080
      ],
      "parameters": {
        "jsCode": "// ============================================================\n// Sort & Select 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\n  // Keep only USDT perpetual pairs\n  if (!sym.endsWith('USDT')) return false;\n\n  // Exclude known stablecoins and fiat tokens\n  if (BLACKLIST_SYMBOLS.has(sym)) return false;\n\n  // Exclude fiat-pair patterns (e.g. EURUSDT, GBPUSDT)\n  const base = sym.slice(0, -4);\n  if (FIAT_PATTERNS.some(fiat =>\n    base === fiat || base.startsWith(fiat) || base.endsWith(fiat)\n  )) {\n    return false;\n  }\n\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.fr_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": "6b57d49a-4998-403e-a8d3-99f863816512",
      "name": "Fetch Binance Tickers",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        544,
        2080
      ],
      "parameters": {
        "url": "https://fapi.binance.com/fapi/v1/ticker/24hr",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "d7296b11-225b-4a23-b6d3-461b813888fd",
      "name": "Every Hour Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        352,
        2080
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "d5f40f5a-bd16-4783-bf5c-ddaee9d6be5f",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1184,
        1776
      ],
      "parameters": {
        "color": 7,
        "width": 656,
        "height": 256,
        "content": "## Alert processing\n\nFormats and evaluates data for alerts, then sends alerts via Telegram if necessary."
      },
      "typeVersion": 1
    },
    {
      "id": "b1296159-df4b-460b-9043-dc4d87cddf09",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1184,
        2080
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 304,
        "content": "## Fetch funding rate and classify\n\nFetches the current funding rate per symbol, classifies direction (longs/shorts pay) and alert level (normal / warning / critical)."
      },
      "typeVersion": 1
    },
    {
      "id": "9a2cac21-930c-4f78-a90f-be63cc037cfd",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        304,
        1952
      ],
      "parameters": {
        "color": 7,
        "width": 384,
        "height": 304,
        "content": "## Trigger and fetch tickers\n\nInitiates the workflow to fetch all tickers from Binance Futures on a schedule."
      },
      "typeVersion": 1
    },
    {
      "id": "200fcade-148e-4101-ba07-8a407a88393c",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -256,
        1952
      ],
      "parameters": {
        "width": 528,
        "height": 416,
        "content": "## Binance Futures Funding Rate Monitor\n\n### How it works\n\n1. Trigger the workflow periodically using the schedule trigger.\n2. Fetch all tickers from Binance Futures.\n3. Filter, sort by 24h quote volume, and select the top N symbols.\n4. Loop through each symbol to fetch its funding rate and accumulate data.\n5. Check for alerts and send a notification via Telegram 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 Funding Rate Data** node."
      },
      "typeVersion": 1
    },
    {
      "id": "d3a65504-d2c8-4d1f-b581-dfd0f7ef2e73",
      "name": "Loop Over Tickers",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1008,
        2080
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "connections": {
    "If Alerts Present": {
      "main": [
        [
          {
            "node": "Send Telegram Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Tickers": {
      "main": [
        [
          {
            "node": "Format Alert Messages",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Fetch Ticker Funding Rate",
            "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
          }
        ]
      ]
    },
    "Fetch Ticker Funding Rate": {
      "main": [
        [
          {
            "node": "Accumulate Funding Rate Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Accumulate Funding Rate Data": {
      "main": [
        [
          {
            "node": "Loop Over Tickers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sort and Select Top 20 Tickers": {
      "main": [
        [
          {
            "node": "Loop Over Tickers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}