{
  "id": "5UieRWkGPv2XT9W1",
  "name": "DIY Stock Watchlist Alert",
  "tags": [],
  "nodes": [
    {
      "id": "d7861ef9-0f89-4c62-95b3-33aec6a30256",
      "name": "Market Hours Polling Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        720,
        464
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "*/5 9-15 * * 1-5"
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "c22fcd32-029f-46c2-bd08-f7693ed96226",
      "name": "Load Stock Watchlist",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        944,
        464
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 955947842,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1fwvOWtXwLzgx1FF_v1FaxTMDEiIN0qPF_zE1uFJj1Q8/edit#gid=955947842",
          "cachedResultName": "Stock Watchlist"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1fwvOWtXwLzgx1FF_v1FaxTMDEiIN0qPF_zE1uFJj1Q8",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1fwvOWtXwLzgx1FF_v1FaxTMDEiIN0qPF_zE1uFJj1Q8/edit?usp=drivesdk",
          "cachedResultName": "N8N - PRACTICE"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "3c2458b6-7208-46f1-b36c-690b5f98e17a",
      "name": "Filter Active Stocks",
      "type": "n8n-nodes-base.code",
      "position": [
        1184,
        464
      ],
      "parameters": {
        "jsCode": "const rows = $input.all();\nconst symbols = rows\n  .filter(r => r.json.active === true || r.json.active === 'TRUE')\n  .map(r => r.json.symbol.trim().toUpperCase());\n\n// Pass both the symbols array AND the full row data downstream\nreturn [{ json: { symbols, rows: rows.map(r => r.json) } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "9129b871-78a6-4b4e-90ab-86d3ed500381",
      "name": "Prepare NSE Quote Request",
      "type": "n8n-nodes-base.set",
      "position": [
        1408,
        464
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a96ea1f2-9ace-4425-92f8-eaed55e07ace",
              "name": "apiBody",
              "type": "array",
              "value": "={{ $json.rows.map((item)=>{\n  return item.Name\n}) }}"
            },
            {
              "id": "f0b763f0-27a4-4b0e-8dff-dda7a127b061",
              "name": "watchlistRows",
              "type": "array",
              "value": "={{ $json.rows }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "222136a6-6d6c-4977-9742-3409122c0abe",
      "name": "Check Alert Availability",
      "type": "n8n-nodes-base.if",
      "position": [
        2128,
        464
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c2694ac3-dc08-405c-9067-6f5a42f44386",
              "operator": {
                "type": "object",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "eab5277e-5add-4759-90dc-9b8760a51c03",
      "name": "No Alerts Exit",
      "type": "n8n-nodes-base.noOp",
      "position": [
        2432,
        544
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "a942de46-4d02-438e-a22c-f14b822c75d0",
      "name": "Route Alert Type",
      "type": "n8n-nodes-base.switch",
      "position": [
        2432,
        320
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "24b3bbf9-f7f5-4c2d-88b1-8b28002b4d43",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "above",
                    "rightValue": "={{ $json.direction }}"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "b25e96dc-c762-499e-870a-517f4235541a",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "below",
                    "rightValue": "={{ $json.direction }}"
                  }
                ]
              }
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "dbb643c5-eb7b-4dd4-bc40-fd1dab7e6fe5",
      "name": "Build Sell Alert Message",
      "type": "n8n-nodes-base.set",
      "position": [
        2656,
        272
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "4ef295fb-b364-46d1-a064-4893dc47b6b9",
              "name": "alertMessage",
              "type": "string",
              "value": "=SELL ALERT: {{ $json.symbol }} hit \u20b9{{ $json.price }} (above \u20b9{{ $json.threshold }})"
            },
            {
              "id": "71b6d672-ff68-4869-863e-675cc93b0a7b",
              "name": "subject",
              "type": "string",
              "value": "=SELL Signal \u2014 {{ $json.symbol }}"
            },
            {
              "id": "8ea5e083-571a-4a71-9d91-cab2cc3c2827",
              "name": "symbol",
              "type": "string",
              "value": "={{ $json.symbol }}"
            },
            {
              "id": "571184ac-ae99-42ec-a566-502896525427",
              "name": "price",
              "type": "number",
              "value": "={{ $json.price }}"
            },
            {
              "id": "e8d8fa20-7e7b-46a6-8bcb-4c7949f1e119",
              "name": "threshold",
              "type": "number",
              "value": "={{ $json.threshold }}"
            },
            {
              "id": "975d1de5-75fe-450b-9854-966739c4473e",
              "name": "direction",
              "type": "string",
              "value": "={{ $json.direction }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "6f335a72-763f-4b29-bd52-800ad9bf30a0",
      "name": "Build Buy Alert Message",
      "type": "n8n-nodes-base.set",
      "position": [
        2656,
        464
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "8def4666-46f9-4955-a956-a2e879a81d41",
              "name": "alertMessage",
              "type": "string",
              "value": "=BUY ALERT: {{ $json.symbol }} dropped to \u20b9{{ $json.price }} (below \u20b9{{ $json.threshold }})"
            },
            {
              "id": "08a2fb59-0368-40ca-92a5-5d02505d2d97",
              "name": "subject",
              "type": "string",
              "value": "=BUY Signal \u2014 {{ $json.symbol }}"
            },
            {
              "id": "bea7e5ef-7e53-49ec-acd7-9bbd8cbbc393",
              "name": "symbol",
              "type": "string",
              "value": "={{ $json.symbol }}"
            },
            {
              "id": "ce39dfc7-3c14-4f69-afca-ad8647c23b48",
              "name": "price",
              "type": "number",
              "value": "={{ $json.price }}"
            },
            {
              "id": "8eec8d5a-518c-4dad-ac38-f9ffbf18199e",
              "name": "threshold",
              "type": "number",
              "value": "={{ $json.threshold }}"
            },
            {
              "id": "3f1b2293-69e2-4e5d-ac6d-dfc7cb4af1e5",
              "name": "direction",
              "type": "string",
              "value": "={{ $json.direction }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "8a26a0c1-898d-4000-8d98-621d3d3b630d",
      "name": "Combine Alert Streams",
      "type": "n8n-nodes-base.merge",
      "position": [
        2880,
        368
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "24db3c2a-38bd-4613-a774-ceff7055533f",
      "name": "Send Email Alert",
      "type": "n8n-nodes-base.gmail",
      "position": [
        3216,
        336
      ],
      "parameters": {
        "message": "={{ $json.alertMessage }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "={{ $json.subject }}",
        "emailType": "text"
      },
      "typeVersion": 2.2
    },
    {
      "id": "9c71b201-6087-42ce-9182-3243d668d5c5",
      "name": "Log Alert History",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3216,
        512
      ],
      "parameters": {
        "columns": {
          "value": {
            "price": "={{ $json.price }}",
            "symbol": "={{ $json.symbol }}",
            "direction": "={{ $json.direction }}",
            "threshold": "={{ $json.threshold }}",
            "timestamp": "={{ new Date().toISOString() }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "symbol",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "symbol",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "price",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "price",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "direction",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "direction",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "threshold",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "threshold",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1545314164,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1fwvOWtXwLzgx1FF_v1FaxTMDEiIN0qPF_zE1uFJj1Q8/edit#gid=1545314164",
          "cachedResultName": "AlertLog"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1fwvOWtXwLzgx1FF_v1FaxTMDEiIN0qPF_zE1uFJj1Q8",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1fwvOWtXwLzgx1FF_v1FaxTMDEiIN0qPF_zE1uFJj1Q8/edit?usp=drivesdk",
          "cachedResultName": "N8N - PRACTICE"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "e5baf996-9fba-4311-a90a-006933dee0db",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -176
      ],
      "parameters": {
        "width": 608,
        "height": 864,
        "content": "## Stock Watchlist Monitoring & Alert Automation\nThis workflow continuously monitors stock prices from a Google Sheets watchlist and automatically generates BUY or SELL alerts when configured thresholds are reached.\n\n\n### How it works:\nThe workflow runs every 5 minutes during market hours using a schedule trigger.\nActive stocks are loaded from the Stock Watchlist sheet.\nOnly enabled rows are processed and converted into a request payload.\nLatest market prices are fetched from the NSE quotes API.\nCurrent prices are compared against the configured buy_below and sell_above values.\nMatching conditions generate alert records with stock symbol, current price, threshold, and signal type.\nAlerts are split into BUY and SELL paths to create appropriate messages.\nNotifications are emailed and every alert is stored in the AlertLog sheet for tracking.\n\n### Setup steps:\nConfigure Google Sheets credentials.\nCreate Stock Watchlist and AlertLog sheets.\nEnsure watchlist contains symbol, active, buy_below, and sell_above columns.\nConfigure Gmail credentials for notifications.\nVerify NSE quote API availability.\nAdjust market schedule timing if needed."
      },
      "typeVersion": 1
    },
    {
      "id": "24708b4c-5619-4ebb-b654-46f42104a644",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        656,
        192
      ],
      "parameters": {
        "color": 2,
        "width": 432,
        "height": 496,
        "content": "### Trigger & Watchlist Loading\n\nLoads stock tracking configuration from Google Sheets.\n\nRuns every 5 minutes during market sessions and retrieves watchlist rows."
      },
      "typeVersion": 1
    },
    {
      "id": "94336ac1-0d5e-49c2-8bd1-2286ecae996d",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1136,
        192
      ],
      "parameters": {
        "color": 2,
        "width": 640,
        "height": 496,
        "content": "### Data Preparation & Market Fetch\n\nPrepares symbols and requests latest market quotes.\n\nBuilds API payload and retrieves live stock prices."
      },
      "typeVersion": 1
    },
    {
      "id": "32752f12-19ff-4eed-9bc7-87954dbf6742",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1824,
        192
      ],
      "parameters": {
        "color": 2,
        "width": 480,
        "height": 496,
        "content": "### Alert Detection Engine\n\nCompares market prices against configured thresholds.\n\nStops execution when no conditions are matched."
      },
      "typeVersion": 1
    },
    {
      "id": "b0779753-9428-4eeb-b8cb-5916de08a243",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2384,
        128
      ],
      "parameters": {
        "color": 2,
        "width": 640,
        "height": 560,
        "content": "### Alert Routing & Message Creation\n\nSeparates BUY and SELL events and creates notification messages.\n\nProduces standardized alert outputs."
      },
      "typeVersion": 1
    },
    {
      "id": "a1d92315-0cb3-4b95-b31f-1debcde2058b",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3056,
        128
      ],
      "parameters": {
        "color": 2,
        "width": 416,
        "height": 560,
        "content": "### Notification & Logging\n\nFinal delivery and audit layer.\n\nSends notifications and stores alerts in Google Sheets history."
      },
      "typeVersion": 1
    },
    {
      "id": "ac814d2d-5a79-4aed-8a6c-6dc9c33031d3",
      "name": "Detect Buy Sell Signals",
      "type": "n8n-nodes-base.code",
      "position": [
        1904,
        464
      ],
      "parameters": {
        "jsCode": "let apiResponse = []; // array of quotes\nfor (const key in $input.first().json.prices) {\n  if (Object.prototype.hasOwnProperty.call($input.first().json.prices, key)) {\n    const element = $input.first().json.prices[key];\n    apiResponse.push(element);\n  }\n}\n\nconst watchlistRows = $('Prepare NSE Quote Request').first().json.watchlistRows;\nconsole.log(watchlistRows)\n\n\n// Build a price map\nconst priceMap = {};\napiResponse.forEach(q => { priceMap[q.symbol] = q.last_price; });\n\nconst alerts = [];\nwatchlistRows.forEach(row => {\n  const price = priceMap[row.Name];\n  if (!price) return;\n\n  const above = row.sell_above && price >= parseFloat(row.sell_above);\n  const below = row.buy_below  && price <= parseFloat(row.buy_below);\n\n  if (above || below) {\n    alerts.push({\n      symbol:    row.Name,\n      price,\n      threshold: above ? row.sell_above : row.buy_below,\n      direction: above ? 'above' : 'below',\n    });\n  }\n});\n\nreturn alerts.map(a => ({ json: a }));"
      },
      "typeVersion": 2
    },
    {
      "id": "f66ffbb2-6981-4869-b9c9-1c0e5ddb692f",
      "name": "Fetch NSE Market Quotes",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1632,
        464
      ],
      "parameters": {
        "url": "https://memic-nse-quotes-api.hf.space/quotes",
        "method": "POST",
        "options": {
          "timeout": 10000
        },
        "jsonBody": "={{ {\n\"symbols\": $json.apiBody\n} }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.4
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "ba2f4722-a1d5-4a91-b632-916506e2dfe4",
  "nodeGroups": [],
  "connections": {
    "Route Alert Type": {
      "main": [
        [
          {
            "node": "Build Sell Alert Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Buy Alert Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Active Stocks": {
      "main": [
        [
          {
            "node": "Prepare NSE Quote Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Stock Watchlist": {
      "main": [
        [
          {
            "node": "Filter Active Stocks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine Alert Streams": {
      "main": [
        [
          {
            "node": "Send Email Alert",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log Alert History",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Buy Alert Message": {
      "main": [
        [
          {
            "node": "Combine Alert Streams",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Detect Buy Sell Signals": {
      "main": [
        [
          {
            "node": "Check Alert Availability",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch NSE Market Quotes": {
      "main": [
        [
          {
            "node": "Detect Buy Sell Signals",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Sell Alert Message": {
      "main": [
        [
          {
            "node": "Combine Alert Streams",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Alert Availability": {
      "main": [
        [
          {
            "node": "Route Alert Type",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Alerts Exit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare NSE Quote Request": {
      "main": [
        [
          {
            "node": "Fetch NSE Market Quotes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Market Hours Polling Trigger": {
      "main": [
        [
          {
            "node": "Load Stock Watchlist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}