8
n8n 中文网amn8n.com

AI驱动的股票情绪分析器

高级

这是一个Crypto Trading, AI Summarization, Multimodal AI领域的自动化工作流,包含 23 个节点。主要使用 Code, Merge, Switch, Aggregate, HttpRequest 等节点。 基于 GPT-4、TwelveData 和 NewsAPI 分析的智能股票交易推荐

前置要求
  • 可能需要目标 API 的认证凭证
  • OpenAI API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "INwMUl3OdeqFBlkr",
  "meta": {
    "instanceId": "e56288a9b12ad2dc7c19cc4170f20f7abcacaad5fb3972dd882c9ce4f34e7668",
    "templateCredsSetupCompleted": true
  },
  "name": "AI驱动的股票情绪分析器",
  "tags": [],
  "nodes": [
    {
      "id": "e58d9c28-2f7f-4332-ab99-1431a2f1b68a",
      "name": "当收到聊天消息时",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -896,
        -64
      ],
      "webhookId": "1659fe58-d78d-40dc-92fa-76f3bf599df8",
      "parameters": {
        "options": {
          "responseMode": "responseNodes"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "d89ad9e2-7a74-44ff-b889-7cf8435f4481",
      "name": "4小时趋势",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -176,
        -256
      ],
      "parameters": {
        "url": "https://api.twelvedata.com/time_series",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpQueryAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "symbol",
              "value": "={{ $json.message.content }}"
            },
            {
              "name": "interval",
              "value": "4h"
            }
          ]
        }
      },
      "credentials": {
        "httpQueryAuth": {
          "id": "R3Dc1LmQu7W6Hpmy",
          "name": "Twelvedata API Key Auth"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "bbce42d7-e50e-4b9e-a168-a0f2f68af753",
      "name": "1天趋势",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -176,
        -64
      ],
      "parameters": {
        "url": "https://api.twelvedata.com/time_series",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpQueryAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "symbol",
              "value": "={{ $json.message.content }}"
            },
            {
              "name": "interval",
              "value": "1day"
            }
          ]
        }
      },
      "credentials": {
        "httpQueryAuth": {
          "id": "R3Dc1LmQu7W6Hpmy",
          "name": "Twelvedata API Key Auth"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "27d3fd72-380f-412e-b004-bcf101af280d",
      "name": "1周趋势",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -176,
        128
      ],
      "parameters": {
        "url": "https://api.twelvedata.com/time_series",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpQueryAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "symbol",
              "value": "={{ $json.message.content }}"
            },
            {
              "name": "interval",
              "value": "1week"
            }
          ]
        }
      },
      "credentials": {
        "httpQueryAuth": {
          "id": "R3Dc1LmQu7W6Hpmy",
          "name": "Twelvedata API Key Auth"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "0f22b55e-8c91-4694-9fde-8810d016fce6",
      "name": "获取新闻",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        768,
        -48
      ],
      "parameters": {
        "url": "https://newsapi.org/v2/everything",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpQueryAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ $json.message.content }}"
            }
          ]
        }
      },
      "credentials": {
        "httpQueryAuth": {
          "id": "gZ6BKf8OJSsy6Jph",
          "name": "NewsAPI API Key"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "344af493-dad1-48f9-bdbe-d7754ca9c47e",
      "name": "新闻情绪分析器",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1104,
        -48
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "GPT-4.1-MINI"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=You are a highly intelligent and accurate sentiment analyzer specializing in the financial markets. Analyze the sentiment of the provided text\n\n- Evaluate the immediate market reaction, recent news impact, and technical volatility.\n- Determine a sentiment category: \"Positive\", \"Neutral\", or \"Negative\".\n- Calculate a numerical score between -1 (extremely negative) and 1 (extremely positive).\n- Provide a concise rationale explaining the short-term sentiment (give a detailed response with appropriate headlines for major events.\n\nYour output must be exactly a JSON object. The value must be an object with three keys: \"category\", \"score\", and \"rationale\". Do not output any additional text.\n\nFor example, your output should look like:\n\n{\n  \"category\": \"Positive\",\n  \"score\": 0.7,\n  \"rationale\": \"...\"\n}\n\nNow, analyze the following text and produce your JSON output: {{ JSON.stringify($json.articles) }}"
            }
          ]
        },
        "jsonOutput": true
      },
      "credentials": {
        "openAiApi": {
          "id": "5n856jvI80lSEErZ",
          "name": "Klinsman OpenAI"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "fb4954a2-9203-4574-8332-2053ec97c3bb",
      "name": "聚合",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        320,
        -64
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "905c0187-c652-468e-9081-bff1cfde5b2f",
      "name": "合并",
      "type": "n8n-nodes-base.merge",
      "position": [
        144,
        -80
      ],
      "parameters": {
        "numberInputs": 3
      },
      "typeVersion": 3.2
    },
    {
      "id": "26bc4bf6-cae8-4478-8b8a-96033c5fb50d",
      "name": "合并1",
      "type": "n8n-nodes-base.merge",
      "position": [
        1392,
        -160
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "07b32114-e812-4020-97cf-e71eac41afea",
      "name": "聚合1",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        1568,
        -160
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "d7d5bb3f-8364-4cb7-9653-1ebf30d037c9",
      "name": "技术数据AI代理",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1808,
        -160
      ],
      "parameters": {
        "text": "=Data Sources\nTechnical Data (Price Action):\n{{ JSON.stringify($json.data[0]) }}\n\nSentiment Analysis (based on news):\nCategory: {{ $json.data[1].message.content.category }}\nScore: {{ $json.data[1].message.content.score }}\nRationale: {{ $json.data[1].message.content.rationale }}\n\n\"Score\" Assignment is between -1 (extremely negative) and 1 (extremely positive)\n\nUse the *Get Stock Sentiment* to additionally get the sentiment about the tool and base your results on the overall sentiment.\n\nAlso - use the *Chat Image for a Stock* tool to get the stock chart image and send it in the output",
        "options": {
          "systemMessage": "=You are a professional algorithmic trader with expertise in multi-timeframe analysis and sentiment integration. Your task is to analyze the provided technical and sentiment data to generate a single, actionable trade recommendation.\n\nAnalysis Framework\n1. Technical Analysis Priority\n\nPrimary Timeframe (4h): Entry/exit timing, immediate trend direction\nSecondary Timeframe (1d): Trend confirmation, key support/resistance levels\nTertiary Timeframe (1w): Overall market context, major trend direction\n\n2. Key Technical Indicators to Evaluate\n\nPrice action patterns (candlestick formations, support/resistance)\nTrend analysis (higher highs/lows, moving average relationships)\nMomentum indicators (RSI overbought/oversold conditions)\nVolume confirmation\nRisk/reward ratio (minimum 1:2 ratio required)\n\n3. Sentiment Integration Rules\n\nBullish sentiment + bullish technicals = Strong BUY signal\nBearish sentiment + bearish technicals = Strong SELL signal\nConflicting signals = HOLD (wait for alignment)\nExtreme sentiment readings = Consider contrarian approach\n\n4. Risk Management Requirements\n\nStop-loss must be placed beyond significant technical levels\nPosition sizing should account for volatility\nMaximum risk per trade: 2% of account\nTarget should provide minimum 1:2 risk/reward ratio\n\nDecision Process\n\nTrend Identification: Determine primary trend across all timeframes\nEntry Signal: Identify optimal entry based on 4h price action\nConfirmation: Validate with 1d trend and volume\nContext Check: Ensure alignment with 1w trend direction\nSentiment Filter: Apply sentiment data to strengthen or weaken signal\nRisk Calculation: Set stop-loss and target based on technical levels\n\nCritical Rules\nOnly recommend BUY/SELL when all timeframes align or when risk/reward is exceptional (>1:3)\nDefault to HOLD when signals are mixed or unclear\nAlways prioritize capital preservation over profit maximization\nEntry price must be actionable (near current market price)\nAll price levels must be justified by technical analysis\n\nOutput Format (STRICT - No additional text)\nTechnical Recommendation: [BUY|SELL|HOLD]\nEntry Price: [specific price level or N/A]\nStop-Loss: [specific price level or N/A]\nTarget Price: [specific price level or N/A]\nRisk/Reward Ratio: [ratio or N/A]\nConfidence Level: [High|Medium|Low|N/A]\nDo not include rationale. \n\nIn the output, only return 'N/A' if no info is known, should be the last resort."
        },
        "promptType": "define"
      },
      "typeVersion": 2.2
    },
    {
      "id": "09d9912b-cdbb-41ac-9f5b-2d92cadddb9e",
      "name": "OpenAI 聊天模型",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1568,
        64
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o",
          "cachedResultName": "gpt-4o"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "5n856jvI80lSEErZ",
          "name": "Klinsman OpenAI"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "36d679d0-5b6d-4c2e-873b-1c0822093a84",
      "name": "代码",
      "type": "n8n-nodes-base.code",
      "position": [
        1152,
        -256
      ],
      "parameters": {
        "jsCode": "// n8n JavaScript Code for Stock Data Transformation - With Price Trends\n// Comprehensive output including trend analysis for LLMs\n\nfunction calculateMovingAverage(prices, period) {\n  if (prices.length < period) return null;\n  const sum = prices.slice(0, period).reduce((a, b) => a + b, 0);\n  return Math.round((sum / period) * 100) / 100;\n}\n\nfunction calculateTrendDirection(prices) {\n  if (prices.length < 3) return 'INSUFFICIENT_DATA';\n  \n  const recent = prices.slice(0, 3);\n  const older = prices.slice(3, 6);\n  \n  const recentAvg = recent.reduce((a, b) => a + b, 0) / recent.length;\n  const olderAvg = older.length > 0 ? older.reduce((a, b) => a + b, 0) / older.length : recentAvg;\n  \n  const change = ((recentAvg - olderAvg) / olderAvg) * 100;\n  \n  if (change > 2) return 'STRONG_UPTREND';\n  if (change > 0.5) return 'UPTREND';\n  if (change < -2) return 'STRONG_DOWNTREND';\n  if (change < -0.5) return 'DOWNTREND';\n  return 'SIDEWAYS';\n}\n\nfunction identifySupportResistance(prices, highs, lows) {\n  const sortedPrices = [...prices].sort((a, b) => a - b);\n  const maxPrice = Math.max(...highs);\n  const minPrice = Math.min(...lows);\n  \n  return {\n    resistance: maxPrice,\n    support: minPrice,\n    median: sortedPrices[Math.floor(sortedPrices.length / 2)]\n  };\n}\n\nfunction transformStockDataForLLM(stockData) {\n  const result = {\n    symbol: '',\n    overview: {},\n    price_trends: {},\n    technical_analysis: {},\n    multi_timeframe: {},\n    llm_summary: ''\n  };\n  \n  let dailyData = null;\n  let weeklyData = null;\n  let intraDayData = null;\n  \n  // Separate data by timeframes\n  stockData.forEach(dataSet => {\n    const meta = dataSet.meta;\n    const interval = meta.interval;\n    \n    result.symbol = meta.symbol;\n    \n    if (interval === '1day') dailyData = dataSet;\n    if (interval === '1week') weeklyData = dataSet;\n    if (interval === '4h') intraDayData = dataSet;\n  });\n  \n  if (!dailyData || !dailyData.values.length) {\n    throw new Error('No daily data found');\n  }\n  \n  const dailyValues = dailyData.values;\n  const latest = dailyValues[0];\n  \n  // Basic overview\n  result.overview = {\n    symbol: result.symbol,\n    current_price: parseFloat(latest.close),\n    date: latest.datetime,\n    daily_change: dailyValues[1] ? parseFloat(latest.close) - parseFloat(dailyValues[1].close) : 0,\n    daily_change_percent: dailyValues[1] ? \n      Math.round(((parseFloat(latest.close) - parseFloat(dailyValues[1].close)) / parseFloat(dailyValues[1].close)) * 100 * 100) / 100 : 0,\n    volume: parseInt(latest.volume),\n    day_range: `$${latest.low} - $${latest.high}`\n  };\n  \n  // Extract price arrays for analysis\n  const closePrices = dailyValues.map(d => parseFloat(d.close));\n  const highPrices = dailyValues.map(d => parseFloat(d.high));\n  const lowPrices = dailyValues.map(d => parseFloat(d.low));\n  const volumes = dailyValues.map(d => parseInt(d.volume));\n  \n  // Price trends analysis\n  result.price_trends = {\n    trend_direction: calculateTrendDirection(closePrices),\n    moving_averages: {\n      ma_5: calculateMovingAverage(closePrices, 5),\n      ma_10: calculateMovingAverage(closePrices, 10),\n      ma_20: calculateMovingAverage(closePrices, 20)\n    },\n    price_position: {\n      above_ma5: closePrices[0] > calculateMovingAverage(closePrices, 5),\n      above_ma10: closePrices[0] > calculateMovingAverage(closePrices, 10),\n      above_ma20: closePrices[0] > calculateMovingAverage(closePrices, 20)\n    },\n    recent_performance: {\n      last_5_days: dailyValues.slice(0, 5).map(d => ({\n        date: d.datetime,\n        close: parseFloat(d.close),\n        change_from_prev: dailyValues.indexOf(d) < dailyValues.length - 1 ? \n          parseFloat(d.close) - parseFloat(dailyValues[dailyValues.indexOf(d) + 1].close) : 0,\n        volume: parseInt(d.volume)\n      })),\n      weekly_change: closePrices.length >= 7 ? \n        Math.round(((closePrices[0] - closePrices[6]) / closePrices[6]) * 100 * 100) / 100 : 0,\n      monthly_change: closePrices.length >= 30 ? \n        Math.round(((closePrices[0] - closePrices[29]) / closePrices[29]) * 100 * 100) / 100 : 0\n    }\n  };\n  \n  // Technical analysis\n  const supportResistance = identifySupportResistance(closePrices.slice(0, 30), highPrices.slice(0, 30), lowPrices.slice(0, 30));\n  const avgVolume = volumes.slice(0, 20).reduce((a, b) => a + b, 0) / Math.min(20, volumes.length);\n  \n  result.technical_analysis = {\n    support_resistance: supportResistance,\n    volume_analysis: {\n      current_volume: volumes[0],\n      average_volume_20d: Math.round(avgVolume),\n      volume_ratio: Math.round((volumes[0] / avgVolume) * 100) / 100,\n      volume_trend: volumes[0] > avgVolume * 1.5 ? 'HIGH' : volumes[0] < avgVolume * 0.5 ? 'LOW' : 'NORMAL'\n    },\n    volatility: {\n      daily_volatility: Math.round(((parseFloat(latest.high) - parseFloat(latest.low)) / parseFloat(latest.close)) * 100 * 100) / 100,\n      recent_volatility: Math.round((Math.max(...highPrices.slice(0, 10)) - Math.min(...lowPrices.slice(0, 10))) / closePrices[0] * 100 * 100) / 100\n    },\n    momentum_indicators: {\n      price_vs_support: Math.round(((closePrices[0] - supportResistance.support) / supportResistance.support) * 100 * 100) / 100,\n      price_vs_resistance: Math.round(((supportResistance.resistance - closePrices[0]) / closePrices[0]) * 100 * 100) / 100\n    }\n  };\n  \n  // Multi-timeframe analysis\n  result.multi_timeframe = {\n    daily: {\n      trend: result.price_trends.trend_direction,\n      last_close: closePrices[0]\n    }\n  };\n  \n  // Add weekly analysis if available\n  if (weeklyData && weeklyData.values.length > 1) {\n    const weeklyPrices = weeklyData.values.map(d => parseFloat(d.close));\n    result.multi_timeframe.weekly = {\n      trend: calculateTrendDirection(weeklyPrices),\n      weekly_change: Math.round(((weeklyPrices[0] - weeklyPrices[1]) / weeklyPrices[1]) * 100 * 100) / 100\n    };\n  }\n  \n  // Add intraday analysis if available\n  if (intraDayData && intraDayData.values.length > 1) {\n    const intradayPrices = intraDayData.values.map(d => parseFloat(d.close));\n    result.multi_timeframe.intraday = {\n      trend: calculateTrendDirection(intradayPrices),\n      recent_sessions: intraDayData.values.slice(0, 6).map(d => ({\n        datetime: d.datetime,\n        close: parseFloat(d.close)\n      }))\n    };\n  }\n  \n  // Generate comprehensive LLM summary\n  const ma5 = result.price_trends.moving_averages.ma_5;\n  const ma20 = result.price_trends.moving_averages.ma_20;\n  const trendStrength = result.price_trends.trend_direction;\n  const volumeStatus = result.technical_analysis.volume_analysis.volume_trend;\n  \n  result.llm_summary = `${result.symbol} Technical Analysis Summary:\n  \nCURRENT STATUS: Trading at $${result.overview.current_price} (${result.overview.daily_change >= 0 ? '+' : ''}${result.overview.daily_change_percent}% today)\n\nTREND ANALYSIS:\n- Overall Trend: ${trendStrength}\n- Price vs 5-day MA ($${ma5}): ${closePrices[0] > ma5 ? 'ABOVE' : 'BELOW'}\n- Price vs 20-day MA ($${ma20}): ${closePrices[0] > ma20 ? 'ABOVE' : 'BELOW'}\n- Weekly Performance: ${result.price_trends.recent_performance.weekly_change >= 0 ? '+' : ''}${result.price_trends.recent_performance.weekly_change}%\n\nTECHNICAL LEVELS:\n- Support: $${supportResistance.support}\n- Resistance: $${supportResistance.resistance}\n- Distance to Support: ${result.technical_analysis.momentum_indicators.price_vs_support}%\n\nVOLUME & MOMENTUM:\n- Volume: ${volumeStatus} (${result.technical_analysis.volume_analysis.volume_ratio}x average)\n- Daily Volatility: ${result.technical_analysis.volatility.daily_volatility}%\n\nKEY INSIGHT: Stock is ${trendStrength.toLowerCase()}, trading ${closePrices[0] > ma20 ? 'above' : 'below'} key moving averages with ${volumeStatus.toLowerCase()} volume activity.`;\n  \n  return result;\n}\n\n// Main execution for n8n\ntry {\n  if (!$json || !$json.data || !Array.isArray($json.data)) {\n    throw new Error('Expected input format: { \"data\": [...] }');\n  }\n  \n  const transformedData = transformStockDataForLLM($json.data);\n  \n  return {\n    json: transformedData\n  };\n  \n} catch (error) {\n  return {\n    json: {\n      error: \"Data transformation failed\",\n      details: error.message,\n      expected_format: \"{ data: [{ meta: {...}, values: [...] }] }\"\n    }\n  };\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "e1b272a7-2de0-47cd-a7ed-66adee5205f4",
      "name": "思考",
      "type": "@n8n/n8n-nodes-langchain.toolThink",
      "position": [
        1776,
        80
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "64480805-811b-4ab3-871e-13cee359226a",
      "name": "获取股票情绪",
      "type": "n8n-nodes-base.perplexityTool",
      "position": [
        1952,
        256
      ],
      "parameters": {
        "model": "sonar",
        "options": {},
        "messages": {
          "message": [
            {
              "content": "=Give me recent sentiment about this stock: {{ $('When chat message received').item.json.chatInput }}"
            }
          ]
        },
        "requestOptions": {}
      },
      "credentials": {
        "perplexityApi": {
          "id": "zHQXY3xprUQicrpf",
          "name": "Perplexity account 2"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "799885b8-c23b-44f3-a0d3-ac2a31051230",
      "name": "检查Twelvedata API是否成功",
      "type": "n8n-nodes-base.switch",
      "position": [
        480,
        -64
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Success",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "24b4ab24-3435-42a1-8a43-80c32f41b938",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('4h trend').item.json.status }}",
                    "rightValue": "ok"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Error",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "df95719f-22f3-4af3-9886-f3dfae4fde71",
                    "operator": {
                      "type": "string",
                      "operation": "notEquals"
                    },
                    "leftValue": "={{ $('4h trend').item.json.status }}",
                    "rightValue": "ok"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "8a313633-398e-454c-8f18-bb4b2a665fd1",
      "name": "获取股票图表图片",
      "type": "n8n-nodes-base.httpRequestTool",
      "position": [
        2368,
        192
      ],
      "parameters": {
        "url": "https://api.chart-img.com/v2/tradingview/advanced-chart/storage",
        "method": "POST",
        "options": {
          "response": {}
        },
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "height",
              "value": "300"
            },
            {
              "name": "theme",
              "value": "dark"
            },
            {
              "name": "interval",
              "value": "1W"
            },
            {
              "name": "style",
              "value": "baseline"
            },
            {
              "name": "symbol",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters4_Value', `set tradingview symbol EXCHANGE:SYMBOL. Example - NASDAQ:MSFT`, 'string') }}"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth",
        "toolDescription": "Get Chart Image for a Stock for the last 1 week"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "2vjana55vzbcPaWS",
          "name": "Chart Img API Key"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ced4c850-4182-451c-ba54-7c4bc00d40a3",
      "name": "返回错误",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        768,
        240
      ],
      "parameters": {
        "message": "=There was an error:  {{ $json.data[0].message }}",
        "options": {},
        "waitUserReply": false
      },
      "typeVersion": 1
    },
    {
      "id": "66370ec1-4c88-4e92-b10e-3302d11488cf",
      "name": "响应聊天",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        2384,
        -160
      ],
      "parameters": {
        "message": "={{ $json.output }}",
        "options": {},
        "waitUserReply": false
      },
      "typeVersion": 1
    },
    {
      "id": "c9c3f88f-8ed6-4413-a4db-d1861b575b84",
      "name": "转换为股票代码",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        -656,
        -64
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "GPT-4.1-MINI"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=I will give you a stock name, just return me the stock symbol. Strictly - Nothing else at all.\n\nStock Name: {{ $json.chatInput }}"
            }
          ]
        }
      },
      "credentials": {
        "openAiApi": {
          "id": "5n856jvI80lSEErZ",
          "name": "Klinsman OpenAI"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "a647a054-5cb3-4d80-8895-08da67ac6f4e",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -320,
        -416
      ],
      "parameters": {
        "color": 5,
        "width": 384,
        "height": 736,
        "content": "## 股票价格趋势"
      },
      "typeVersion": 1
    },
    {
      "id": "a9d0f2b6-a89c-4872-be86-418ce8d3bb49",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        672,
        -224
      ],
      "parameters": {
        "color": 4,
        "width": 288,
        "height": 352,
        "content": "## 新闻API"
      },
      "typeVersion": 1
    },
    {
      "id": "5d09c698-c92b-430e-ac93-664fcb47951b",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2192,
        16
      ],
      "parameters": {
        "color": 4,
        "width": 432,
        "height": 352,
        "content": "## 图表图片API"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "3ec964d2-dd25-48ab-a4df-eb5011e5873b",
  "connections": {
    "Code": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Think": {
      "ai_tool": [
        [
          {
            "node": "Technical Data AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Merge1": {
      "main": [
        [
          {
            "node": "Aggregate1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4h trend": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get News": {
      "main": [
        [
          {
            "node": "News Sentiment Analyzer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate": {
      "main": [
        [
          {
            "node": "Check Twelvedata API Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1day trend": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Aggregate1": {
      "main": [
        [
          {
            "node": "Technical Data AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1week trend": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Respond to Chat": {
      "main": [
        []
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Technical Data AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Get Stock Sentiment": {
      "ai_tool": [
        [
          {
            "node": "Technical Data AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Convert to Stock Symbol": {
      "main": [
        [
          {
            "node": "4h trend",
            "type": "main",
            "index": 0
          },
          {
            "node": "1day trend",
            "type": "main",
            "index": 0
          },
          {
            "node": "1week trend",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "News Sentiment Analyzer": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Technical Data AI Agent": {
      "main": [
        [
          {
            "node": "Respond to Chat",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Chart Image for Stock": {
      "ai_tool": [
        [
          {
            "node": "Technical Data AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Convert to Stock Symbol",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Twelvedata API Success": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get News",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond with Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

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

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

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

需要付费吗?

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

工作流信息
难度等级
高级
节点数量23
分类3
节点类型14
难度说明

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

作者
Jitesh Dugar

Jitesh Dugar

@jiteshdugar

AI Automation Specialist - OpenAI, CRM & Automation Expert with a solid understanding of various tools that include Zapier, Make, Zoho CRM, Hubspot, Google Sheets, Airtable, Pipedrive, Google Analytics, and more.

外部链接
在 n8n.io 查看

分享此工作流