{
  "id": "i8yq9z68frpqF37H",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Commodity Sentiment Tracker",
  "tags": [],
  "nodes": [
    {
      "id": "5906322d-e84b-4fd5-9cb2-956e6c1eb9b2",
      "name": "Energy",
      "type": "n8n-nodes-base.rssFeedRead",
      "position": [
        -64,
        -336
      ],
      "parameters": {
        "url": "https://oilprice.com/rss/main",
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "962f4eca-7868-44e8-8aba-290128f2fbeb",
      "name": "Invezz",
      "type": "n8n-nodes-base.rssFeedRead",
      "position": [
        -64,
        -144
      ],
      "parameters": {
        "url": "https://invezz.com/news/commodities/feed/",
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "7aab7b0c-6b31-4692-8c70-e5069dbade86",
      "name": "Normalize Article",
      "type": "n8n-nodes-base.set",
      "position": [
        832,
        -240
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={\n  \"title\": \"{{ $json.title }}\",\n  \"link\": \"{{ $json.link }}\",\n  \"pubDate\": \"{{ $json.pubDate }}\",\n  \"content\": \"{{ $json.content.replace(/\"/g, '\\\\\"') }}\",\n  \"contentSnippet\": \"{{ $json.contentSnippet.replace(/\"/g, '\\\\\"') }}\",\n  \"source\": \"{{ $json.link.includes('oilprice') ? 'OilPrice' : 'Invezz' }}\"\n}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "35435dc3-194f-46fa-a437-4340a0494bbd",
      "name": "AI Sentiment Classification",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1056,
        -240
      ],
      "parameters": {
        "text": "=You are a financial news analyst.\n\nAnalyze this commodity-related news.\n\nReturn ONLY valid JSON:\n\n{\n \"sentiment\": \"Positive | Negative | Neutral\",\n \"confidence\": number (0-100),\n \"commodity\": \"Gold | Oil | Natural Gas | Wheat | etc\",\n \"impact_level\": \"High | Medium | Low\",\n \"summary\": \"One-line summary\"\n}\n\nNews Content:\n{{ $json.content }}\nContent Snippet:\n{{ $json.contentSnippet }}",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "56128c3c-9671-4d91-9d03-54b9e8b05c89",
      "name": "Groq Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGroq",
      "position": [
        1128,
        -16
      ],
      "parameters": {
        "model": "openai/gpt-oss-120b",
        "options": {}
      },
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3d7b6cd1-ebf3-4a05-9313-21a48ebd4393",
      "name": "No Operation, do nothing",
      "type": "n8n-nodes-base.noOp",
      "position": [
        2752,
        -144
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "d2374c84-3ba8-48db-9dc5-2f9c3966a489",
      "name": "Find Latest News",
      "type": "n8n-nodes-base.sort",
      "position": [
        160,
        -144
      ],
      "parameters": {
        "options": {
          "disableDotNotation": true
        },
        "sortFieldsUi": {
          "sortField": [
            {
              "fieldName": "pubDate"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "743a1a06-67e8-47c5-9217-4c124cdc2fdd",
      "name": "Latest news related to Energy",
      "type": "n8n-nodes-base.sort",
      "position": [
        160,
        -336
      ],
      "parameters": {
        "options": {},
        "sortFieldsUi": {
          "sortField": [
            {
              "order": "descending",
              "fieldName": "pubDate"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "79057f58-37e7-40d0-b024-75ee762193d9",
      "name": "Top 5 News",
      "type": "n8n-nodes-base.limit",
      "position": [
        384,
        -144
      ],
      "parameters": {
        "maxItems": 5
      },
      "typeVersion": 1
    },
    {
      "id": "6fc5c37c-42ec-4fe7-bd5d-4e7cfb783e09",
      "name": "Top 5 news of Enery",
      "type": "n8n-nodes-base.limit",
      "position": [
        384,
        -336
      ],
      "parameters": {
        "maxItems": 5
      },
      "typeVersion": 1
    },
    {
      "id": "59d0f38c-8176-4a87-a410-7bec03f64f20",
      "name": "Put together Both news",
      "type": "n8n-nodes-base.merge",
      "position": [
        608,
        -240
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "joinMode": "keepEverything",
        "fieldsToMatchString": "creator"
      },
      "typeVersion": 3.2
    },
    {
      "id": "8ddba567-b2d1-417b-8e90-22e0e7eff464",
      "name": "Format AI Output",
      "type": "n8n-nodes-base.code",
      "position": [
        1408,
        -240
      ],
      "parameters": {
        "jsCode": "return items.map(item => {\n  return {\n    json: JSON.parse(item.json.output)\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "a59bf2bb-e5fe-41be-b308-9de376eff74e",
      "name": "Store in Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1632,
        -240
      ],
      "parameters": {
        "columns": {
          "value": {
            "URL": "={{ $('Normalize Article').item.json.link }}",
            "Title": "={{ $('Normalize Article').item.json.title }}",
            "Impact": "={{ $json.impact_level }}",
            "Source": "={{ $('Normalize Article').item.json.source }}",
            "Summary": "={{ $json.summary }}",
            "Commodity": "={{ $json.commodity }}",
            "Sentiment": "={{ $json.sentiment }}",
            "Timestamp": "={{ $now }}",
            "Confidence": "={{ $json.confidence }}"
          },
          "schema": [
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Source",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Source",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Commodity",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Commodity",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Sentiment",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Sentiment",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Confidence",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Confidence",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Impact",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Impact",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Summary",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Summary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "URL",
              "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/14X62r_2c4Ze4tfPAY_QX9DvbhVnM67_mA1VWBlAmNhY/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "14X62r_2c4Ze4tfPAY_QX9DvbhVnM67_mA1VWBlAmNhY",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/14X62r_2c4Ze4tfPAY_QX9DvbhVnM67_mA1VWBlAmNhY/edit?usp=drivesdk",
          "cachedResultName": "CommoditySentiment"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "c85f8e9f-e985-4e88-819c-06a871f4923d",
      "name": "Map Sentiment Score",
      "type": "n8n-nodes-base.code",
      "position": [
        1856,
        -240
      ],
      "parameters": {
        "jsCode": "const sentimentMap = {\n  \"Positive\": 1,\n  \"Neutral\": 0,\n  \"Negative\": -1\n};\n\nreturn items.map(item => {\n  return {\n    json: {\n      ...item.json,\n      sentiment_score: sentimentMap[item.json.Sentiment] || 0\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "6165b8e6-acb3-42cf-899e-addaa2e631f2",
      "name": "Aggregate by Commodity",
      "type": "n8n-nodes-base.code",
      "position": [
        2080,
        -240
      ],
      "parameters": {
        "jsCode": "const grouped = {};\n\nitems.forEach(item => {\n  const c = item.json.Commodity;\n\n  if (!grouped[c]) {\n    grouped[c] = {\n      scores: [],\n      latest: item.json\n    };\n  }\n\n  grouped[c].scores.push(\n    item.json.Sentiment === \"Positive\" ? 1 :\n    item.json.Sentiment === \"Negative\" ? -1 : 0\n  );\n});\n\nconst result = [];\n\nfor (const commodity in grouped) {\n  const data = grouped[commodity];\n  const avg = data.scores.reduce((a,b)=>a+b,0)/data.scores.length;\n\n  result.push({\n    json: {\n      commodity,\n      avg_sentiment: avg,\n      articles: data.scores.length,\n      summary: data.latest.Summary,\n      link: data.latest.URL\n    }\n  });\n}\n\nreturn result;"
      },
      "typeVersion": 2
    },
    {
      "id": "9b8e3bc2-4cc3-45aa-a3eb-759e091a1726",
      "name": "Prepare Slack Message",
      "type": "n8n-nodes-base.set",
      "position": [
        2304,
        -240
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "30023a58-fa51-473d-aebf-45f6256bb991",
              "name": "text",
              "type": "string",
              "value": "={{\n` *Commodity Sentiment Alert*\n\n*${$json.commodity}*\n\n Score: *${$json.avg_sentiment.toFixed(2)}*\n Articles: ${$json.articles}\n\n${\n  $json.avg_sentiment > 0.5 \n    ? \" *Strong Bullish*\"\n    : $json.avg_sentiment > 0 \n      ? \" *Bullish*\"\n      : $json.avg_sentiment < -0.5 \n        ? \" *Strong Bearish*\"\n        : $json.avg_sentiment < 0 \n          ? \" *Bearish*\"\n          : \" *Neutral*\"\n}\n\n-----------------\n ${$json.summary}\n ${$json.link}`\n}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f05bede8-a9da-4fb8-b4d9-f315cc1c7320",
      "name": "Checks if need to send alert",
      "type": "n8n-nodes-base.if",
      "position": [
        2528,
        -240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "8fb20299-4236-4b98-89b3-96377be6f757",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $('Aggregate by Commodity').item.json.avg_sentiment }}",
              "rightValue": 0.3
            },
            {
              "id": "88e86781-8341-4ae7-953e-c95123075a77",
              "operator": {
                "type": "number",
                "operation": "lt"
              },
              "leftValue": "={{ $('Aggregate by Commodity').item.json.avg_sentiment }}",
              "rightValue": -0.3
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "dfc9245e-44ae-49e1-b940-8aac9ab46c0d",
      "name": "Send Slack Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        2752,
        -336
      ],
      "parameters": {
        "text": "={{ $json.text }}",
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "U0ANV4YLNTV",
          "cachedResultName": ""
        },
        "select": "user",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "ff4d73b8-550a-4ae8-bfc0-56f03493b284",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -992,
        -1072
      ],
      "parameters": {
        "width": 592,
        "height": 608,
        "content": "## Commodity Sentiment Tracker\n\nThis workflow automatically tracks commodity-related news sentiment and alerts users about major trend shifts.\n\nIt starts by pulling the latest news from RSS feeds. Each article is processed using AI to classify sentiment (Positive, Neutral, Negative), assign confidence, and extract structured insights like commodity type and impact level.\n\nThe data is stored in Google Sheets, ensuring persistence and enabling historical tracking. A deduplication step prevents duplicate articles using URL matching.\n\nNext, sentiment scores are calculated and aggregated per commodity to identify overall trends. When significant positive or negative sentiment shifts are detected, the workflow generates a formatted alert message.\n\nFinally, alerts are sent to Slack with key details including commodity, trend direction, and latest news summary.\n\n## Setup Steps:\nAdd your RSS feed URL(s)\nConfigure OpenAI credentials\nConnect Google Sheets (with proper columns)\nSet Slack Webhook URL\nAdjust sentiment thresholds if needed\n\nThis workflow helps traders and analysts stay ahead of market sentiment changes in real time."
      },
      "typeVersion": 1
    },
    {
      "id": "5d00be9f-e654-4db5-9217-a778b9040581",
      "name": "Executes Everyday at 10AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -288,
        -240
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 10
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "5c391a0d-4a9d-4782-a0da-904958cf94df",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -336,
        -496
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 624,
        "content": "## Triggers & RSS Feeds\n\nHandles workflow initiation and fetches news from multiple RSS sources to ensure continuous data input."
      },
      "typeVersion": 1
    },
    {
      "id": "ab3bd9d0-de4a-48a5-8234-00b5973d1326",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        112,
        -496
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 624,
        "content": "## Data Filtering & Preparation\n\nSorts, limits, and merges RSS data to keep only relevant and recent articles for processing."
      },
      "typeVersion": 1
    },
    {
      "id": "12964d4e-6b14-45e5-978b-06290c2c1832",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        800,
        -496
      ],
      "parameters": {
        "color": 7,
        "width": 976,
        "height": 624,
        "content": "## AI Processing & Storage\n\nPrepares AI input, performs sentiment analysis, formats the response, and stores structured data in Google Sheets with deduplication."
      },
      "typeVersion": 1
    },
    {
      "id": "1c49ec77-3404-4a96-9da2-15edec03e139",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1792,
        -496
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 624,
        "content": "## Sentiment Scoring & Aggregation\n\nConverts sentiment into numeric scores and calculates average sentiment per commodity."
      },
      "typeVersion": 1
    },
    {
      "id": "4efa4699-0471-420c-9c88-b4fedec50410",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2256,
        -496
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 624,
        "content": "## Alert Generation (Slack)\n\nFormats and sends alerts to Slack with commodity trend and latest summarized news."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "c410219b-5cf7-4818-80c3-98a06a0db589",
  "connections": {
    "Energy": {
      "main": [
        [
          {
            "node": "Latest news related to Energy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Invezz": {
      "main": [
        [
          {
            "node": "Find Latest News",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Top 5 News": {
      "main": [
        [
          {
            "node": "Put together Both news",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Groq Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Sentiment Classification",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Find Latest News": {
      "main": [
        [
          {
            "node": "Top 5 News",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format AI Output": {
      "main": [
        [
          {
            "node": "Store in Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Article": {
      "main": [
        [
          {
            "node": "AI Sentiment Classification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map Sentiment Score": {
      "main": [
        [
          {
            "node": "Aggregate by Commodity",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Top 5 news of Enery": {
      "main": [
        [
          {
            "node": "Put together Both news",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Slack Message": {
      "main": [
        [
          {
            "node": "Checks if need to send alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate by Commodity": {
      "main": [
        [
          {
            "node": "Prepare Slack Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Put together Both news": {
      "main": [
        [
          {
            "node": "Normalize Article",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store in Google Sheets": {
      "main": [
        [
          {
            "node": "Map Sentiment Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Executes Everyday at 10AM": {
      "main": [
        [
          {
            "node": "Energy",
            "type": "main",
            "index": 0
          },
          {
            "node": "Invezz",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Sentiment Classification": {
      "main": [
        [
          {
            "node": "Format AI Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Checks if need to send alert": {
      "main": [
        [
          {
            "node": "Send Slack Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Operation, do nothing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Latest news related to Energy": {
      "main": [
        [
          {
            "node": "Top 5 news of Enery",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}