{
  "id": "d4zYlMotJ8QScsL0",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "SENSEX Signal Generator",
  "tags": [],
  "nodes": [
    {
      "id": "3adc7301-269e-464d-8710-16ec42c5e306",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1072,
        432
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "facc7467-aca8-495b-9c73-944e2ea78944",
      "name": "Fetching INDEX data",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -64,
        224
      ],
      "parameters": {
        "url": "https://query1.finance.yahoo.com/v8/finance/chart/%5EBSESN?range=1mo&interval=1d",
        "options": {}
      },
      "typeVersion": 4.3
    },
    {
      "id": "b80fb44b-61ad-42cc-9a41-6d5f0b839aa8",
      "name": "Code to gain insights",
      "type": "n8n-nodes-base.code",
      "position": [
        128,
        224
      ],
      "parameters": {
        "jsCode": "const prices = $json.chart.result[0].indicators.quote[0].close;\n\n// helper\nfunction avg(arr) {\n  return arr.reduce((a, b) => a + b, 0) / arr.length;\n}\n\n// moving averages\nconst last5 = prices.slice(-5);\nconst last20 = prices.slice(-20);\n\nconst shortMA = avg(last5);\nconst longMA = avg(last20);\n\n// momentum\nconst momentum = shortMA - longMA;\n\n// price change\nconst latest = prices[prices.length - 1];\nconst old = prices[prices.length - 6];\n\nconst priceChange = ((latest - old) / old) * 100;\n\n// volatility\nconst mean = avg(prices);\nconst variance = avg(prices.map(p => (p - mean) ** 2));\nconst volatility = Math.sqrt(variance);\n\nreturn [{\n  trend: shortMA > longMA ? \"uptrend\" : \"downtrend\",\n  shortMA,\n  longMA,\n  momentum,\n  volatility,\n  priceChange\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "376596c8-6a69-4de5-9baf-49bc94070c8e",
      "name": "AI agent output parsing",
      "type": "n8n-nodes-base.set",
      "position": [
        1600,
        224
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "bd6fbe6e-1e35-4ec2-b546-3a76f66eef24",
              "name": "parsed",
              "type": "object",
              "value": "={{ JSON.parse($json.output.replace(/```json|```|\\n/g, '').trim()) }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "300d9b6a-2fdb-41dc-8e1d-e6320d7e7658",
      "name": "Validating signal",
      "type": "n8n-nodes-base.if",
      "position": [
        2336,
        224
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "84b03050-d8d6-4a27-8b2f-0e1c28dc3664",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.score }}",
              "rightValue": 70
            },
            {
              "id": "2270ebeb-a0cf-415b-b20d-1e3b7c5f269f",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.final_signal }}",
              "rightValue": "Hold"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "07980712-cd93-4d6f-9088-2b14a0e13546",
      "name": "Log into sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2592,
        208
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $now.toFormat('dd-MM-yyyy') }}{{ $now.toFormat('dd-MM-yyyy HH:mm:ss') }}",
            "Index": "SENSEX",
            "Trend": "={{ $('Code to gain insights').item.json.trend }}",
            "Reason": "={{ $json.reason }}",
            "Signal": "={{ $json.signal }}",
            "Confidence": "={{ $json.confidence }}"
          },
          "schema": [
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Index",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Index",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Signal",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Signal",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Confidence",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Confidence",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Trend",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Trend",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Reason",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Reason",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1wLS1N4_lnKTfUoSohlCm6zEzjIFO1sR4Mn-IHOJ-MFg/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1wLS1N4_lnKTfUoSohlCm6zEzjIFO1sR4Mn-IHOJ-MFg",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1wLS1N4_lnKTfUoSohlCm6zEzjIFO1sR4Mn-IHOJ-MFg/edit?usp=drivesdk",
          "cachedResultName": "Signals"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "a1dd836e-13cc-42fd-8aa0-9b62e3a1f248",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -992,
        -480
      ],
      "parameters": {
        "width": 656,
        "height": 960,
        "content": "## AI-POWERED HYBRID SIGNAL GENERATOR (SENSEX)\n\nHOW THIS WORKFLOW WORKS\nThis workflow automates stock market analysis using a hybrid approach: Technical Indicators + Fundamental News Sentiment.\n\nFlow:\n1. Trigger workflow (Manual / Cron)\n2. Fetch SENSEX historical data (Yahoo Finance API)\n3. Calculate indicators:\n   - Moving Averages (5-day & 20-day)  - Momentum  - Volatility  - Price Change %\n4. Fetch latest SENSEX news headlines (Google News RSS) & limit to top articles\n5. Structure technical and news data for AI processing\n6. Gemini AI generates:\n   - Signal (Buy / Sell / Hold)  - Confidence  - Strength  - Risk Level  - Reason\n7. Parse AI output into JSON & calculate signal score\n8. Validate signals (Score > 70 AND Signal is NOT \"Hold\")\n9. Store actionable results in Google Sheets\n\nSETUP STEPS\n1. Import this workflow into n8n\n\n2. Configure Credentials:\n   - Google Gemini API\n   - Google Sheets OAuth2\n\n3. Prepare Google Sheet with columns:\n   Date | Index | Signal | Confidence | Trend | Reason\n\n4. Verify URLs in the HTTP Request node (Yahoo Finance) and RSS Read node (Google News)\n\n5. Execute workflow and verify:\n   - AI output is successfully synthesizing math + news\n   - Valid data is stored in Google Sheets\n\nCORE FEATURES\n AI Hybrid Analysis (Technical Data + Fundamental News)  \n Dynamic Signal Scoring Engine  \n Automated Signal Validation (Score-based & Excludes Holds)  \n Real-time Logging to Sheets  \n Scalable for multiple indices  \n\nOBJECTIVE\nConvert raw market data and real-world news sentiment into intelligent, AI-driven trading signals for better decision-making."
      },
      "typeVersion": 1
    },
    {
      "id": "9434ad32-3d4e-404c-bbf9-7e08886d278a",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1504,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 624,
        "height": 416,
        "content": " ##  DATA TRANSFORMATION & SIGNAL ENGINE\n\nThis section acts as the central processing unit of the workflow.\n\nResponsibilities:\n1. Parse AI response into structured JSON       \n2. Extract key variables:   - signal, strength, confidence, risk level\n3. Standardize data for consistency  \n4. Compute signal score based on: - Confidence level - Signal strength  - Risk assessment\n"
      },
      "typeVersion": 1
    },
    {
      "id": "108d324e-9c74-4621-b2eb-e836097f83bc",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        32
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 368,
        "content": " ## Market Data & Indicator Processing\n\nFetches SENSEX data and computes key indicators like trend, momentum, volatility and price change.\n\n The SET node standardizes these values for downstream AI analysis."
      },
      "typeVersion": 1
    },
    {
      "id": "73a1b6ee-859a-4728-a7f3-082594348356",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2272,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 320,
        "content": "## Signal Validation & Storage\n\n- Filters high-quality signals based on score threshold (>70). \n- Valid signals are logged into Google Sheets with key details like signal type, confidence, trend and reasoning for tracking and analysis."
      },
      "typeVersion": 1
    },
    {
      "id": "f0d94fdc-5c3f-464c-bbc6-8df8684f936e",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1024,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 336,
        "height": 512,
        "content": "##  AI Signal Generation\n\nUses Gemini AI to analyze market indicators and generate trading signals with confidence, strength and risk level."
      },
      "typeVersion": 1
    },
    {
      "id": "33620934-953d-46ed-89a0-24d9510c6a9a",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1072,
        224
      ],
      "parameters": {
        "text": "=You are an expert stock market analyst AI. Your task is to generate a trading signal for the SENSEX by analyzing both technical indicators and recent fundamental news sentiment.\n\n### INPUT DATA\n\n**Technical Indicators:**\nTrend: {{ $('Code to gain insights').item.json.trend }}\nMomentum: {{ $('Code to gain insights').item.json.momentum }}\nVolatility:{{ $('Code to gain insights').item.json.volatility }}\nPrice Change: {{ $('Code to gain insights').item.json.priceChange }}\n\n**Latest SENSEX News:**\n{{ $json.title}}\n### ANALYSIS RULES\n1. Evaluate the technical indicators to determine the current mathematical market structure.\n2. Analyze the news headlines to gauge fundamental market sentiment (bullish, bearish or neutral).\n3. Synthesize both data points. If the news sentiment heavily contradicts the technical trend, adjust your output by lowering your confidence and increasing the risk level.\n4. Provide clear reasoning that explicitly mentions BOTH the technicals and the news context.\n\n### OUTPUT FORMAT\nYou must return ONLY a valid JSON object matching the exact structure below. Do not include markdown formatting like ```json or any conversational text.\n\n{\n  \"signal\": \"Buy / Sell\",\n  \"strength\": \"Weak / Moderate / Strong\",\n  \"confidence\": [Insert integer between 0-100],\n  \"reason\": \"[Provide a concise explanation synthesizing the technical data and news sentiment]\",\n  \"risk_level\": \"Low / Medium / High\"\n}",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "17974b1f-d840-4a4b-a026-d89ab2db1b46",
      "name": "Score Calculator",
      "type": "n8n-nodes-base.code",
      "position": [
        1904,
        224
      ],
      "parameters": {
        "jsCode": "return items.map(item => {\n  const parsed = item.json.parsed || {};\n\n  // Extract values\n  const signal = parsed.signal;\n  const strength = parsed.strength;\n  const confidence = Number(parsed.confidence);\n  const reason = parsed.reason;\n  const risk_level = parsed.risk_level;\n\n  // Calculate score\n  const score =\n    (confidence > 80 ? 50 : 0) +\n    (strength === \"Strong\" ? 30 : 0) +\n    (risk_level === \"Low\" ? 20 : 0);\n\n  return {\n    json: {\n      signal,\n      strength,\n      confidence,\n      reason,\n      risk_level,\n      score\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "a8764ea6-bf49-4876-9859-1c237fc01742",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        512,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 320,
        "content": " ## Latest News Fetching \n\nFetches SENSEX news and extracts the latest post and pass it to ai agent for further processing.\nConsidering news to make decision is crucial because of sudden fluctuations in market will destroy the trades"
      },
      "typeVersion": 1
    },
    {
      "id": "c0b1ec3a-e183-4336-8a20-780f2d6df1ef",
      "name": "News Fetching",
      "type": "n8n-nodes-base.rssFeedRead",
      "position": [
        576,
        224
      ],
      "parameters": {
        "url": "https://news.google.com/rss/search?q=Sensex&hl=en-IN&gl=IN&ceid=IN:en",
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "2dfb93de-f099-4327-84a9-424bcaf064fc",
      "name": "Extrating latest news",
      "type": "n8n-nodes-base.limit",
      "position": [
        768,
        224
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "650a74c0-0827-432f-a0b2-57affa419b2a",
      "name": "Parse Important Data",
      "type": "n8n-nodes-base.set",
      "position": [
        320,
        224
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "5f2db6b6-34ae-4a1d-97f6-7b040724b1b7",
              "name": "trend",
              "type": "string",
              "value": "={{ $json.trend }}"
            },
            {
              "id": "71b6b2e2-0e81-4a97-9ed0-c09fc1ff20ef",
              "name": "momentum",
              "type": "number",
              "value": "={{ $json.momentum }}"
            },
            {
              "id": "10e7ef5c-4c46-4def-90a1-cc769dabb0c6",
              "name": "volatility",
              "type": "number",
              "value": "={{ $json.volatility }}"
            },
            {
              "id": "20c67e3b-a5f9-4c42-8efd-5ec888ecf503",
              "name": "price_change",
              "type": "number",
              "value": "={{ $json.priceChange }}"
            },
            {
              "id": "478943fe-3b9c-49bf-8395-2a34f90effe0",
              "name": "strength",
              "type": "string",
              "value": "={{ $json.momentum > 0 ? \"Bullish\" : \"Bearish\" }}"
            },
            {
              "id": "202385e3-ec56-4675-a8b3-fcf32da28a9c",
              "name": "volatility_level",
              "type": "string",
              "value": "={{ $json.volatility > 300 ? \"High\" : \"Low\" }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a4033ac2-dcde-4754-80ef-cb203507fbb2",
      "name": "Start",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -368,
        224
      ],
      "parameters": {},
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "e2cfd8ae-6dbc-41a5-8950-464d368d92ea",
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Fetching INDEX data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "AI agent output parsing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "News Fetching": {
      "main": [
        [
          {
            "node": "Extrating latest news",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Score Calculator": {
      "main": [
        [
          {
            "node": "Validating signal",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validating signal": {
      "main": [
        [
          {
            "node": "Log into sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetching INDEX data": {
      "main": [
        [
          {
            "node": "Code to gain insights",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Important Data": {
      "main": [
        [
          {
            "node": "News Fetching",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code to gain insights": {
      "main": [
        [
          {
            "node": "Parse Important Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extrating latest news": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI agent output parsing": {
      "main": [
        [
          {
            "node": "Score Calculator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  }
}