网格工作流测试版


创建日期: 2025-10-17 17:35:19 最后修改: 2025-10-24 10:07:35
复制: 0 点击次数: 22
avatar of ianzeng123 ianzeng123
1
关注
149
关注者
策略源码
{"type":"n8n","content":"{\"workflowData\":{\"nodes\":[{\"parameters\":{\"notice\":\"\",\"exchange\":0,\"symbol\":{\"__rl\":true,\"value\":\"={{$vars.product_code}}\",\"mode\":\"id\"},\"period\":60,\"limit\":500,\"rule\":{\"interval\":[{\"field\":\"seconds\",\"secondsInterval\":60}]}},\"type\":\"n8n-nodes-base.klineCloseTrigger\",\"typeVersion\":1,\"position\":[-896,160],\"id\":\"85a94b84-f0db-4aaf-9d90-2461f6aadc1f\",\"name\":\"K线收盘触发器1\"},{\"parameters\":{\"model\":{\"__rl\":true,\"value\":\"qwen3-max-preview\",\"mode\":\"list\",\"cachedResultName\":\"qwen3-max-preview\"}},\"type\":\"n8n-nodes-base.lmOpenAi\",\"typeVersion\":1,\"position\":[880,448],\"id\":\"54b12969-7093-4069-bd48-2f1b659aee03\",\"name\":\"OpenAI 模型1\",\"credentials\":{\"openAiApi\":{\"id\":\"f3da26db-84a0-4a0b-8e63-6bcc89a187e7\",\"name\":\"ali\"}}},{\"parameters\":{\"mode\":\"rules\",\"rules\":{\"values\":[{\"conditions\":{\"options\":{\"caseSensitive\":true,\"leftValue\":\"\",\"typeValidation\":\"strict\",\"version\":2},\"conditions\":[{\"leftValue\":\"={{ $json.aiTrigger.shouldTrigger }}\",\"rightValue\":\"false\",\"operator\":{\"type\":\"boolean\",\"operation\":\"false\",\"singleValue\":true},\"id\":\"0029cdc5-fc22-425f-82aa-bea90f32f866\"}],\"combinator\":\"and\"},\"renameOutput\":false},{\"conditions\":{\"options\":{\"caseSensitive\":true,\"leftValue\":\"\",\"typeValidation\":\"strict\",\"version\":2},\"conditions\":[{\"id\":\"64d4c904-c8d4-439b-a890-335ae87605ac\",\"leftValue\":\"={{ $json.aiTrigger.shouldTrigger }}\",\"rightValue\":\"\",\"operator\":{\"type\":\"boolean\",\"operation\":\"true\",\"singleValue\":true}}],\"combinator\":\"and\"},\"renameOutput\":false}]},\"looseTypeValidation\":false,\"options\":{}},\"type\":\"n8n-nodes-base.switch\",\"typeVersion\":3.2,\"position\":[0,160],\"id\":\"6db362b4-1c86-4df9-894a-756dc33d873c\",\"name\":\"分支\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"let grid = _G('grid');\\nlet initPrice = _G('initPrice');\\nlet initEquity = _G('initEquity');\\n\\n// ========== 从 n8n 变量读取配置参数 ==========\\nlet maxPositions = $vars.maxPositions;      // 最大档位数\\nlet stepPercent = $vars.stepPercent;        // 网格步长\\nlet volatilityThreshold = 0.02; // 波动率阈值(默认2%)\\nlet volatilityPeriod = 20; // 波动率计算周期(默认20根K线)\\n\\nexchange.SetContractType($vars.product_code)\\n\\n// ========== 波动率检查函数 ==========\\nfunction checkVolatility() {\\n  // 获取历史K线数据\\n  let records = exchange.GetRecords();\\n  if (!records || records.length < volatilityPeriod) {\\n    Log('K线数据不足,无法计算波动率');\\n    return { isHigh: false, value: 0 };\\n  }\\n  \\n  // 计算最近N根K线的价格波动率\\n  let prices = [];\\n  for (let i = records.length - volatilityPeriod; i < records.length; i++) {\\n    prices.push(records[i].Close);\\n  }\\n  \\n  // 计算平均价格\\n  let avgPrice = prices.reduce((a, b) => a + b, 0) / prices.length;\\n  \\n  // 计算标准差\\n  let squareDiffs = prices.map(price => Math.pow(price - avgPrice, 2));\\n  let avgSquareDiff = squareDiffs.reduce((a, b) => a + b, 0) / squareDiffs.length;\\n  let stdDev = Math.sqrt(avgSquareDiff);\\n  \\n  // 计算波动率 (标准差/平均价格)\\n  let volatility = stdDev / avgPrice;\\n  \\n  Log('当前波动率:', (volatility * 100).toFixed(2) + '%', \\n      '阈值:', (volatilityThreshold * 100).toFixed(2) + '%');\\n  \\n  return {\\n    isHigh: volatility > volatilityThreshold,\\n    value: volatility\\n  };\\n}\\n\\n// ========== 初始化前先检查波动率 ==========\\nif (!grid || Object.keys(grid).length === 0) {\\n  \\n  // 检查波动率\\n  let volatilityCheck = checkVolatility();\\n  \\n  if (volatilityCheck.isHigh) {\\n    Log('⚠️ 当前市场波动率过高:', (volatilityCheck.value * 100).toFixed(2) + '%');\\n    Log('等待市场平稳后再初始化网格...');\\n    return { \\n      status: 'waiting',\\n      reason: 'high_volatility',\\n      volatility: volatilityCheck.value\\n    };\\n  }\\n  \\n  Log('✓ 波动率检查通过,开始初始化网格');\\n  \\n  // ========== 获取初始权益 ==========\\n  if (!initEquity) {\\n    let equity = exchange.GetAccount();\\n    if (equity) {\\n      initEquity = equity.Equity;\\n      _G('initEquity', initEquity);\\n      Log('使用当前市场权益作为初始权益:', initEquity);\\n    } else {\\n      Log('获取市场账户失败');\\n      return null;\\n    }\\n  }\\n\\n  // ========== 获取初始价格 ==========\\n  if (!initPrice) {\\n    let ticker = exchange.GetTicker();\\n    if (ticker) {\\n      initPrice = ticker.Last;\\n      _G('initPrice', initPrice);\\n      Log('使用当前市场价格作为初始价格:', initPrice);\\n    } else {\\n      Log('获取市场价格失败');\\n      return null;\\n    }\\n  }\\n\\n  // ========== 初始化网格 ==========\\n  grid = {\\n    // ========== 配置参数 ==========\\n    stepPercent: stepPercent,        // 网格步长\\n    maxPositions: maxPositions,      // 最大档位数\\n    \\n    // ========== 网格数据 ==========\\n    longOpenPrices: [],    // 目标多仓开仓价格数组\\n    longClosePrices: [],   // 目标多仓平仓价格数组\\n    longPositions: [],     // 多仓持仓状态数组\\n    shortOpenPrices: [],   // 目标空仓开仓价格数组\\n    shortClosePrices: [],  // 目标空仓平仓价格数组\\n    shortPositions: []     // 空仓持仓状态数组\\n  };\\n  \\n  // 初始化多仓网格(价格下跌时开多)\\n  for (let i = 1; i <= maxPositions; i++) {\\n    grid.longOpenPrices.push(initPrice * (1 - stepPercent * i));\\n    grid.longClosePrices.push(initPrice * (1 - stepPercent * (i - 1)));\\n    grid.longPositions.push({\\n      isOpen: false,\\n      openTime: null,\\n      openPrice: null\\n    });\\n  }\\n  \\n  // 初始化空仓网格(价格上涨时开空)\\n  for (let i = 1; i <= maxPositions; i++) {\\n    grid.shortOpenPrices.push(initPrice * (1 + stepPercent * i));\\n    grid.shortClosePrices.push(initPrice * (1 + stepPercent * (i - 1)));\\n    grid.shortPositions.push({\\n      isOpen: false,\\n      openTime: null,\\n      openPrice: null\\n    });\\n  }\\n  \\n  _G('grid', grid);\\n  Log('========== 网格初始化完成 ==========');\\n  Log('初始价格:', initPrice);\\n  Log('初始权益:', initEquity);\\n  Log('网格步长:', (stepPercent * 100) + '%');\\n  Log('最大档位:', maxPositions);\\n  Log('当前波动率:', (volatilityCheck.value * 100).toFixed(2) + '%');\\n  Log('多仓网格范围:', grid.longOpenPrices[0].toFixed(2), '-', grid.longOpenPrices[maxPositions-1].toFixed(2));\\n  Log('空仓网格范围:', grid.shortOpenPrices[0].toFixed(2), '-', grid.shortOpenPrices[maxPositions-1].toFixed(2));\\n  Log('===================================');\\n} \\n\\nreturn {};\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[-672,160],\"id\":\"8a6ae0dc-edfe-421e-a013-f712b8b44c4b\",\"name\":\"参数初始化\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"var lotSize = $vars.lotSize || 0.001; // 每手数量\\n\\nvar grid = _G('grid');\\nvar initPrice = _G('initPrice');\\n\\nif (!initPrice || !grid) {\\n    return {};\\n}\\n\\nexchange.SetContractType($vars.product_code)\\n\\nfunction checkLongOpen(price) {\\n    for (var i = 0; i < grid.longOpenPrices.length; i++) {\\n        // 价格低于目标开仓价 且 该位置无持仓\\n        if (price <= grid.longOpenPrices[i] && !grid.longPositions[i].isOpen) {\\n            Log('开多')\\n            exchange.SetDirection('buy');\\n            var orderId = exchange.Buy(-1, lotSize);\\n            if (orderId) {\\n                // 记录开仓信息\\n                grid.longPositions[i] = {\\n                    isOpen: true,\\n                    openTime: Date.now(),\\n                    openPrice: price\\n                };\\n                _G('grid', grid);\\n                Log('开多 第', i + 1, '档', '开仓价:', price, '目标平仓价:', grid.longClosePrices[i]);\\n            }\\n        }\\n    }\\n}\\n\\nfunction checkLongClose(price) {\\n    for (var i = 0; i < grid.longClosePrices.length; i++) {\\n        // 有持仓 且 价格达到目标平仓价\\n        if (grid.longPositions[i].isOpen && price >= grid.longClosePrices[i]) {\\n            Log('平多')\\n            exchange.SetDirection('closebuy');\\n            var orderId = exchange.Sell(-1, lotSize);\\n            if (orderId) {\\n                var profit = ((price - grid.longPositions[i].openPrice) / grid.longPositions[i].openPrice * 100).toFixed(2);\\n                Log('平多 第', i + 1, '档', '开仓价:', grid.longPositions[i].openPrice, '平仓价:', price, '盈利:', profit + '%');\\n                \\n                // 清除持仓信息\\n                grid.longPositions[i] = {\\n                    isOpen: false,\\n                    openTime: null,\\n                    openPrice: null\\n                };\\n                _G('grid', grid);\\n            }\\n        }\\n    }\\n}\\n\\nfunction checkShortOpen(price) {\\n    for (var i = 0; i < grid.shortOpenPrices.length; i++) {\\n        // 价格高于目标开仓价 且 该位置无持仓\\n        if (price >= grid.shortOpenPrices[i] && !grid.shortPositions[i].isOpen) {\\n            Log('开空')\\n            exchange.SetDirection('sell');\\n            var orderId = exchange.Sell(-1, lotSize);\\n            if (orderId) {\\n                // 记录开仓信息\\n                grid.shortPositions[i] = {\\n                    isOpen: true,\\n                    openTime: Date.now(),\\n                    openPrice: price\\n                };\\n                _G('grid', grid);\\n                Log('开空 第', i + 1, '档', '开仓价:', price, '目标平仓价:', grid.shortClosePrices[i]);\\n            }\\n        }\\n    }\\n}\\n\\nfunction checkShortClose(price) {\\n    for (var i = 0; i < grid.shortClosePrices.length; i++) {\\n        // 有持仓 且 价格达到目标平仓价\\n        if (grid.shortPositions[i].isOpen && price <= grid.shortClosePrices[i]) {\\n            Log('平空')          \\n            exchange.SetDirection('closesell');\\n            var orderId = exchange.Buy(-1, lotSize);\\n            if (orderId) {\\n                var profit = ((grid.shortPositions[i].openPrice - price) / grid.shortPositions[i].openPrice * 100).toFixed(2);\\n                Log('平空 第', i + 1, '档', '开仓价:', grid.shortPositions[i].openPrice, '平仓价:', price, '盈利:', profit + '%');\\n                \\n                // 清除持仓信息\\n                grid.shortPositions[i] = {\\n                    isOpen: false,\\n                    openTime: null,\\n                    openPrice: null\\n                };\\n                _G('grid', grid);\\n            }\\n        }\\n    }\\n}\\n\\n// 获取当前价格\\nvar ticker = exchange.GetTicker();\\nif (!ticker) {\\n    Log('获取ticker失败');\\n    return {};\\n}\\n\\nvar price = ticker.Last;\\n\\n// 检查多仓开平\\ncheckLongOpen(price);\\ncheckLongClose(price);\\n\\n// 检查空仓开平\\ncheckShortOpen(price);\\ncheckShortClose(price);\\n\\nreturn {};\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[-448,160],\"id\":\"0e4f2c7c-3560-40b8-9e2b-d78aff000adf\",\"name\":\"网格策略源码\"},{\"parameters\":{},\"type\":\"n8n-nodes-base.noOp\",\"typeVersion\":1,\"position\":[432,64],\"id\":\"568f4ffb-07ac-4b9a-9068-be5a846842ae\",\"name\":\"无操作\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"// n8n 的正确语法\\nconst inputData = $input.all();\\nconst spotData = inputData[0].json;\\n\\n// 从特定节点获取数据\\nconst positionNode = $node[\\\"触发判断\\\"].json;\\n\\n// 返回数据\\nreturn {\\n  timestamp: new Date().toISOString(),\\n  \\n  // 原始新闻数据保持不变\\n  spotData: spotData,\\n  \\n  // 只整理持仓数据\\n  positions: positionNode\\n};\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[656,256],\"id\":\"5604751f-a9b9-4c0b-b1be-521c664a8fba\",\"name\":\"结果整理\"},{\"parameters\":{\"inputText\":\"=你是一个专业的量化交易策略分析师,负责判断双向网格策略是否需要重置参数。\\n\\n## 策略说明\\n**双向网格交易策略**:\\n- **初始价格(initPrice)**:网格中心价格\\n- **多仓网格**:价格下跌时分档开多,价格回升至目标价平仓(步长{{$vars.stepPercent * 100}}%)\\n- **空仓网格**:价格上涨时分档开空,价格回落至目标价平仓(步长{{$vars.stepPercent * 100}}%)\\n- **最大档位**:多空各{{$vars.maxPositions}}档,共{{$vars.maxPositions * 2}}个潜在仓位\\n\\n## 当前触发条件\\n系统检测到以下异常情况之一,触发AI分析:\\n1. ✅ 满仓状态({{$vars.maxPositions}}个仓位全部持有)\\n2. ✅ 最长持仓时间 ≥ 24小时(持仓被深度套牢)\\n3. ✅ 价格偏离度 ≥ 3%(价格突破或跌破网格范围)\\n\\n---\\n\\n## 输入数据解读\\n\\n### 📊 数据1:持仓详情\\n{{JSON.stringify($json.positions, null, 2)}}\\n\\n**包含信息**:\\n- **longPositions**: 多仓数组,每个元素包含 `{isOpen, openPrice, openTime, floatProfit}`\\n- **shortPositions**: 空仓数组,结构同上\\n- **summary**: \\n  - `totalCount`: 当前持仓总数\\n  - `avgHoldTime`: 平均持仓时长(小时)\\n  - `totalFloatProfit`: 总浮动盈亏百分比\\n- **gridInfo**:\\n  - `initPrice`: 网格初始中心价\\n  - `currentPrice`: 当前市场价格\\n  - `gridUpperLimit`: 网格上限价格\\n  - `gridLowerLimit`: 网格下限价格\\n  - `stepPercent`: 网格步长\\n\\n### 📈 数据2:现货期货价差\\n{{JSON.stringify($json.spotData, null, 2)}}\\n\\n**包含信息**:\\n- **最近60天的现货/期货价差(basis)数据**\\n- **schema**: [day, spot_price, futures_price, basis]\\n- **分析重点**:\\n  - basis为正:期货溢价(市场看多)\\n  - basis为负:现货溢价(市场看空)\\n  - basis趋势变化:市场情绪转向\\n\\n---\\n\\n## 判断逻辑\\n\\n### ✅ 需要重置网格(输出 \\\"Yes\\\")\\n满足以下**任意2项或以上**:\\n1. **趋势明确**:\\n   - 价格单边突破网格上限/下限超过5%\\n   - basis持续单边扩大/缩小超过7天\\n   \\n2. **深度套牢**:\\n   - 平均持仓时长 > 48小时\\n   - 总浮动盈亏 < -5%\\n   - 所有持仓均为同一方向(全多或全空)\\n\\n3. **市场结构变化**:\\n   - basis由正转负或由负转正(市场情绪反转)\\n   - 近7天basis波动率显著增加(市场不稳定)\\n\\n4. **价格远离网格中心**:\\n   - 当前价格与initPrice偏离 > 8%\\n\\n### ❌ 无需重置(输出 \\\"No\\\")\\n以下情况**维持现有网格**:\\n1. 价格在网格上下限范围内正常波动\\n2. basis数据显示市场处于震荡整理\\n3. 持仓时长 < 24小时且浮动盈亏在 -3% ~ +3%\\n4. basis趋势与价格走势不一致(可能是假突破)\\n\\n---\\n\\n## 注意事项\\n⚠️ **谨慎判断原则**:\\n- 避免频繁重置(会损失已有持仓的潜在盈利)\\n- 重置意味着清仓所有持仓并重新建立网格\\n- 只在市场出现明确趋势且原网格无法适应时才重置\\n- 优先考虑basis数据(反映市场真实供需)\\n\\n🎯 **决策优先级**:\\n1. basis趋势(最重要)\\n2. 价格偏离度\\n3. 持仓时长和盈亏\\n4. 市场波动率\",\"options\":{\"categories\":\"Yes, No\",\"systemPromptTemplate\":\"You are highly intelligent and accurate sentiment analyzer. Analyze the sentiment of the provided text. Categorize it into one of the following: {categories}. Use the provided formatting instructions. Only output the JSON.\\nPlease respond with a raw JSON object only, not inside any code block, Markdown, or text explanation.\\nYour response must be only valid JSON (no backticks, no language labels, no extra text).\"}},\"type\":\"n8n-nodes-base.sentimentAnalysis\",\"typeVersion\":1.1,\"position\":[880,256],\"id\":\"aa8417d0-c235-47df-b64e-e210a95e7fb2\",\"name\":\"AI参数分析\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"Log('清仓仓位,重置所有参数')\\n\\nlet positions = exchange.GetPosition();\\n\\nif (positions[0].Type === 0) {\\n    // 平多仓 - 市价卖出\\n    const orderId = exchange.CreateOrder(positions[0].Symbol, 'closebuy', -1, positions[0].Amount);\\n    Log(`✓ 平多仓成功,订单ID: ${orderId}`);\\n} else if (positions[0].Type === 1) {\\n    // 平空仓 - 市价买入\\n    const orderId = exchange.CreateOrder(positions[0].Symbol, 'closesell', -1, positions[0].Amount);\\n    Log(`✓ 平空仓成功,订单ID: ${orderId}`);\\n}\\n\\n_G('grid', null);\\n_G('initPrice', null);\\n_G('lastAItime', Date.now());\\n\\nreturn {};\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[1280,160],\"id\":\"87f55459-9a18-4530-be02-5abe9dad7a27\",\"name\":\"重置策略\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"Log('AI分析不支持调整原始价格')\\n\\n_G('lastAItime', Date.now())\\n\\nreturn {};\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[1280,352],\"id\":\"b603434b-feb4-445a-98fa-7505e6fd2f34\",\"name\":\"AI冷却\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"// ========== 持仓统计节点 ==========\\nvar grid = _G('grid');\\nexchange.SetContractType($vars.product_code)\\nvar ticker = exchange.GetTicker();\\nvar curaccount = exchange.GetAccount();\\nvar initPrice = _G('initPrice');\\nvar initEquity = _G('initEquity');\\n\\nif (!ticker || !grid || !initPrice || !curaccount || !initEquity) {\\n    return {};\\n}\\n\\nlet curProfit = curaccount.Equity - initEquity;\\nLogProfit(curProfit, \\\"&\\\");\\n\\nvar currentPrice = ticker.Last;\\nvar now = Date.now();\\nvar maxPositions = grid.maxPositions || 5;\\n\\n// 统计开仓数量和总浮动盈亏\\nvar openCount = 0;\\nvar lastOpenPosition = null;\\nvar totalProfit = 0;\\nvar longCount = 0;\\nvar shortCount = 0;\\n\\n// 统计多仓\\nfor (var i = 0; i < grid.longPositions.length; i++) {\\n    if (grid.longPositions[i].isOpen) {\\n        openCount++;\\n        longCount++;\\n        lastOpenPosition = grid.longPositions[i];\\n        var posProfit = ((currentPrice - grid.longPositions[i].openPrice) / grid.longPositions[i].openPrice) * 100;\\n        totalProfit += posProfit;\\n    }\\n}\\n\\n// 统计空仓\\nfor (var i = 0; i < grid.shortPositions.length; i++) {\\n    if (grid.shortPositions[i].isOpen) {\\n        openCount++;\\n        shortCount++;\\n        lastOpenPosition = grid.shortPositions[i];\\n        var posProfit = ((grid.shortPositions[i].openPrice - currentPrice) / grid.shortPositions[i].openPrice) * 100;\\n        totalProfit += posProfit;\\n    }\\n}\\n\\n// 构建持仓表格\\nvar table = {\\n    type: \\\"table\\\",\\n    title: \\\"双向网格持仓\\\",\\n    cols: [\\\"初始价\\\", \\\"当前价\\\", \\\"网格步长\\\", \\\"多仓数\\\", \\\"空仓数\\\", \\\"总持仓\\\", \\\"初始权益\\\", \\\"当前权益\\\", \\\"累计盈亏\\\", \\\"浮动盈亏%\\\"],\\n    rows: [[\\n        _N(initPrice, 2),\\n        _N(currentPrice, 2),\\n        _N(grid.stepPercent * 100, 2) + '%',\\n        longCount,\\n        shortCount,\\n        openCount + '/' + maxPositions,\\n        _N(initEquity, 2),\\n        _N(curaccount.Equity, 2),\\n        _N(curProfit, 2),\\n        _N(totalProfit, 2) + '%'\\n    ]]\\n};\\n\\nLogStatus(\\\"`\\\" + JSON.stringify(table) + \\\"`\\\");\\n\\n// 不是满仓不触发AI\\nif (openCount < maxPositions) {\\n    return { aiTrigger: { shouldTrigger: false } };\\n}\\n\\n// 检查AI冷却时间(1天)\\nvar lastAItime = _G('lastAItime');\\nif (lastAItime && (now - lastAItime) < 1000 * 60 * 60 * 24) {\\n    return { aiTrigger: { shouldTrigger: false } };\\n}\\n\\n// 满仓时计算条件\\nvar holdHours = (now - lastOpenPosition.openTime) / 3600000;\\nvar priceDeviation = Math.abs(currentPrice / lastOpenPosition.openPrice - 1);\\n\\n// 价格偏离>3% 或 持仓>24小时\\nvar shouldTriggerAI = priceDeviation > 0.03 || holdHours >= 24;\\n\\nif (shouldTriggerAI) {\\n    Log('触发AI分析 偏离:', (priceDeviation * 100).toFixed(2) + '% 时长:', holdHours.toFixed(1), '小时');\\n}\\n\\nreturn {\\n    aiTrigger: {\\n        shouldTrigger: shouldTriggerAI\\n    }\\n};\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[-224,160],\"id\":\"1811ff16-a87a-4129-9faf-6b1a6c5e43b0\",\"name\":\"触发判断\"},{\"parameters\":{\"method\":\"GET\",\"url\":\"https://www.datadata.cn/api/v1/query/352d0796-17c1-4a14-90a9-4d965760edc0/data\",\"authentication\":\"none\",\"sendQuery\":true,\"specifyQuery\":\"keypair\",\"queryParameters\":{\"parameters\":[{\"name\":\"product_code\",\"value\":\"={{ $vars.product_code.replace(/[^a-zA-Z]/g, '').toUpperCase()}}\"}]},\"sendHeaders\":false,\"sendBody\":false,\"options\":{},\"infoMessage\":\"\"},\"type\":\"n8n-nodes-base.httpRequest\",\"typeVersion\":4.2,\"position\":[432,256],\"id\":\"eade281f-42eb-45e6-adba-2c8a5b7dd81e\",\"name\":\"HTTP 请求\"}],\"pinData\":{},\"connections\":{\"K线收盘触发器1\":{\"main\":[[{\"node\":\"参数初始化\",\"type\":\"main\",\"index\":0}]]},\"OpenAI 模型1\":{\"ai_languageModel\":[[{\"node\":\"AI参数分析\",\"type\":\"ai_languageModel\",\"index\":0}]]},\"分支\":{\"main\":[[{\"node\":\"无操作\",\"type\":\"main\",\"index\":0}],[{\"node\":\"HTTP 请求\",\"type\":\"main\",\"index\":0}]]},\"参数初始化\":{\"main\":[[{\"node\":\"网格策略源码\",\"type\":\"main\",\"index\":0}]]},\"网格策略源码\":{\"main\":[[{\"node\":\"触发判断\",\"type\":\"main\",\"index\":0}]]},\"结果整理\":{\"main\":[[{\"node\":\"AI参数分析\",\"type\":\"main\",\"index\":0}]]},\"AI参数分析\":{\"main\":[[{\"node\":\"重置策略\",\"type\":\"main\",\"index\":0}],[{\"node\":\"AI冷却\",\"type\":\"main\",\"index\":0}]]},\"触发判断\":{\"main\":[[{\"node\":\"分支\",\"type\":\"main\",\"index\":0}]]},\"HTTP 请求\":{\"main\":[[{\"node\":\"结果整理\",\"type\":\"main\",\"index\":0}]]}},\"active\":false,\"settings\":{\"timezone\":\"Asia/Shanghai\",\"executionOrder\":\"v1\"},\"tags\":[],\"meta\":{\"templateCredsSetupCompleted\":true},\"credentials\":{},\"id\":\"054cd6d1-b7f9-4fd2-bf78-bc6b52b67726\",\"plugins\":{},\"mcpClients\":{}},\"startNodes\":[],\"triggerToStartFrom\":{\"name\":\"K线收盘触发器1\"}}"}