CoinGeckoの暗号資産価格予測パイプライン:Gemini AI、Decodo、Gmail

上級

これはCrypto Trading分野の自動化ワークフローで、24個のノードを含みます。主にSet, Code, Gmail, DataTable, SplitInBatchesなどのノードを使用。 CoinGeckoの暗号資産価格予測パイプライン:Gemini AI、Decodo、Gmail

前提条件
  • Googleアカウント + Gmail API認証情報
  • Google Gemini API Key

カテゴリー

ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
  "meta": {
    "instanceId": "689fa22e68cd4198e4ae37f3cc44f498087edd235a867e22515be823bab694c7",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "0c833f46-cfe8-4a41-8c4d-a6cb16492b7d",
      "name": "出力をJSONに変換",
      "type": "n8n-nodes-base.code",
      "position": [
        1984,
        2128
      ],
      "parameters": {
        "jsCode": "const data = items[0].json.output;\n\nlet cleaned = data.trim();\n\nif (cleaned.startsWith(\"```\")) {\n  cleaned = cleaned\n    .replace(/^```(json)?/i, \"\")\n    .replace(/```$/, \"\")\n    .trim();\n}\n\nlet parsed;\ntry {\n  parsed = JSON.parse(cleaned);\n} catch (e) {\n  throw new Error(\"❌ Cannot parse JSON from AI Agent: \" + e.message + \"\\nData: \" + cleaned);\n}\n\nreturn [\n  {\n    json: parsed\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "7adcc446-89d8-45d3-8e38-976c6c540e83",
      "name": "データ挿入",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        1408,
        1808
      ],
      "parameters": {
        "columns": {
          "value": {
            "ts": "={{ $json.ts }}",
            "coin": "={{ $json.coin }}",
            "price": "={{ $json.price }}",
            "change_1h": "={{ $json.change_1h }}",
            "change_7d": "={{ $json.change_7d }}",
            "change_24h": "={{ $json.change_24h }}",
            "market_cap": "={{ $json.market_cap }}",
            "volume_24h": "={{ $json.volume_24h }}"
          },
          "schema": [
            {
              "id": "coin",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "coin",
              "defaultMatch": false
            },
            {
              "id": "ts",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "ts",
              "defaultMatch": false
            },
            {
              "id": "price",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "price",
              "defaultMatch": false
            },
            {
              "id": "change_1h",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "change_1h",
              "defaultMatch": false
            },
            {
              "id": "change_24h",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "change_24h",
              "defaultMatch": false
            },
            {
              "id": "change_7d",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "change_7d",
              "defaultMatch": false
            },
            {
              "id": "market_cap",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "market_cap",
              "defaultMatch": false
            },
            {
              "id": "volume_24h",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "volume_24h",
              "defaultMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "b3ek8fMoxaftXS9A",
          "cachedResultUrl": "/projects/I8J05gT6Zk37Q2dE/datatables/b3ek8fMoxaftXS9A",
          "cachedResultName": "Coin Prices"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6d65fa35-bf5d-4b92-b4cd-942987fe2e3a",
      "name": "構造化出力パーサー",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1520,
        2928
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"coin\": \"bitcoin\",\n  \"latest\": {\n    \"ts\": \"2025-10-20T01:02:27Z\",\n    \"price\": 108177,\n    \"change_1h\": 0.4,\n    \"change_24h\": 1.2\n  },\n  \"direction_6h\": \"up\",\n  \"direction_12h\": \"up\",\n  \"direction_24h\": \"up\",\n  \"best_up_window\": { \"start_iso\": \"2025-10-20T04:00:00Z\", \"end_iso\": \"2025-10-20T08:00:00Z\" },\n  \"best_down_window\": null,\n  \"confidence\": \"medium\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "e1570d01-cdf8-408f-ad5b-3991486b7670",
      "name": "JSONをMakeする",
      "type": "n8n-nodes-base.code",
      "position": [
        1168,
        2704
      ],
      "parameters": {
        "jsCode": "const rows = items.map(i => i.json);\n\n// keep last 48h only\nconst cutoff = Date.now() - 48 * 60 * 60 * 1000;\nconst recent = rows.filter(r => new Date(r.ts).getTime() >= cutoff);\n\n// group by coin\nconst byCoin = {};\nfor (const r of recent) {\n  const c = String(r.coin).toLowerCase();\n  if (!byCoin[c]) byCoin[c] = [];\n  byCoin[c].push(r);\n}\n\n// downsample: 30m buckets, max 120 points\nfunction downsample30m(sortedArr) {\n  const out = [];\n  let lastBucket = -1;\n  for (const r of sortedArr) {\n    const t = new Date(r.ts).getTime();\n    const bucket = Math.floor(t / (30 * 60 * 1000));\n    if (bucket !== lastBucket) {\n      out.push([new Date(t).toISOString(), Number(r.price_usd ?? r.price)]);\n      lastBucket = bucket;\n    }\n  }\n  return out.slice(-120);\n}\n\nconst out = [];\nfor (const [coin, arr] of Object.entries(byCoin)) {\n  arr.sort((a,b)=> new Date(a.ts) - new Date(b.ts));\n  if (!arr.length) continue;\n  const last = arr[arr.length - 1];\n\n  out.push({\n    json: {\n      coin,\n      latest: {\n        ts: last.ts,\n        price: Number(last.price_usd ?? last.price),\n        change_1h: typeof last.change_1h === 'number' ? last.change_1h : null,\n        change_24h: typeof last.change_24h === 'number' ? last.change_24h : null\n      },\n      series: downsample30m(arr)\n    }\n  });\n}\n\nreturn out;"
      },
      "typeVersion": 2
    },
    {
      "id": "9ad8435e-08ff-46bf-91bd-7f4026a065f2",
      "name": "スケジュール:30分毎(スクレイピング&ログ)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        416,
        2000
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 30
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "eaab942c-c6fa-4a6a-871e-83c0dcc6af6a",
      "name": "コイン設定",
      "type": "n8n-nodes-base.set",
      "position": [
        736,
        2000
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cf2fee0b-6433-4fad-98e7-91ac8a46684e",
              "name": "coin 1",
              "type": "string",
              "value": "bitcoin"
            },
            {
              "id": "e2b7bd0c-4b93-4b18-b17a-e03eac7611b0",
              "name": "coin 2",
              "type": "string",
              "value": "ethereum"
            },
            {
              "id": "f3099a1f-351f-433e-be96-dc89c56eecb8",
              "name": "coin 3",
              "type": "string",
              "value": "solana"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "08ea4ffc-e47b-4c62-83d3-26028aa2850e",
      "name": "コインアイテム構築",
      "type": "n8n-nodes-base.code",
      "position": [
        960,
        2000
      ],
      "parameters": {
        "jsCode": "const input = items[0].json;\nconst out = [];\n\nfor (const [key, val] of Object.entries(input)) {\n  if (key.toLowerCase().includes('coin') && val) {\n    out.push({ json: { coin: val } });\n  }\n}\n\nreturn out;"
      },
      "typeVersion": 2
    },
    {
      "id": "4048d49b-3270-499c-a348-a5ce7f948908",
      "name": "各コインに対して",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1184,
        2000
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "4212ffb5-e4e2-451b-8399-2e90c81ad684",
      "name": "CoinGeckoスクレイピング(Decodo)",
      "type": "@decodo/n8n-nodes-decodo.decodo",
      "position": [
        1408,
        2000
      ],
      "parameters": {
        "geo": "=United States",
        "url": "=https://www.coingecko.com/en/coins/{{ $json.coin }}"
      },
      "credentials": {
        "decodoApi": {
          "id": "Xc6AkeDSHbyutWEs",
          "name": "Decodo Credentials Hendra"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4cf00c51-1630-44d1-83ba-6585fbc8ca28",
      "name": "コインメトリクス解析(LLM)",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1632,
        2000
      ],
      "parameters": {
        "text": "=Extract coin data from the following website content and return it in the specified JSON format.\n\nWebsite content:\n{{ $json.data.results[0].content }}\n\nCRITICAL INSTRUCTIONS FOR PERCENTAGE CHANGES:\n\nThe content contains a table like this:\n| 1h | 24h | 7d | 14d | 30d | 1y |\n| --- | --- | --- | --- | --- | --- |\n| 0.5% | 5.1% | 1.2% | 9.7% | 8.9% | 54.3% |\n\nThese percentages DO NOT include +/- signs. You MUST:\n1. Search the ENTIRE content for indicators whether each change is positive or negative.\n2. Look for explicit keywords: \"up\", \"down\", \"increased\", \"decreased\", \"gain\", \"loss\", \"rose\", \"fell\".\n3. Look for color indicators in text, class names, or inline styles: \"red\", \"green\", \"text-red\", \"text-green\", \"color: red\", \"color: green\".\n4. Look for arrow or icon descriptions or characters: \"↑\", \"↑\", \"down\", \"arrow-up\", \"arrow-down\", \"fa-arrow-down\".\n5. Check the main price display area and any summary nearby for directional words or icons.\n6. If an indicator signals DOWN/RED/↓ -> the percentage must be NEGATIVE (prefix with -).\n   If an indicator signals UP/GREEN/↑ -> the percentage must be POSITIVE (no - sign).\n7. If multiple contradictory indicators are present near the same number, prioritize: \n   (a) explicit arrow/icon near the number, (b) color/class name near the number, (c) textual phrase in the same sentence/clause.\n\nInformation to extract:\n- Coin name: {{ $('For Each Coin').item.json.coin }}\n- Current timestamp in UTC (use current time when generating response)\n- Current coin price in USD (main price display)\n- Price change over the last 1 hour with correct sign (+/-)\n- Price change over the last 24 hours with correct sign (+/-)\n- Price change over the last 7 days with correct sign (+/-)\n- Market capitalization in USD (convert B/T to full numbers)\n- 24-hour trading volume in USD (convert B/M to full numbers)\n\nEXAMPLE CONVERSIONS (MUST follow exactly):\n- $2.21T -> 2210000000000\n- $66.2B -> 66200000000\n- $1.5M -> 1500000\n\nFORMATTING RULES (MANDATORY):\n1. Return ONLY a single valid JSON object, nothing else.\n2. Timestamp (ts) must be ISO 8601 UTC format (e.g., 2025-10-16T07:41:38Z).\n3. All numeric values must be plain numbers (no $, commas, % signs, not strings).\n   - e.g., change_1h: -0.5  (not \"-0.5%\" and not \"-0.5\")\n4. For percentage fields (change_1h, change_24h, change_7d) return decimal numbers (e.g., -1.4 or 0.5).\n5. If a data point is not found after thorough search, set it to null.\n6. Do NOT output any additional keys beyond the required fields.\n7. Do NOT include code fences, explanations, backticks, or any surrounding text.\n8. The output must be directly parseable via JSON.parse().\n\nIMPORTANT: Output ONLY the single JSON object. DO NOT add explanations or extra text. The output must be VALID JSON parsable by JSON.parse().",
        "options": {
          "systemMessage": "=You are a cryptocurrency data extraction assistant specialized in analyzing CoinGecko-like website content.\n\nYour task is to extract coin information from the provided HTML/text content and return it in a precise JSON format as requested by the user.\n\nRequired output format example:\n{\n  \"coin\": \"bitcoin\",\n  \"ts\": \"2025-10-16T07:41:38Z\",\n  \"price\": 110893,\n  \"change_1h\": -0.5,\n  \"change_24h\": -1.4,\n  \"change_7d\": -9.1,\n  \"market_cap\": 2210211755802,\n  \"volume_24h\": 66206993665\n}\n\nCritical extraction rules:\n1. Timestamp (ts) must be in ISO 8601 UTC format.\n2. All numbers must be pure numeric values without currency symbols, commas, or percent signs.\n3. For percentage changes (change_1h, change_24h, change_7d):\n   - Find the table with \"1h | 24h | 7d | 14d | 30d | 1y\" or similar.\n   - Determine sign using visual/textual indicators: colors (green/red), arrows (↑/↓), class names (text-green/text-red), and directional words (up/down/increased/decreased).\n   - If indicator = negative (red/down/↓) => add negative sign.\n   - If indicator = positive (green/up/↑) => positive number (no sign).\n   - Return as decimal numbers (e.g., -1.4 or 0.5).\n4. Convert market cap and volume units to full numbers (T/B/M/K) exactly as the Example Conversions.\n5. If any field cannot be found after thorough search, return null for that field.\n6. Return only the JSON object — do not add any extra text.\n7. Do not output code blocks, backticks, logs, or surrounding commentary.\n\nIf there are conflicting indicators, prioritize explicit nearby arrow/icon and class/style attributes above textual summary. If no clear indicator exists for a specific change, return the numeric magnitude as found but set its sign to null (or use the best inference from nearby sentences). Always prefer conservative (null) over guessing when uncertain."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "97b97f73-ff5e-4c68-ad98-c92240e36f1f",
      "name": "解析用Gemini",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1696,
        2224
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "id": "858IDdJ9nuIsYkCZ",
          "name": "Hendra Gemini"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e4935000-ecc3-4f40-8506-dde0e1610134",
      "name": "過去48時間データ読み込み",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        944,
        2704
      ],
      "parameters": {
        "limit": {},
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "b3ek8fMoxaftXS9A",
          "cachedResultUrl": "/projects/I8J05gT6Zk37Q2dE/datatables/b3ek8fMoxaftXS9A",
          "cachedResultName": "Coin Prices"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f2758f49-05b4-448c-bf79-05ac8a55784b",
      "name": "次24時間予測(LLM)",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1392,
        2704
      ],
      "parameters": {
        "text": "=COIN: {{$json.coin}}\nLATEST:\n- ts: {{$json.latest.ts}}\n- price: {{$json.latest.price}}\n- change_1h: {{ $json.latest.change_1h }}\n- change_24h: {{ $json.latest.change_24h }}\n\nSERIES (ISO, price) every ~30m, oldest→newest:\n{{$json.series}}\n\nTask: Produce the STRICT JSON per system prompt.",
        "options": {
          "systemMessage": "You analyze short-term crypto price action for beginners. Output STRICT JSON only.\n\nGiven the last ~48h price series and latest snapshot, estimate likely direction windows for the NEXT 24 HOURS.\n\nReturn this JSON:\n{\n  \"direction_6h\": \"up|down|flat\",\n  \"direction_12h\": \"up|down|flat\",\n  \"direction_24h\": \"up|down|flat\",\n  \"best_up_window\": {\"start_iso\":\"\", \"end_iso\":\"\"} or null,\n  \"best_down_window\": {\"start_iso\":\"\", \"end_iso\":\"\"} or null,\n  \"confidence\": \"low|medium|high\"\n}\n\nRules:\n- Use only provided data.\n- If signals mixed → prefer \"flat\" and reduce confidence.\n- best_*_window should be a contiguous window inside the next 24h from latest.ts (estimate based on recent momentum/volatility).\n- JSON only. No markdown, no code fences."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "861691d9-daf8-4d28-b51b-9dc3a7d9fa0b",
      "name": "メール構築(HTML+テキスト)",
      "type": "n8n-nodes-base.code",
      "position": [
        1744,
        2704
      ],
      "parameters": {
        "jsCode": "// Build combined HTML email (HTML only, GMT-flex)\n// Reads GMT offset from node \"Recipient Email\" -> field `timezone`\n// Accepted: \"+8\", \"8\", \"GMT+7\", \"UTC+5:30\", \"-3\", \"-03:30\", 8\n\nfunction safeParse(x) {\n  if (!x && x !== 0) return {};\n  if (typeof x === 'object') return x;\n  try { return JSON.parse(x); } catch { return {}; }\n}\nfunction fmtUSD(n) {\n  if (n == null || isNaN(n)) return '-';\n  return new Intl.NumberFormat('en-US', { maximumFractionDigits: 2 }).format(Number(n));\n}\nfunction dirWord(d) {\n  const x = String(d || '').toLowerCase();\n  if (x === 'up') return 'likely to rise';\n  if (x === 'down') return 'likely to fall';\n  return 'flat';\n}\nfunction confWord(c) {\n  const x = String(c || '').toLowerCase();\n  if (x === 'high') return 'high';\n  if (x === 'medium') return 'medium';\n  return 'low';\n}\n\n// ---- GMT offset helpers ----\nfunction parseGmtOffset(raw) {\n  if (raw === undefined || raw === null || raw === '') return { minutes: 480, label: \"GMT+08:00\" }; // default +8\n  let s = String(raw).trim().toUpperCase();      // \"GMT+7\", \"UTC+5:30\", \"+8\", \"8\", \"-03:30\"\n  s = s.replace(/^GMT|^UTC/, '');\n  if (s === '') s = '+0';\n  if (!/^[-+]/.test(s)) s = (Number(s) >= 0 ? '+' : '') + s; // allow \"8\" -> \"+8\"\n\n  const m = s.match(/^([+-])(\\d{1,2})(?::?(\\d{2}))?$/);\n  if (!m) return { minutes: 480, label: \"GMT+08:00\" };\n  const sign = m[1] === '-' ? -1 : 1;\n  const hh = Math.min(14, Math.max(0, parseInt(m[2], 10)));\n  const mm = m[3] ? Math.min(59, Math.max(0, parseInt(m[3], 10))) : 0;\n  const minutes = sign * (hh * 60 + mm);\n  const lab = `GMT${sign === 1 ? '+' : '-'}${String(hh).padStart(2,'0')}:${String(mm).padStart(2,'0')}`;\n  return { minutes, label: lab };\n}\n\nfunction toLocalHHMM(iso, offsetMin, label) {\n  if (!iso) return null;\n  try {\n    const d = new Date(iso);\n    const local = new Date(d.getTime() + offsetMin * 60000);\n    const t = local.toISOString().substring(11,16); // HH:MM\n    return `${t} ${label}`;\n  } catch { return null; }\n}\nfunction fmtWindowLocal(w, offsetMin, label) {\n  if (!w || !w.start_iso || !w.end_iso) return null;\n  const s = toLocalHHMM(w.start_iso, offsetMin, label);\n  const e = toLocalHHMM(w.end_iso, offsetMin, label);\n  return (s && e) ? `${s} – ${e}` : null;\n}\n\n// ---- read recipient tz ----\nlet tzRaw = null;\ntry { tzRaw = $('Recipient Email + Timezone').first().json.timezone ?? null; } catch {}\nconst tz = parseGmtOffset(tzRaw);\nconst tzLabel = tz.label;\nconst tzMinutes = tz.minutes;\n\n// ---- build per-coin HTML cards ----\nconst cards = items.map(it => {\n  const raw = it.json && ('output' in it.json) ? it.json.output : it.json;\n  const o = safeParse(raw);\n\n  const coin = (o.coin || '').toUpperCase() || 'UNKNOWN';\n  const price = o.latest?.price ?? o.price ?? null;\n  const ch1 = (o.latest?.change_1h ?? o.change_1h);\n  const ch24 = (o.latest?.change_24h ?? o.change_24h);\n  const d6 = o.direction_6h || 'flat';\n  const d12 = o.direction_12h || 'flat';\n  const d24 = o.direction_24h || 'flat';\n  const upWin = fmtWindowLocal(o.best_up_window, tzMinutes, tzLabel);\n  const downWin = fmtWindowLocal(o.best_down_window, tzMinutes, tzLabel);\n  const conf = confWord(o.confidence);\n\n  const html = [\n    `<div style=\"padding:12px;border-radius:8px;border:1px solid #e6e6e6;margin-bottom:10px;background:#ffffff;\">`,\n    `  <div style=\"display:flex;justify-content:space-between;align-items:center\">`,\n    `    <div style=\"font-weight:700;font-size:16px;\">${coin}</div>`,\n    `    <div style=\"font-size:14px;color:#333\">Price: $${fmtUSD(price)}</div>`,\n    `  </div>`,\n    `  <div style=\"margin-top:8px;font-size:13px;color:#333\">`,\n    `    <div><strong>Forecast</strong>: 6h — ${dirWord(d6)}, 12h — ${dirWord(d12)}, 24h — ${dirWord(d24)}</div>`,\n    (typeof ch1 !== 'undefined' && ch1 !== null) ? `    <div>1h change: ${Number(ch1)}%</div>` : ``,\n    (typeof ch24 !== 'undefined' && ch24 !== null) ? `    <div>24h change: ${Number(ch24)}%</div>` : ``,\n    upWin   ? `    <div style=\"margin-top:6px;color:green;\"><strong>Favorable for upside:</strong> ${upWin}</div>` : ``,\n    downWin ? `    <div style=\"margin-top:6px;color:red;\"><strong>Prone to downside:</strong> ${downWin}</div>` : ``,\n    `    <div style=\"margin-top:8px;font-size:12px;color:#666;\"><em>Model confidence: ${conf}</em></div>`,\n    `  </div>`,\n    `</div>`\n  ].filter(Boolean).join('\\n');\n\n  return html;\n});\n\n// fallback if empty\nif (cards.length === 0) {\n  cards.push(`<div style=\"padding:12px;border-radius:8px;border:1px solid #e6e6e6;background:#fff;\">No forecast available.</div>`);\n}\n\n// header time in recipient's GMT\nconst now = new Date();\nconst nowLocal = new Date(now.getTime() + tzMinutes * 60000);\nconst nowLabel = `${nowLocal.toISOString().substring(0,10)} ${nowLocal.toISOString().substring(11,19)} ${tzLabel}`;\n\n// final HTML\nconst body_html = `\n<div style=\"font-family:Arial,Helvetica,sans-serif;background:#f7f7f7;padding:16px;\">\n  <div style=\"max-width:700px;margin:0 auto;\">\n    <div style=\"color:#111;line-height:1.4;\">\n      <h2 style=\"margin:0 0 8px 0;font-size:18px;\">Crypto Forecast — ${nowLabel}</h2>\n      <div style=\"margin-bottom:10px;color:#666;font-size:12px;\">Note: this is not financial advice. For educational purposes only.</div>\n    </div>\n    <div>\n      ${cards.join('<div style=\"height:8px\"></div>')}\n    </div>\n  </div>\n</div>`.trim();\n\nreturn [{ json: { body_html } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "9efa28ee-6359-4488-833c-509b245a5618",
      "name": "メール送信(Gmail)",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1968,
        2704
      ],
      "webhookId": "22e7450f-fa5c-4aed-9849-f394f8514fe8",
      "parameters": {
        "sendTo": "<your_recipient_email>",
        "message": "={{ $json.body_html }}",
        "options": {},
        "subject": "=Crypto Forecast — {{$json.body_html.match(/GMT[+-]\\d{2}:\\d{2}/)?.[0] || 'GMT'}} "
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "xFrtY2kQTvgGH9NM",
          "name": "Hendra Gmail"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "5cbf47a5-6b94-477f-8a89-61a8d23ae24d",
      "name": "予測用Gemini",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1392,
        2928
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "id": "858IDdJ9nuIsYkCZ",
          "name": "Hendra Gemini"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "8bbe2f83-b73d-4caa-af47-34921c50a4cb",
      "name": "付箋2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1600,
        1648
      ],
      "parameters": {
        "color": 5,
        "width": 400,
        "height": 304,
        "content": "Map fields to your Data Table schema. Keep numbers as pure numeric types.\n\nThe data type you must implement to your Data Table:\n\n{\n\"coin\": string,\n\"ts\": string,\n\"price\": number,\n\"change_1h\": number,\n\"change_24h\": number,\n\"change_7d\": number,\n\"market_cap\": number,\n\"volume_24h\": number\n}"
      },
      "typeVersion": 1
    },
    {
      "id": "7ef7e9a1-effa-4509-9199-e05b055eff17",
      "name": "付箋4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        336,
        1904
      ],
      "parameters": {
        "color": 5,
        "width": 272,
        "height": 256,
        "content": "Ensure your instance timezone matches your expectations; schedule uses server time."
      },
      "typeVersion": 1
    },
    {
      "id": "e9245fdd-b8b2-4cd1-90b9-82f56ee78217",
      "name": "受信メールアドレス+タイムゾーン",
      "type": "n8n-nodes-base.set",
      "position": [
        720,
        2704
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "dc601405-466f-4456-9377-f1cb1a34562c",
              "name": "recipientEmail",
              "type": "string",
              "value": "hoktarizal@student.ciputra.ac.id"
            },
            {
              "id": "45b95be4-4a9c-4ad9-9fac-e28b7c4438b1",
              "name": "timezone",
              "type": "string",
              "value": "GMT+0"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "3d971d2b-6242-4c71-8ffa-dade92014e26",
      "name": "付箋3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        2528
      ],
      "parameters": {
        "color": 3,
        "width": 2080,
        "height": 640,
        "content": "## Forecast Email Automation (Daily 18:00)\nThis flow loads the last 48h of crypto data, generates 24h price movement forecasts using Gemini LLM, and sends a formatted HTML email report to the configured recipient based on their timezone.\nIncludes confidence level, directional trend (6h/12h/24h), and favorable trading windows."
      },
      "typeVersion": 1
    },
    {
      "id": "9f8bdde9-e6e5-4d8a-bef5-9796da792d1a",
      "name": "付箋5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        1504
      ],
      "parameters": {
        "color": 4,
        "width": 2080,
        "height": 944,
        "content": "## CoinGecko Scraper & Data Logger (Every 30m)\nThis flow scrapes live cryptocurrency data from CoinGecko at regular 30-minute intervals and stores it in the Data Table for historical tracking and forecasting.\n\nIt loops through a predefined list of coins (e.g., Bitcoin, Ethereum, Solana), extracts market metrics via Decodo, parses the HTML output into structured JSON with Gemini LLM, and logs each entry to the database with clean numeric formatting."
      },
      "typeVersion": 1
    },
    {
      "id": "61a3d05f-c356-45b3-b398-acdda74694bd",
      "name": "スケジュール:毎日18:00(予測メール)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        512,
        2704
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 18
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "eedd1f06-4db7-4cee-b5d3-e123de9ff94d",
      "name": "付箋6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -544,
        1680
      ],
      "parameters": {
        "width": 592,
        "height": 672,
        "content": "## Automated Crypto Forecast Pipeline using Decodo and Gmail\n\nSign Up for Decodo [HERE](https://visit.decodo.com/discount) for discount\n\nThis template scrapes CoinGecko pages for selected coins, converts metrics into clean JSON, stores them in an n8n Data Table, generates 24-hour direction forecasts with Gemini, and emails a concise report.\n\n## Who’s it for?\nCrypto watchers who want automated snapshots, forecasts, and a daily email—without managing a full data stack.\n\n## How it works\n1. 30-min schedule loops coins, scrapes CoinGecko (Decodo), parses metrics, and upserts to Data Table.\n2. 18:00 schedule loads last 48h data.\n3. Gemini estimates next-24h direction windows.\n4. Email is rendered (HTML + plain text) and sent.\n\n## How to set up\n- Add [Decodo](https://visit.decodo.com/discount), Gmail, and Gemini credentials.\n- Open **Configure Coins** to edit tickers.\n- Set Data Table ID.\n- Replace recipient email.\n- (Self-host only) Community node **Decodo** required. @decodo/n8n-nodes-decodo (community)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "bd21e39f-ba2b-41de-908c-5d313a69b9db",
      "name": "付箋7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        656,
        1888
      ],
      "parameters": {
        "color": 5,
        "height": 272,
        "content": "Edit coin values (e.g., bitcoin, ethereum, solana). Use CoinGecko slugs.\n\nhttps://www.coingecko.com/"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "e1570d01-cdf8-408f-ad5b-3991486b7670": {
      "main": [
        [
          {
            "node": "f2758f49-05b4-448c-bf79-05ac8a55784b",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4048d49b-3270-499c-a348-a5ce7f948908": {
      "main": [
        [
          {
            "node": "7adcc446-89d8-45d3-8e38-976c6c540e83",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "4212ffb5-e4e2-451b-8399-2e90c81ad684",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "eaab942c-c6fa-4a6a-871e-83c0dcc6af6a": {
      "main": [
        [
          {
            "node": "08ea4ffc-e47b-4c62-83d3-26028aa2850e",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "08ea4ffc-e47b-4c62-83d3-26028aa2850e": {
      "main": [
        [
          {
            "node": "4048d49b-3270-499c-a348-a5ce7f948908",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "97b97f73-ff5e-4c68-ad98-c92240e36f1f": {
      "ai_languageModel": [
        [
          {
            "node": "4cf00c51-1630-44d1-83ba-6585fbc8ca28",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "e4935000-ecc3-4f40-8506-dde0e1610134": {
      "main": [
        [
          {
            "node": "e1570d01-cdf8-408f-ad5b-3991486b7670",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5cbf47a5-6b94-477f-8a89-61a8d23ae24d": {
      "ai_languageModel": [
        [
          {
            "node": "f2758f49-05b4-448c-bf79-05ac8a55784b",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "0c833f46-cfe8-4a41-8c4d-a6cb16492b7d": {
      "main": [
        [
          {
            "node": "4048d49b-3270-499c-a348-a5ce7f948908",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "f2758f49-05b4-448c-bf79-05ac8a55784b": {
      "main": [
        [
          {
            "node": "861691d9-daf8-4d28-b51b-9dc3a7d9fa0b",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4cf00c51-1630-44d1-83ba-6585fbc8ca28": {
      "main": [
        [
          {
            "node": "0c833f46-cfe8-4a41-8c4d-a6cb16492b7d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6d65fa35-bf5d-4b92-b4cd-942987fe2e3a": {
      "ai_outputParser": [
        [
          {
            "node": "f2758f49-05b4-448c-bf79-05ac8a55784b",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "861691d9-daf8-4d28-b51b-9dc3a7d9fa0b": {
      "main": [
        [
          {
            "node": "9efa28ee-6359-4488-833c-509b245a5618",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4212ffb5-e4e2-451b-8399-2e90c81ad684": {
      "main": [
        [
          {
            "node": "4cf00c51-1630-44d1-83ba-6585fbc8ca28",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "e9245fdd-b8b2-4cd1-90b9-82f56ee78217": {
      "main": [
        [
          {
            "node": "e4935000-ecc3-4f40-8506-dde0e1610134",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "9ad8435e-08ff-46bf-91bd-7f4026a065f2": {
      "main": [
        [
          {
            "node": "eaab942c-c6fa-4a6a-871e-83c0dcc6af6a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "61a3d05f-c356-45b3-b398-acdda74694bd": {
      "main": [
        [
          {
            "node": "e9245fdd-b8b2-4cd1-90b9-82f56ee78217",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
よくある質問

このワークフローの使い方は?

上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。

このワークフローはどんな場面に適していますか?

上級 - 仮想通貨取引

有料ですか?

このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。

ワークフロー情報
難易度
上級
ノード数24
カテゴリー1
ノードタイプ11
難易度説明

上級者向け、16ノード以上の複雑なワークフロー

作成者
外部リンク
n8n.ioで表示

このワークフローを共有

カテゴリー

カテゴリー: 34