{
  "id": "z8p6r4MRvb3YWvpa",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Automated Daily Report of Top 100 Stock Price Changes",
  "tags": [],
  "nodes": [
    {
      "id": "e84b9576-6c4a-424c-9f64-0ce3cdca5909",
      "name": "Daily Market Close Trigger\t",
      "type": "n8n-nodes-base.cron",
      "position": [
        -624,
        -32
      ],
      "parameters": {
        "triggerTimes": {
          "item": [
            {
              "hour": 17
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d4544920-d3b4-4928-88c9-435fd82e7cbe",
      "name": "Set Configuration Variables\t",
      "type": "n8n-nodes-base.set",
      "position": [
        -400,
        -32
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "api-key-assignment",
              "name": "twelvedata_api_key",
              "type": "string",
              "value": "your_api_key_add_here"
            },
            {
              "id": "symbols-assignment",
              "name": "top_symbols",
              "type": "string",
              "value": "AAPL,MSFT,GOOGL,AMZN,TSLA"
            },
            {
              "id": "whatsapp-number",
              "name": "whatsapp_number",
              "type": "string",
              "value": "+1234567890"
            },
            {
              "id": "email-recipient",
              "name": "email_recipient",
              "type": "string",
              "value": "user@example.com"
            },
            {
              "id": "fd42d040-23dc-456f-89ee-144be97a1e8c",
              "name": "",
              "type": "string",
              "value": ""
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "30d03cb8-c49a-4eb1-8e58-5cf8434c313b",
      "name": "Fetch Stock Data from Twelve Data\t",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -176,
        -32
      ],
      "parameters": {
        "url": "=https://api.twelvedata.com/quote?symbol={{ $json.top_symbols }}&apikey={{ $json.twelvedata_api_key }}",
        "options": {
          "timeout": 30000
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "interval",
              "value": "1day"
            },
            {
              "name": "outputsize",
              "value": "1"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "9ab66310-6532-4267-bf5e-38131317a677",
      "name": "Process Stock Movements\t",
      "type": "n8n-nodes-base.code",
      "position": [
        48,
        -32
      ],
      "parameters": {
        "jsCode": "const stockData = $input.first().json;\nlet processedStocks = [];\n\n// Check for API error\nif (stockData.error) {\n  throw new Error(`Twelve Data API Error: ${stockData.error.message}`);\n}\n\n// Handle single or multiple stock responses\nlet quotes = [];\nif (Array.isArray(stockData)) {\n  quotes = stockData;\n} else if (stockData.symbol) {\n  quotes = [stockData];\n} else {\n  quotes = Object.values(stockData).filter(item => item.symbol);\n}\n\nfor (let stock of quotes) {\n  if (stock && stock.symbol && stock.percent_change) {\n    const percentChange = parseFloat(stock.percent_change);\n    const price = parseFloat(stock.close || stock.price);\n    const change = parseFloat(stock.change);\n    processedStocks.push({\n      symbol: stock.symbol,\n      name: stock.name || stock.symbol,\n      price: isNaN(price) ? null : price,\n      change: isNaN(change) ? null : change,\n      percent_change: isNaN(percentChange) ? null : percentChange,\n      volume: stock.volume ? parseInt(stock.volume) : null,\n      movement_type: percentChange > 0 ? 'gain' : 'loss',\n      abs_percent_change: Math.abs(percentChange)\n    });\n  }\n}\n\n// Sort by absolute percentage change\nprocessedStocks.sort((a, b) => b.abs_percent_change - a.abs_percent_change);\n\n// Top 5 movers\nconst topMovers = processedStocks.slice(0, 5);\nconst gainers = topMovers.filter(stock => stock.percent_change > 0).slice(0, 3);\nconst losers = topMovers.filter(stock => stock.percent_change < 0).slice(0, 3);\n\nconst currentDate = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\n\nreturn [{ json: { date: currentDate, total_stocks: processedStocks.length, top_gainers: gainers, top_losers: losers, biggest_movers: topMovers } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "940a5f7c-555d-4eab-8bd1-d4a44060d315",
      "name": "Format WhatsApp Message\t",
      "type": "n8n-nodes-base.code",
      "position": [
        272,
        -112
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nlet message = `\ud83d\udcc8 *DAILY STOCK MARKET REPORT*\\n`;\nmessage += `\ud83d\udcc5 Date: ${data.date}\\n`;\nmessage += `\ud83d\udcca Analyzed: ${data.total_stocks} stocks\\n\\n`;\nmessage += `\ud83d\udfe2 *TOP GAINERS*\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n`;\ndata.top_gainers.forEach((stock, index) => {\n  message += `${index + 1}. ${stock.symbol}\\n`;\n  message += `   \ud83d\udcb0 $${stock.price?.toFixed(2) || 'N/A'}\\n`;\n  message += `   \ud83d\udcc8 +${stock.percent_change?.toFixed(2) || 'N/A'}% (+$${stock.change?.toFixed(2) || 'N/A'})\\n\\n`;\n});\nmessage += `\ud83d\udd34 *TOP LOSERS*\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n`;\ndata.top_losers.forEach((stock, index) => {\n  message += `${index + 1}. ${stock.symbol}\\n`;\n  message += `   \ud83d\udcb0 $${stock.price?.toFixed(2) || 'N/A'}\\n`;\n  message += `   \ud83d\udcc9 ${stock.percent_change?.toFixed(2) || 'N/A'}% ($${stock.change?.toFixed(2) || 'N/A'})\\n\\n`;\n});\nmessage += `\\n\u26a1 Generated by Stock Alert Bot`;\nreturn [{ json: { whatsapp_message: message } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "3d3b1981-004c-4ae1-a450-63690b0e9100",
      "name": "Format Email Content\t",
      "type": "n8n-nodes-base.code",
      "position": [
        272,
        48
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nlet htmlContent = `<!DOCTYPE html><html><head><style>body { font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }.container { max-width: 600px; margin: 0 auto; background: white; padding: 20px; border-radius: 10px; }.header { text-align: center; border-bottom: 2px solid #007bff; padding-bottom: 10px; }.section { margin-bottom: 20px; }.stock-table { width: 100%; border-collapse: collapse; }.stock-table th, .stock-table td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }.stock-table th { background-color: #f8f9fa; }.gain { color: #28a745; }.loss { color: #dc3545; }.symbol { font-weight: bold; color: #007bff; }</style></head><body><div class=\"container\"><div class=\"header\"><h2>\ud83d\udcc8 Daily Stock Market Report</h2><p><strong>Date:</strong> ${data.date}</p></div><div class=\"section\"><h3 style=\"color: #28a745;\">\ud83d\udfe2 Top Gainers</h3><table class=\"stock-table\"><thead><tr><th>Symbol</th><th>Price</th><th>Change</th><th>% Change</th></tr></thead><tbody>`;\ndata.top_gainers.forEach((stock) => {\n  htmlContent += `<tr><td class=\"symbol\">${stock.symbol}</td><td>$${stock.price?.toFixed(2) || 'N/A'}</td><td class=\"gain\">+$${stock.change?.toFixed(2) || 'N/A'}</td><td class=\"gain\">+${stock.percent_change?.toFixed(2) || 'N/A'}%</td></tr>`;\n});\nhtmlContent += `</tbody></table></div><div class=\"section\"><h3 style=\"color: #dc3545;\">\ud83d\udd34 Top Losers</h3><table class=\"stock-table\"><thead><tr><th>Symbol</th><th>Price</th><th>Change</th><th>% Change</th></tr></thead><tbody>`;\ndata.top_losers.forEach((stock) => {\n  htmlContent += `<tr><td class=\"symbol\">${stock.symbol}</td><td>$${stock.price?.toFixed(2) || 'N/A'}</td><td class=\"loss\">$${stock.change?.toFixed(2) || 'N/A'}</td><td class=\"loss\">${stock.percent_change?.toFixed(2) || 'N/A'}%</td></tr>`;\n});\nhtmlContent += `</tbody></table></div><div style=\"text-align: center; margin-top: 20px; color: #666;\"><p>\u26a1 Generated by Stock Alert System</p></div></body></html>`;\nconst plainText = `DAILY STOCK MARKET REPORT\\nDate: ${data.date}\\nStocks Analyzed: ${data.total_stocks}\\n\\nTOP GAINERS:\\n${data.top_gainers.map((stock, i) => `${i+1}. ${stock.symbol}: $${stock.price?.toFixed(2) || 'N/A'} (+${stock.percent_change?.toFixed(2) || 'N/A'}%)`).join('\\n')}\\n\\nTOP LOSERS:\\n${data.top_losers.map((stock, i) => `${i+1}. ${stock.symbol}: $${stock.price?.toFixed(2) || 'N/A'} (${stock.percent_change?.toFixed(2) || 'N/A'}%)`).join('\\n')}\\n\\nGenerated by Stock Alert System`;\nreturn [{ json: { email_html: htmlContent, email_text: plainText, email_subject: `Daily Stock Report - ${data.date}` } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "d703c8f4-20c5-4960-8b11-59dd20d8952a",
      "name": "Send Email Alert\t",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        496,
        48
      ],
      "parameters": {
        "html": "={{ $json.email_html }}",
        "options": {},
        "subject": "={{ $json.email_subject }}",
        "toEmail": "={{ $('Set Configuration Variables\t').item.json.email_recipient }}",
        "fromEmail": "user@example.com",
        "emailFormat": "html"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "a6436b0d-b49e-4186-b9d7-e80177665e8f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -640,
        -176
      ],
      "parameters": {
        "width": 160,
        "height": 300,
        "content": "Triggers daily at 5:00 PM (after market close) Monday-Friday.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1b1643d8-294d-457f-9164-9a0990ecef94",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -432,
        -176
      ],
      "parameters": {
        "color": 4,
        "width": 170,
        "height": 300,
        "content": "Sets API key, stock symbols, and alert recipients.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e1cafd10-344b-4d39-91d6-04588d7e6d67",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        -176
      ],
      "parameters": {
        "color": 3,
        "width": 170,
        "height": 300,
        "content": "Fetches stock data for selected symbols via Twelve Data API.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "4dcb1252-bcc4-4b6d-8a05-b5d8600bce13",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -176
      ],
      "parameters": {
        "color": 5,
        "width": 170,
        "height": 300,
        "content": "Processes stock data to identify top gainers and losers.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "444844c9-b1c2-40b6-907e-0b93e08aea6c",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        464,
        -208
      ],
      "parameters": {
        "color": 6,
        "width": 170,
        "height": 332,
        "content": "Sends formatted alerts via WhatsApp and Email.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "26752e0e-0ab8-4f67-858b-c0d954891d9b",
      "name": "Send message",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        480,
        -112
      ],
      "parameters": {
        "textBody": "={{ $json.whatsapp_message }}",
        "operation": "send",
        "phoneNumberId": "=+919877663344",
        "additionalFields": {},
        "recipientPhoneNumber": "={{ $('Set Configuration Variables\t').item.json.whatsapp_number }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "e99f69ff-d8ff-4f02-980c-5c27a29d37cb",
  "connections": {
    "Format Email Content\t": {
      "main": [
        [
          {
            "node": "Send Email Alert\t",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format WhatsApp Message\t": {
      "main": [
        [
          {
            "node": "Send message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Stock Movements\t": {
      "main": [
        [
          {
            "node": "Format WhatsApp Message\t",
            "type": "main",
            "index": 0
          },
          {
            "node": "Format Email Content\t",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily Market Close Trigger\t": {
      "main": [
        [
          {
            "node": "Set Configuration Variables\t",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Configuration Variables\t": {
      "main": [
        [
          {
            "node": "Fetch Stock Data from Twelve Data\t",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Stock Data from Twelve Data\t": {
      "main": [
        [
          {
            "node": "Process Stock Movements\t",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}