8
n8n 中文网amn8n.com

情感分析机器人

高级

这是一个Crypto Trading, AI Summarization领域的自动化工作流,包含 18 个节点。主要使用 If, Code, HttpRequest, GoogleSheets, SplitInBatches 等节点。 使用Google Gemini和EODHD新闻API实现自动化股票情感分析

前置要求
  • 可能需要目标 API 的认证凭证
  • Google Sheets API 凭证
  • Google Gemini API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "meta": {
    "instanceId": "34d07950904120624117fd89d9d9b4f13d9fa466720a0972ac5aa843f9eb8cb8",
    "templateCredsSetupCompleted": true
  },
  "name": "情感分析机器人",
  "tags": [],
  "nodes": [
    {
      "id": "0d063cec-e739-48b6-9698-0ac586f147ad",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1040,
        1620
      ],
      "parameters": {
        "text": "=You are a stock sentiment analyzer. Your task is to evaluate news content for their potential impact on a specific stock.\n\nInput Format:\n    User input is in the following format:\n        Symbol: (The stock symbol also called ticker symbol)\n        title: (News headline that you have to analyze for sentiment of the given stock)\ncontent:(the content of the news to analyze)\nAnalysis Guidelines:\n    Evaluate how the news might affect the price of only the stock specified by the user in the input and generate a sentiment score between -1 and 1.\n    A score close to -1 indicates a strong negative impact, suggesting the news could significantly drive the stock price down.\n    A score near 0 represents a neutral impact, implying little to no effect on the stock price.\n    Conversely, a score close to 1 reflects a strong positive impact, likely driving the stock price up.\n    When generating the score, consider whether the news is surprising i.e., if it contains new information - or already priced in.\n    Explain in detail the rationale behind the score, highlighting why the news is positive, negative, or neutral for the given stock's price.\nOutput Format:\n    Return the result as JSON in the following format:\n\n        { symbol: (The stock symbol also called ticker symbol),\"sentiment_score\": (The sentiment score - float between -1 and 1), \"rationale\": (Your explanation for the score)}\nProvide the JSON output only. Do not include any other text.\n\nReal stock Symbol:\n{{$('loop_over_tickers').all()[0].json.ticker}}\n{{ $('join_articles_into_1').all()[0].json.fullString }}\n",
        "options": {},
        "promptType": "define"
      },
      "executeOnce": false,
      "typeVersion": 2
    },
    {
      "id": "a9bec4e8-b9df-4868-b6c3-072316fe1ed9",
      "name": "Google Gemini聊天模型1",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1028,
        1840
      ],
      "parameters": {
        "options": {
          "maxOutputTokens": 2048
        },
        "modelName": "models/gemini-2.0-flash"
      },
      "credentials": {
        "googlePalmApi": {
          "id": "ynRNNwts1fakC7X4",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "0b197810-0002-4f2c-8122-1db9a6a81558",
      "name": "从EODHD获取文章",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        160,
        1520
      ],
      "parameters": {
        "url": "https://eodhd.com/api/news",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpQueryAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "s",
              "value": "={{ $json.ticker }}"
            },
            {
              "name": "offset",
              "value": "0"
            },
            {
              "name": "limit",
              "value": "10"
            },
            {
              "name": "fmt",
              "value": "json"
            }
          ]
        }
      },
      "credentials": {
        "httpQueryAuth": {
          "id": "p1dJbEo98pH5SVih",
          "name": "Query Auth account"
        }
      },
      "executeOnce": false,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "392f7ccd-aba3-4911-859a-556535f45eea",
      "name": "循环处理股票代码",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -200,
        1640
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "6e5b9817-b6ec-4c0a-98fd-b41340ab6230",
      "name": "从表格读取股票代码",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -420,
        1640
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 470128021,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1tQDBVDqn5v08GOsjupjV8o3Jzqd4-fKoSoGhWLEOTww/edit#gid=470128021",
          "cachedResultName": "stocks"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1tQDBVDqn5v08GOsjupjV8o3Jzqd4-fKoSoGhWLEOTww",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1tQDBVDqn5v08GOsjupjV8o3Jzqd4-fKoSoGhWLEOTww/edit?usp=drivesdk",
          "cachedResultName": "Stock Sentiment"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "Bpltco7Lqc7P73Qp",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "e68be220-53b9-4b3d-a543-98a916382d42",
      "name": "如果股票代码无效",
      "type": "n8n-nodes-base.if",
      "position": [
        380,
        1520
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "770d6272-1cde-44d7-9e15-fe5d7c28ba36",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $ifEmpty($input.all().toJsonString(),'True') }}",
              "rightValue": "True"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "bfc2cc77-5fc2-41ae-9e2a-22fed368c852",
      "name": "在Google表格中写入无效股票代码",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        600,
        1420
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{$today}}\n",
            "stock": "={{ $('loop_over_tickers').item.json.ticker }}",
            "sentimentScore": "Invaild Ticker"
          },
          "schema": [
            {
              "id": "date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "stock",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "stock",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "sentimentScore",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "sentimentScore",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "rational",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "rational",
              "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/1tQDBVDqn5v08GOsjupjV8o3Jzqd4-fKoSoGhWLEOTww/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1tQDBVDqn5v08GOsjupjV8o3Jzqd4-fKoSoGhWLEOTww",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1tQDBVDqn5v08GOsjupjV8o3Jzqd4-fKoSoGhWLEOTww/edit?usp=drivesdk",
          "cachedResultName": "Stock Sentiment"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "Bpltco7Lqc7P73Qp",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "81a16d3a-cdc4-4ad3-8769-b858a999f0ed",
      "name": "将文章合并为一个",
      "type": "n8n-nodes-base.code",
      "position": [
        600,
        1620
      ],
      "parameters": {
        "jsCode": "// --- n8n Code Node (JavaScript) ---\n// This script takes an array of objects and converts it into a single JSON string.\n\n// 1. Extract the JSON data from all incoming n8n items.\nconst allArticlesArray = items.map(item => item.json);\n\n// 2. Convert the entire array into a single JSON string.\n// The 'null, 2' arguments format the string with indentation for readability.\nconst combinedString = JSON.stringify(allArticlesArray, null, 2);\n\n// 3. Return the result as a single item.\n// The output will have one property, 'fullString', containing the combined text.\nreturn [\n  {\n    json: {\n      fullString: combinedString\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "9c05ff30-59c7-45e0-8079-e3a0f01547bd",
      "name": "将输出格式化为JSON",
      "type": "n8n-nodes-base.code",
      "onError": "continueRegularOutput",
      "position": [
        1600,
        1520
      ],
      "parameters": {
        "jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n// The input is an array of items. We'll work with the first item.\n\n\n// Access the string value from the 'output' field in the input JSON.\nconst rawStringWithMarkdown = item.json.output;\nconsole.log(item.json.output)\n// The JSON we want is nested inside a markdown code block (```json ... ```).\n// We need to extract just the JSON part.\n\n// Find the first occurrence of '{' to locate the start of the JSON object.\nconst jsonStartIndex = rawStringWithMarkdown.indexOf('{');\n\n// Find the last occurrence of '}' to locate the end of the JSON object.\nconst jsonEndIndex = rawStringWithMarkdown.lastIndexOf('}');\n\n// Slice the string from the start to the end to get only the clean JSON string.\n// We add +1 to jsonEndIndex because substring's second argument is exclusive.\nconst cleanJsonString = rawStringWithMarkdown.substring(jsonStartIndex, jsonEndIndex + 1);\n\n// Parse the cleaned string into a proper, usable JSON object.\nconst parsedJson = JSON.parse(cleanJsonString);\n\n// Return the parsed JSON object. The keys (symbol, sentiment_score, etc.)\n// will become individual fields in the n8n output for the next node to use.\nreturn parsedJson;}\n\n"
      },
      "executeOnce": false,
      "retryOnFail": false,
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "c5817f1f-8e79-4c13-9807-fd5176c2773f",
      "name": "如果格式化成功",
      "type": "n8n-nodes-base.if",
      "position": [
        1840,
        1620
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "770d6272-1cde-44d7-9e15-fe5d7c28ba36",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.error }}",
              "rightValue": "True"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "0dc93919-fb1a-46df-b316-1044f11cd791",
      "name": "将情感分析写入表格",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2360,
        1740
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{$today}}\n",
            "stock": "={{$('loop_over_tickers').all()[0].json.ticker.replace(\".US\",\"\")}}",
            "rational": "={{ $json.rationale }}",
            "sentimentScore": "={{ $json.sentiment_score }}"
          },
          "schema": [
            {
              "id": "date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "stock",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "stock",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "sentimentScore",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "sentimentScore",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "rational",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "rational",
              "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/1tQDBVDqn5v08GOsjupjV8o3Jzqd4-fKoSoGhWLEOTww/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1tQDBVDqn5v08GOsjupjV8o3Jzqd4-fKoSoGhWLEOTww",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1tQDBVDqn5v08GOsjupjV8o3Jzqd4-fKoSoGhWLEOTww/edit?usp=drivesdk",
          "cachedResultName": "Stock Sentiment"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "Bpltco7Lqc7P73Qp",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "3cbf7b55-50ae-4d1c-8f9e-56941441ef00",
      "name": "计划触发器",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -640,
        1640
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 16
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ce8d9b54-2026-4faa-9ee1-c261170c8426",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -620,
        660
      ],
      "parameters": {
        "width": 480,
        "height": 440,
        "content": "# 工作流概述"
      },
      "typeVersion": 1
    },
    {
      "id": "efaee1f9-e57a-4640-a1d6-eb5bc5f341af",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -680,
        1200
      ],
      "parameters": {
        "color": 4,
        "width": 640,
        "height": 640,
        "content": "# 1. 每日触发和股票代码检索"
      },
      "typeVersion": 1
    },
    {
      "id": "eaca666d-2830-4e98-bfe4-44c15d452939",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        80,
        1020
      ],
      "parameters": {
        "color": 5,
        "width": 680,
        "height": 940,
        "content": "# 2. 新闻文章检索和验证"
      },
      "typeVersion": 1
    },
    {
      "id": "92a8b9e8-cdca-4584-938f-b478b8136867",
      "name": "便签3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        1180
      ],
      "parameters": {
        "color": 6,
        "width": 500,
        "height": 800,
        "content": "# 3. 使用AI进行情感分析"
      },
      "typeVersion": 1
    },
    {
      "id": "aa4c0dfb-0e02-4f74-b908-27b6b81bbef1",
      "name": "便签4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1500,
        980
      ],
      "parameters": {
        "color": 2,
        "width": 560,
        "height": 860,
        "content": "# 4. 输出格式化和错误处理"
      },
      "typeVersion": 1
    },
    {
      "id": "cd441252-7867-40e4-9fb9-aa1e6fd53fb9",
      "name": "便签5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2160,
        1300
      ],
      "parameters": {
        "color": 3,
        "width": 520,
        "height": 600,
        "content": "# 5. 存储结果"
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "pinData": {},
  "settings": {
    "timezone": "Asia/Jerusalem",
    "callerPolicy": "workflowsFromSameOwner",
    "executionOrder": "v1"
  },
  "versionId": "28688d53-2f5a-4653-bd71-bca83d087647",
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "format_output_as_json",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Read_tickers_from_Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "loop_over_tickers": {
      "main": [
        [],
        [
          {
            "node": "Get articles from EODHD",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If_ticker_not_valid": {
      "main": [
        [
          {
            "node": "Write_in_google_sheets_invalid_ticker",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "join_articles_into_1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "if_format_succesful": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "write_sentiment_to_sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "join_articles_into_1": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "format_output_as_json": {
      "main": [
        [
          {
            "node": "if_format_succesful",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get articles from EODHD": {
      "main": [
        [
          {
            "node": "If_ticker_not_valid",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read_tickers_from_Sheet": {
      "main": [
        [
          {
            "node": "loop_over_tickers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "write_sentiment_to_sheets": {
      "main": [
        [
          {
            "node": "loop_over_tickers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

高级 - 加密货币交易, AI 摘要总结

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量18
分类2
节点类型9
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

作者
Raz Hadas

Raz Hadas

@raz-hadas

Co-founder of buildmyflow, on a mission to create powerful and easy-to-use n8n automation templates. With a background in AI and a passion for social impact as the co-founder of TovTech, I'm dedicated to building a community-focused resource for free and premium workflows that save you time and unlock new possibilities. Let's automate together! https://www.linkedin.com/in/raz-hadas/

外部链接
在 n8n.io 查看

分享此工作流