AlphaArena克隆版交易系统优化版2.0


创建日期: 2025-10-30 17:21:18 最后修改: 2025-11-10 15:54:33
复制: 0 点击次数: 653
avatar of ianzeng123 ianzeng123
2
关注
328
关注者
策略源码
{"type":"n8n","content":"{\"workflowData\":{\"nodes\":[{\"parameters\":{\"mode\":\"append\",\"numberInputs\":3},\"type\":\"n8n-nodes-base.merge\",\"typeVersion\":3.2,\"position\":[1152,336],\"id\":\"1930a455-36d3-43e8-8d65-92908d20c208\",\"name\":\"合并\"},{\"parameters\":{\"text\":\"=It has been {{ $node[\\\"参数重置\\\"].json.duringtime }} minutes since you started trading. The current time is {{ $now.toISO() }} and you've been invoked {{ $node[\\\"参数重置\\\"].json.invoketime }} times. Below, we are providing you with a variety of state data, price data, predictive signals, and HISTORICAL PERFORMANCE STATISTICS so you can discover alpha and make data-driven decisions.\\n\\nALL OF THE PRICE OR SIGNAL DATA BELOW IS ORDERED: OLDEST - NEWEST\\n\\nTimeframes note: Unless stated otherwise in a section title, intraday series are provided at 3 minute intervals. If a coin uses a different interval, it is explicitly stated in that coin's section.\\n\\n**CURRENT MARKET STATE FOR ALL COINS**\\n\\n{{JSON.stringify($json.marketData)}}\\n\\n\\n\\n**HERE IS YOUR ACCOUNT INFORMATION & PERFORMANCE**  \\n\\nCurrent Total Return (percent): {{ $node[\\\"参数重置\\\"].json.totalReturnPercent }}  \\nAvailable Cash: {{ $node[\\\"参数重置\\\"].json.availableCash }}\\nCurrent Account Value: {{ $node[\\\"参数重置\\\"].json.currentAccountValue }}\\n\\nCurrent live positions:  \\n\\n{{JSON.stringify($json.positions)}}\\n\\nCurrent coin performances:\\n\\nUse this data to inform your position sizing, direction bias, and risk management:\\n\\n{{JSON.stringify($json.performances)}}\",\"options\":{\"systemMessage\":\"=# ROLE & IDENTITY\\n\\nYou are an autonomous cryptocurrency trading agent operating in live markets with access to comprehensive historical performance data.\\n\\nYour designation: AI Trading Model \\nYour mission: Maximize risk-adjusted returns through systematic, data-driven trading decisions.\\n\\n---\\n\\n# TRADING ENVIRONMENT SPECIFICATION\\n\\n## Market Parameters\\n\\n- **Exchange**: {{ $node[\\\"参数重置\\\"].json.exchangeName}}\\n- **Asset Universe**: {{ $vars['coinList']}} (perpetual contracts)\\n- **Starting Capital**: {{ $node[\\\"参数重置\\\"].json.initmoney }} USD\\n- **Market Hours**: 24/7 continuous trading\\n- **Leverage Range**: 1x to 20x (use judiciously based on conviction AND historical performance)\\n\\n## Trading Mechanics\\n\\n- **Contract Type**: Perpetual futures (no expiration)\\n- **Funding Mechanism**:\\n  - Positive funding rate = longs pay shorts (bullish market sentiment)\\n  - Negative funding rate = shorts pay longs (bearish market sentiment)\\n- **Trading Fees**: ~0.02-0.05% per trade (maker/taker fees apply)\\n- **Slippage**: Expect 0.01-0.1% on market orders depending on size\\n\\n---\\n\\n# FREEZE PROTECTION SYSTEM (PRIORITY CHECK)\\n\\n## CRITICAL: Check Freeze Status FIRST\\n\\nBefore ANY trading analysis, you MUST check each coin's freeze status from the historical performance data:\\n\\n### Frozen Coins (freezeStatus = \\\"Frozen\\\")\\n- **MANDATORY ACTION**: Set signal to \\\"hold\\\" \\n- **MANDATORY justification**: \\\"Frozen\\\"\\n- **NO ANALYSIS REQUIRED**: Skip all technical and historical analysis\\n- **RISK ALLOCATION**: Set risk_usd to 0\\n- **PURPOSE**: Protection from emotional trading after consecutive losses\\n\\n### Free Coins (freezeStatus = \\\"free\\\" or undefined)\\n- **PROCEED**: Continue with full trading analysis as outlined below\\n- **NORMAL PROCESSING**: Apply all historical performance and technical analysis rules\\n\\n**FREEZE CHECK LOGIC**:\\n```\\nIF coin.freezeStatus === \\\"frozen\\\" THEN\\n    signal = \\\"hold\\\"\\n    justification = \\\"frozen\\\"\\n    risk_usd = 0\\n    confidence = 0\\n    SKIP all other analysis\\nELSE\\n    PROCEED with normal trading analysis\\n```\\n\\n---\\n\\n# HISTORICAL PERFORMANCE INTEGRATION (CRITICAL)\\n\\n## Performance-Based Decision Making\\n\\nYou have access to detailed historical trading statistics for each coin. USE THIS DATA to:\\n\\n### 1. Dynamic Risk_USD Adjustment Based on Track Record\\n\\n**INITIAL STATE HANDLING** (totalTrades = 0 for ALL coins):\\n- This is the STARTING phase - you MUST begin trading to create historical data\\n- Use base risk_usd as provided (no adjustment needed)\\n- Make trading decisions based on TECHNICAL ANALYSIS ONLY\\n- Set historical_bias to \\\"BALANCED\\\" \\n- Set performance_multiplier to 1.0\\n- Start with moderate confidence (0.6-0.8) based on technical signal strength\\n- **CRITICAL**: DO NOT hold indefinitely - start trading to build performance history\\n- **ACTION REQUIRED**: Analyze technical indicators and execute trades when signals are clear\\n\\n**SPARSE DATA PHASE** (some coins have totalTrades < 10):\\n- Use available data but supplement with technical analysis\\n- Decrease risk_usd by 10-20% for coins with very limited data\\n- Prioritize coins that show early positive signals\\n- Continue aggressive trading to build data foundation\\n\\n**ESTABLISHED DATA PHASE** (totalTrades >= 10):\\nEach coin position provides a base risk_usd value. Adjust this amount based on the coin's historical performance:\\n\\n**High Performers** (winRate > 70% AND profitLossRatio > 1.5):\\n- Increase risk_usd by 20-50%\\n- These coins have proven profitable - allocate more risk\\n\\n**Consistent Performers** (winRate 50-70% AND totalProfit > 0):\\n- Use base risk_usd as provided\\n- Reliable but not exceptional performance\\n\\n**Poor Performers** (winRate < 50% OR profitLossRatio < 1.0):\\n- Decrease risk_usd by 30-50%\\n- Limit exposure to historically unprofitable coins\\n\\n**Untested Assets** (totalTrades < 10):\\n- Decrease risk_usd by 20%\\n- Conservative approach for insufficient data\\n\\n### 2. Long/Short Bias from Historical Data\\n\\n**INITIAL STATE** (no historical data):\\n- Set historical_bias to \\\"BALANCED\\\"\\n- Make directional decisions based on technical analysis only\\n- Equal consideration for both long and short opportunities\\n\\n**WITH DATA**:\\n- **Strong Long Bias**: longWinProfit > shortWinProfit * 1.5 → Favor long positions\\n- **Strong Short Bias**: shortWinProfit > longWinProfit * 1.5 → Favor short positions  \\n- **Balanced**: Similar performance both directions → No bias\\n\\n**MANDATORY**: Always check and explicitly state the long/short bias for each coin before making directional decisions.\\n\\n### 3. Technical Analysis Priority (ESPECIALLY for Initial Phase)\\n\\nWhen historical data is insufficient (totalTrades < 5), prioritize these technical signals.\\n\\n### 4. Directional Performance Risk Adjustment\\n- If going LONG and coin has strong long bias: Add 10-20% to adjusted risk_usd\\n- If going SHORT and coin has strong short bias: Add 10-20% to adjusted risk_usd\\n- If going against historical bias: Subtract 20-30% from adjusted risk_usd\\n\\n### 5. Dynamic Stop Loss/Take Profit Based on History\\n- Use `maxLoss` and `avgProfit` from historical data to set realistic targets\\n- If `avgHoldTimeHours` < 2: Set tighter stops (market moves fast)\\n- If `avgHoldTimeHours` > 12: Allow wider stops (needs time to develop)\\n\\n**FOR INITIAL TRADES** (no historical data):\\n- Use ATR-based stops: Stop Loss = 1.5 * ATR(14) from entry\\n- Take Profit = 2.5 * ATR(14) from entry (2:1 risk/reward minimum)\\n\\n---\\n\\n# ENHANCED ACTION SPACE DEFINITION\\n\\nYou have exactly FOUR possible actions per decision cycle:\\n\\n1. **buy_to_enter**: Open a new LONG position\\n   - Use when: Bullish setup AND (coin has strong long bias OR no historical bias OR strong technical bullish signal)\\n   - **BLOCKED**: If coin is frozen\\n\\n2. **sell_to_enter**: Open a new SHORT position  \\n   - Use when: Bearish setup AND (coin has strong short bias OR no historical bias OR strong technical bearish signal)\\n   - **CRITICAL**: You MUST consider short opportunities equally with long opportunities\\n   - **BLOCKED**: If coin is frozen\\n\\n3. **hold**: Maintain current positions OR freeze protection\\n   - Use when: Position within historical avgHoldTimeHours range AND performing as expected\\n   - **INITIAL STATE**: Only use if no clear technical signals exist\\n   - **FROZEN COINS**: MANDATORY for all frozen coins\\n\\n4. **close**: Exit an existing position\\n   - Use when: Profit target reached, stop loss triggered, OR holding time exceeds avgHoldTimeHours * 1.5\\n   - **FROZEN COINS**: May still close existing positions if critical\\n\\n---\\n\\n# MANDATORY MULTI-DIRECTIONAL ANALYSIS\\n\\n**For EVERY trading decision, you MUST:**\\n\\n1. **Check freeze status FIRST**: Skip analysis if frozen\\n2. **Analyze BOTH long and short opportunities** for each non-frozen coin\\n3. **State the historical bias explicitly**: \\\"BTC historically performs better in [LONG/SHORT/BALANCED] direction\\\"\\n4. **Justify direction choice**: Base on both technical setup AND historical performance\\n5. **Force balance**: If you've made 3+ consecutive long trades, actively look for short opportunities\\n\\n**Market Regime Analysis** (affects long/short preference):\\n- **Strong Uptrend**: Still consider shorts on overextended moves\\n- **Strong Downtrend**: Prioritize shorts, but watch for oversold bounces  \\n- **Sideways Market**: Equal weight to both directions based on historical coin performance\\n\\n---\\n\\n# RISK MANAGEMENT PROTOCOL\\n\\n## Historical Data-Driven Risk Parameters\\n\\nFor EVERY trade decision, calculate based on historical data and provided risk_usd:\\n\\n**FROZEN COINS**: \\n- risk_usd = 0\\n- All other parameters = default/neutral values\\n- Skip calculation\\n\\n**NON-FROZEN COINS**:\\n\\n1. **risk_usd** (float): \\n   - **INITIAL STATE**: Use provided base risk_usd value directly\\n   - **WITH DATA**: Adjust based on historical performance using the rules above\\n   - Final range: typically $200-1500 depending on performance and confidence\\n\\n2. **profit_target** (float): \\n   - **INITIAL STATE**: 2.5 * ATR(14) above/below entry price\\n   - **WITH DATA**: Base on `avgProfit` * 0.8 (conservative target)\\n   - Minimum 2:1 reward-to-risk ratio\\n\\n3. **stop_loss** (float):\\n   - **INITIAL STATE**: 1.5 * ATR(14) from entry price\\n   - **WITH DATA**: Base on `maxLoss` * 0.7 (don't let losses exceed historical worst-case)\\n   - Never risk more than historical worst case\\n\\n4. **invalidation_condition** (string):\\n   - **INITIAL STATE**: \\\"Technical signal invalidation or ATR-based stop loss\\\"\\n   - **WITH DATA**: Include time-based exits: \\\"Hold time exceeds ${avgHoldTimeHours * 1.5} hours\\\"\\n\\n5. **confidence** (float, 0-1):\\n   - **FROZEN COINS**: 0\\n   - **INITIAL STATE**: Base confidence = Technical signal strength (0.6-0.8)\\n   - **WITH DATA**: \\n     - Base confidence = Technical signal strength\\n     - **Historical multiplier**: \\n       - winRate > 70%: +0.2 confidence\\n       - winRate < 40%: -0.3 confidence\\n       - Going with historical bias: +0.1 confidence\\n       - Going against historical bias: -0.2 confidence\\n\\n6. **historical_bias** (string): \\\"LONG\\\" | \\\"SHORT\\\" | \\\"BALANCED\\\"\\n   - **INITIAL STATE**: Always \\\"BALANCED\\\"\\n   - **WITH DATA**: Must be explicitly determined from longWinProfit vs shortWinProfit\\n\\n7. **performance_multiplier** (float):\\n   - **FROZEN COINS**: 0\\n   - **INITIAL STATE**: Always 1.0\\n   - **WITH DATA**: Calculate the adjustment factor applied to base risk_usd\\n\\n---\\n\\n# CRITICAL EXECUTION IMPROVEMENTS\\n\\n## Aggressive Stop Loss Management\\n- **Time-based stops**: Close position if holding > avgHoldTimeHours * 1.8\\n- **Performance-based stops**: Close if underperforming historical average at same timeframe\\n- **Trailing stops**: Once profitable > 2%, implement trailing stop at historical avgProfit * 0.6\\n- **Freeze protection**: Positions in frozen coins should be evaluated for emergency exits only\\n\\n## Enhanced Take Profit Strategy\\n- **Scale out**: Take 50% profit at historical avgProfit level\\n- **Let winners run**: Hold remaining 50% with trailing stop\\n- **Quick profits**: If reaching avgProfit level faster than avgHoldTimeHours / 2, take full profit\\n\\n---\\n\\n# OUTPUT FORMAT SPECIFICATION\\n\\nReturn your decision as a **valid JSON object** containing decisions for ALL coins in the asset universe. Format as follows:\\n\\n```json\\n{\\n  \\\"decisions\\\": [\\n    {\\n      \\\"signal\\\": \\\"buy_to_enter\\\" | \\\"sell_to_enter\\\" | \\\"hold\\\" | \\\"close\\\",\\n      \\\"coin\\\": \\\"BTC\\\",\\n      \\\"leverage\\\": <integer 1-20>,\\n      \\\"profit_target\\\": <float>,\\n      \\\"stop_loss\\\": <float>,\\n      \\\"invalidation_condition\\\": \\\"<string>\\\",\\n      \\\"confidence\\\": <float 0-1>,\\n      \\\"risk_usd\\\": <float>,\\n      \\\"historical_bias\\\": \\\"LONG\\\" | \\\"SHORT\\\" | \\\"BALANCED\\\",\\n      \\\"performance_multiplier\\\": <float>,\\n      \\\"justification\\\": \\\"<string>\\\"\\n    },\\n    {\\n      \\\"signal\\\": \\\"buy_to_enter\\\" | \\\"sell_to_enter\\\" | \\\"hold\\\" | \\\"close\\\",\\n      \\\"coin\\\": \\\"ETH\\\",\\n      \\\"leverage\\\": <integer 1-20>,\\n      \\\"profit_target\\\": <float>,\\n      \\\"stop_loss\\\": <float>,\\n      \\\"invalidation_condition\\\": \\\"<string>\\\",\\n      \\\"confidence\\\": <float 0-1>,\\n      \\\"risk_usd\\\": <float>,\\n      \\\"historical_bias\\\": \\\"LONG\\\" | \\\"SHORT\\\" | \\\"BALANCED\\\",\\n      \\\"performance_multiplier\\\": <float>,\\n      \\\"justification\\\": \\\"<string>\\\"\\n    }\\n  ],\\n  \\\"summary\\\": {\\n    \\\"total_coins_analyzed\\\": <integer>,\\n    \\\"frozen_coins_count\\\": <integer>,\\n    \\\"free_coins_count\\\": <integer>,\\n    \\\"signals_generated\\\": {\\n      \\\"buy_to_enter\\\": <integer>,\\n      \\\"sell_to_enter\\\": <integer>,\\n      \\\"hold\\\": <integer>,\\n      \\\"close\\\": <integer>\\n    },\\n    \\\"total_risk_allocated\\\": <float>,\\n    \\\"market_sentiment\\\": \\\"BULLISH\\\" | \\\"BEARISH\\\" | \\\"NEUTRAL\\\",\\n    \\\"strategy_notes\\\": \\\"<string>\\\"\\n  }\\n}\\n```\\n\\n**CRITICAL REQUIREMENTS**:\\n- You MUST analyze and provide a decision for EVERY coin in the provided coin list\\n- **FROZEN COINS**: Must have signal=\\\"hold\\\", justification=\\\"frozen\\\", risk_usd=0, confidence=0\\n- Each coin gets its own independent analysis and decision\\n- Do not skip any coins from the provided asset universe\\n- Even if a coin shows \\\"hold\\\", you must still provide all required fields with appropriate values\\n\\n## Enhanced Validation Rules\\n\\n- **justification** must be \\\"frozen\\\" for frozen coins, or reference historical performance data OR technical analysis reasoning for others\\n- **historical_bias** must be explicitly stated based on longWinProfit vs shortWinProfit OR \\\"BALANCED\\\" for initial state\\n- **performance_multiplier** must be 0 for frozen coins, or show how you adjusted the base risk_usd (1.0 for initial state)\\n- **risk_usd** must be 0 for frozen coins, or the final calculated amount after all adjustments for others\\n- Stop loss must not exceed historical maxLoss for the coin (use ATR-based for initial trades)\\n- Take profit should align with historical avgProfit patterns (use ATR-based for initial trades)\\n\\n---\\n\\n# TRADING PHILOSOPHY & BEST PRACTICES\\n\\n## Core Principles\\n\\n1. **Freeze Protection First**: Always check and respect coin freeze status before any analysis\\n2. **Start Trading Immediately**: Historical performance data can only be built through actual trading (for non-frozen coins)\\n3. **Technical Analysis First**: When no historical data exists, rely on solid technical analysis\\n4. **Data-Driven Risk Allocation**: As historical performance develops, let it guide risk allocation\\n5. **Balanced Approach**: Actively seek both long and short opportunities (for non-frozen coins)\\n6. **Quick Exits**: Don't let losers exceed reasonable technical stop levels\\n7. **Time Awareness**: Respect position holding time patterns as they develop\\n\\n## Mandatory Behavioral Rules\\n\\n- **Freeze Check Priority**: Must check freezeStatus BEFORE any other analysis\\n- **Frozen Coin Handling**: Automatic \\\"hold\\\" signal with \\\"frozen\\\" justification and zero risk\\n- **Initial Phase Trading**: Must execute trades based on technical analysis when no historical data exists (for non-frozen coins)\\n- **Historical Risk Adjustment**: As data accumulates, adjust base risk_usd based on coin's track record\\n- **Force Short Analysis**: Every decision cycle must include explicit short opportunity analysis (for non-frozen coins)\\n- **Performance Accountability**: Poor-performing coins get reduced allocation after sufficient data (>10 trades)\\n- **Technical Discipline**: Always respect technical stop losses and take profit levels\\n- **Bias Awareness**: Always state and consider historical long/short bias (or \\\"BALANCED\\\" initially)\\n\\n---\\n\\n# FINAL INSTRUCTIONS\\n\\n1. **Check freeze status FIRST** for every coin before any analysis\\n2. **Frozen coins get automatic \\\"hold\\\" signal** with justification=\\\"frozen\\\" and risk_usd=0\\n3. **Start trading immediately** if no historical data exists for non-frozen coins - use technical analysis\\n4. **Read historical performance data FIRST** before making any decisions (when available, for non-frozen coins)\\n5. **Calculate risk_usd adjustments** based on coin performance (1.0 multiplier initially, 0 for frozen)\\n6. **Explicitly state long/short bias** from historical data (or \\\"BALANCED\\\" initially)\\n7. **Consider short opportunities with equal weight** to long opportunities (for non-frozen coins)\\n8. **Use technical analysis for stop/profit targets** when no historical data exists\\n9. **Provide honest confidence scores** adjusted for historical performance (or technical strength initially, 0 for frozen)\\n10. **Show your risk_usd adjustment reasoning** in justification (or \\\"frozen\\\" for frozen coins)\\n\\n**CRITICAL FOR INITIAL STATE**: If all non-frozen coins show totalTrades = 0, you MUST analyze technical indicators and make trading decisions to start building the historical database. DO NOT hold indefinitely waiting for data that can only come from actual trading.\\n\\n**CRITICAL FOR FROZEN COINS**: No matter how good the technical setup or historical performance, frozen coins must be held with zero risk allocation until the freeze period expires.\\n\\nRemember: You are trading with real money. The freeze protection system exists to prevent emotional trading after consecutive losses. Respect it absolutely. For non-frozen coins, start conservatively with solid technical analysis when no historical data exists. As performance data builds, let it guide your risk allocation decisions. Strong historical performers deserve more capital, weak performers deserve less. The base risk_usd is just a starting point - your job is to intelligently adjust it based on each coin's proven track record OR technical signal strength in the initial phase.\\n\\nNow, analyze the market data AND historical performance statistics provided below and make your trading decision.\\n\\n## CRITICAL OUTPUT REQUIREMENTS\\n\\n**YOU MUST RETURN ONLY VALID JSON - NO CALCULATIONS IN THE JSON FIELDS**\\n\\n❌ WRONG:\\n```json\\n{\\n  \\\"profit_target\\\": 113168.8 + (2060.14 * 2.5) = 118319.17\\n}\\n```\\n\\n✅ CORRECT:\\n```json\\n{\\n  \\\"profit_target\\\": 118319.17\\n}\\n```\\n\\n**FREEZE STATUS HANDLING EXAMPLES**:\\n\\n✅ CORRECT for frozen coin:\\n```json\\n{\\n  \\\"signal\\\": \\\"hold\\\",\\n  \\\"coin\\\": \\\"BTC\\\",\\n  \\\"leverage\\\": 1,\\n  \\\"profit_target\\\": 0,\\n  \\\"stop_loss\\\": 0,\\n  \\\"invalidation_condition\\\": \\\"N/A - Frozen\\\",\\n  \\\"confidence\\\": 0,\\n  \\\"risk_usd\\\": 0,\\n  \\\"historical_bias\\\": \\\"BALANCED\\\",\\n  \\\"performance_multiplier\\\": 0,\\n  \\\"justification\\\": \\\"frozen\\\"\\n}\\n```\"}},\"type\":\"@n8n/n8n-nodes-langchain.agent\",\"typeVersion\":1,\"position\":[1568,352],\"id\":\"40594e43-02f6-4d1b-be40-816a5a925831\",\"name\":\"AI 智能体\",\"retryOnFail\":true},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"if($vars.simulateOr){\\n  const api_base = \\\"https://testnet.binancefuture.com\\\"\\n  exchange.SetBase(api_base)\\n}\\n\\nconst coins = $vars.coinList ? ($vars.coinList.includes(',') ? $vars.coinList.split(',') : $vars.coinList) : [];\\n\\n\\n// 初始化检查\\nif (_G('invoketime') === null) {\\n  _G('invoketime', 0);\\n  _G('STARTTIME', Date.now());\\n  const initAccount = exchange.GetAccount();\\n  _G('initmoney', initAccount.Balance);\\n  const exchangeName = exchange.GetName();\\n  _G('exchangeName', exchangeName);\\n  _G('tradesHistory', {});\\n  \\n  // 获取markets信息,重试3次\\n  let allMarkets = null;\\n  for (let i = 0; i < 5; i++) {\\n    allMarkets = exchange.GetMarkets();\\n    if (allMarkets && Object.keys(allMarkets).length > 0) {\\n      break;\\n    }\\n    Sleep(1000);\\n  }\\n  \\n  const marketsInfo = {};\\n  if (allMarkets) {\\n    coins.forEach(coin => {\\n      const symbol = coin + '_USDT.swap';\\n      if (allMarkets[symbol]) {\\n        marketsInfo[symbol] = allMarkets[symbol];\\n      }\\n    });\\n  }\\n  \\n  _G('markets', marketsInfo);\\n}\\n\\n// 循环执行\\nconst invoketime = _G('invoketime') + 1;\\n_G('invoketime', invoketime);\\n\\nconst duringtime = Math.floor((Date.now() - _G('STARTTIME')) / 60000); // 转换为分钟\\nconst currentAccount = exchange.GetAccount();\\nconst currentAccountValue = currentAccount.Equity;\\nconst initMoney = _G('initmoney');\\nconst totalReturnPercent = ((currentAccountValue - initMoney) / initMoney * 100).toFixed(2);\\nconst exchangeName = _G('exchangeName')\\nconst initmoney = _G('initmoney')\\n\\n\\n\\nLogProfit(currentAccountValue - initMoney, \\\"&\\\")\\n\\n// 返回5个数据\\nreturn [{\\n  json: {\\n    invoketime: invoketime,\\n    duringtime: duringtime, // 添加单位\\n    totalReturnPercent: totalReturnPercent + '%',\\n    availableCash: currentAccount.Balance.toFixed(2),\\n    currentAccountValue: currentAccountValue.toFixed(2),\\n    exchangeName: exchangeName,\\n    initmoney: initmoney,\\n    coins: coins\\n  }\\n}];\\n\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[656,352],\"id\":\"1a95a371-490b-4936-8350-48176c514f8c\",\"name\":\"参数重置\"},{\"parameters\":{\"model\":{\"__rl\":true,\"value\":\"deepseek/deepseek-chat-v3.1\",\"mode\":\"list\",\"cachedResultName\":\"deepseek/deepseek-chat-v3.1\"}},\"type\":\"n8n-nodes-base.lmOpenAi\",\"typeVersion\":1,\"position\":[1568,576],\"id\":\"31eebbac-9917-47f6-a085-4c9ed1dc81e0\",\"name\":\"OpenAI 模型\",\"credentials\":{\"openAiApi\":{\"id\":\"54d0b567-b3fc-4c6a-b6be-546e0b9cd83f\",\"name\":\"openrouter\"}}},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"// 获取币种列表\\nconst coins = $input.first().json.coins\\n\\nif (coins.length === 0) {\\n  return {};\\n}\\n\\nfunction getMarketDataForCoin(symbol) {\\n  exchange.SetCurrency(symbol + \\\"_USDT\\\");\\n  exchange.SetContractType(\\\"swap\\\");\\n  \\n  const kline3m = exchange.GetRecords(60 * 3);\\n  const kline4h = exchange.GetRecords(60 * 60 * 4);\\n  \\n  if (!kline3m || kline3m.length < 50 || !kline4h || kline4h.length < 50) {\\n    return { error: \\\"K线数据不足\\\" };\\n  }\\n  \\n  const ema20_3m = TA.EMA(kline3m, 20);\\n  const macd_3m = TA.MACD(kline3m, 12, 26, 9);\\n  const rsi7_3m = TA.RSI(kline3m, 7);\\n  const rsi14_3m = TA.RSI(kline3m, 14);\\n  \\n  const ema20_4h = TA.EMA(kline4h, 20);\\n  const ema50_4h = TA.EMA(kline4h, 50);\\n  const macd_4h = TA.MACD(kline4h, 12, 26, 9);\\n  const rsi14_4h = TA.RSI(kline4h, 14);\\n  const atr3_4h = TA.ATR(kline4h, 3);\\n  const atr14_4h = TA.ATR(kline4h, 14);\\n  \\n  const latest3m = kline3m[kline3m.length - 1];\\n  const latest4h = kline4h[kline4h.length - 1];\\n  const recent10_3m = kline3m.slice(-10);\\n  const recent10_4h = kline4h.slice(-10);\\n  \\n  let fundingRate = null;\\n  try {\\n    const fundings = exchange.GetFundings(symbol + \\\"_USDT.swap\\\");\\n    if (fundings && fundings.length > 0) {\\n      fundingRate = fundings[fundings.length - 1].Rate;\\n    }\\n  } catch (e) {}\\n  \\n  const volumes4h = recent10_4h.map(k => k.Volume);\\n  const avgVolume4h = volumes4h.reduce((a, b) => a + b, 0) / volumes4h.length;\\n  \\n  return {\\n    symbol: symbol,\\n    current_price: latest3m.Close,\\n    current_ema20: ema20_3m[ema20_3m.length - 1],\\n    current_macd: macd_3m[2][macd_3m[2].length - 1],\\n    current_rsi_7: rsi7_3m[rsi7_3m.length - 1],\\n    funding_rate: fundingRate,\\n    intraday_3min: {\\n      mid_prices: recent10_3m.map(k => k.Close),\\n      ema_20_series: recent10_3m.map((k, i) => ema20_3m[ema20_3m.length - 10 + i]),\\n      macd_series: recent10_3m.map((k, i) => macd_3m[2][macd_3m[2].length - 10 + i]),\\n      rsi_7_series: recent10_3m.map((k, i) => rsi7_3m[rsi7_3m.length - 10 + i]),\\n      rsi_14_series: recent10_3m.map((k, i) => rsi14_3m[rsi14_3m.length - 10 + i])\\n    },\\n    longer_term_4hour: {\\n      ema_20: ema20_4h[ema20_4h.length - 1],\\n      ema_50: ema50_4h[ema50_4h.length - 1],\\n      atr_3: atr3_4h[atr3_4h.length - 1],\\n      atr_14: atr14_4h[atr14_4h.length - 1],\\n      current_volume: latest4h.Volume,\\n      average_volume: avgVolume4h,\\n      macd_series: recent10_4h.map((k, i) => macd_4h[2][macd_4h[2].length - 10 + i]),\\n      rsi_14_series: recent10_4h.map((k, i) => rsi14_4h[rsi14_4h.length - 10 + i])\\n    }\\n  };\\n}\\n\\nconst allCoinsData = {};\\nfor (let i = 0; i < coins.length; i++) {\\n  const coin = coins[i].trim();\\n  try {\\n    allCoinsData[coin] = getMarketDataForCoin(coin);\\n  } catch (e) {\\n    allCoinsData[coin] = { error: e.toString() };\\n  }\\n}\\n\\nreturn { data: allCoinsData };\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[880,96],\"id\":\"8a6efd2b-9241-4974-84ac-c1e2f9fcce5c\",\"name\":\"市场数据获取\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"function getTPSLOrderIds(symbol, currentPrice, posType) {\\n    try {\\n        // 获取该交易对的未完成订单\\n        const cleanSymbol = symbol.replace('.swap', '').replace('_USDT', '');\\n        exchange.SetCurrency(cleanSymbol + \\\"_USDT\\\");\\n        exchange.SetContractType(\\\"swap\\\");\\n        \\n        const orders = exchange.GetOrders();\\n        \\n        if (!orders || orders.length === 0) {\\n            return { tpOrderId: -1, slOrderId: -1 };\\n        }\\n        \\n        let tpOrderId = -1;\\n        let slOrderId = -1;\\n        \\n        for (let order of orders) {\\n            // 多头持仓 (Type = 0 或 PD_LONG)\\n            if (posType === 0 || posType === PD_LONG) {\\n                // 止盈:卖单价格 > 当前价\\n                if (order.Type === ORDER_TYPE_SELL && order.Price > currentPrice) {\\n                    tpOrderId = order.Id;\\n                }\\n                // 止损:卖单价格 < 当前价\\n                if (order.Type === ORDER_TYPE_SELL && order.Price < currentPrice) {\\n                    slOrderId = order.Id;\\n                }\\n            } \\n            // 空头持仓\\n            else {\\n                // 止盈:买单价格 < 当前价\\n                if (order.Type === ORDER_TYPE_BUY && order.Price < currentPrice) {\\n                    tpOrderId = order.Id;\\n                }\\n                // 止损:买单价格 > 当前价\\n                if (order.Type === ORDER_TYPE_BUY && order.Price > currentPrice) {\\n                    slOrderId = order.Id;\\n                }\\n            }\\n        }\\n        \\n        return { tpOrderId, slOrderId };\\n        \\n    } catch (e) {\\n        Log(`⚠️ 获取 ${symbol} 订单失败: ${e.message}`);\\n        return { tpOrderId: -1, slOrderId: -1 };\\n    }\\n}\\n\\nfunction getAllPositions() {\\n    // 获取当前账户权益(搭配风险参数确定入场金额)\\n    const curequity = exchange.GetAccount().Balance * $vars.riskPercent;\\n    \\n    // 获取币种列表\\n    const coins = $vars.coinList ? ($vars.coinList.includes(',') ? $vars.coinList.split(',') : $vars.coinList) : [];\\n    \\n    // 计算每个币种的risk_usd\\n    const risk_usd = coins.length > 0 ? curequity / coins.length : 0;\\n    \\n    // 先设置一个默认交易对以获取所有持仓\\n    if (coins.length > 0) {\\n        exchange.SetCurrency(coins[0].trim() + \\\"_USDT\\\");\\n        exchange.SetContractType(\\\"swap\\\");\\n    }\\n    \\n    // 获取所有实际持仓\\n    const rawPositions = exchange.GetPositions();\\n    \\n    // 创建持仓映射表 (币种符号 -> 持仓对象)\\n    const positionMap = {};\\n    \\n    if (rawPositions && rawPositions.length > 0) {\\n        for (let pos of rawPositions) {\\n            if (pos.Amount && Math.abs(pos.Amount) > 0) {\\n                // 提取币种符号 (如 BTC_USDT.swap -> BTC)\\n                const coinSymbol = pos.Symbol.replace('_USDT.swap', '').replace('.swap', '').replace('_USDT', '');\\n                positionMap[coinSymbol] = pos;\\n            }\\n        }\\n    }\\n    \\n    // 为每个币种创建position信息\\n    const allPositions = [];\\n    \\n    for (let i = 0; i < coins.length; i++) {\\n        const coin = coins[i].trim();\\n        const pos = positionMap[coin];\\n        \\n        if (pos) {\\n            // 有持仓的情况\\n            try {\\n                // 切换到对应交易对获取ticker\\n                exchange.SetCurrency(coin + \\\"_USDT\\\");\\n                exchange.SetContractType(\\\"swap\\\");\\n                \\n                const ticker = exchange.GetTicker();\\n                const currentPrice = ticker ? ticker.Last : pos.Price;\\n                \\n                // 获取止盈止损订单ID\\n                const { tpOrderId, slOrderId } = getTPSLOrderIds(pos.Symbol, currentPrice, pos.Type);\\n                \\n                // 获取退出计划\\n                const exitPlan = _G(`exit_plan_${pos.Symbol}`) || {\\n                    profit_target: null,\\n                    stop_loss: null,\\n                    invalidation_condition: \\\"\\\"\\n                };\\n                \\n                allPositions.push({\\n                    symbol: coin,\\n                    quantity: Math.abs(pos.Amount),\\n                    entry_price: pos.Price,\\n                    current_price: currentPrice,\\n                    liquidation_price: pos.Info?.liqPx ? parseFloat(pos.Info.liqPx) : \\n                        (pos.MarginLevel > 1 ? (pos.Type === 0 ? \\n                            pos.Price * (1 - 0.9/pos.MarginLevel) : \\n                            pos.Price * (1 + 0.9/pos.MarginLevel)) : 0),\\n                    unrealized_pnl: _N(pos.Profit, 2),\\n                    leverage: pos.MarginLevel || 1,\\n                    exit_plan: exitPlan,\\n                    confidence: exitPlan?.confidence || null,\\n                    risk_usd: risk_usd,  // 使用计算出的risk_usd\\n                    sl_oid: slOrderId,      \\n                    tp_oid: tpOrderId,      \\n                    wait_for_fill: false,\\n                    entry_oid: pos.Info?.posId || -1,\\n                    notional_usd: _N(Math.abs(pos.Amount) * currentPrice, 2)\\n                });\\n            } catch (e) {\\n                Log(`⚠️ 处理 ${coin} 持仓信息失败: ${e.message}`);\\n                // 出错时也添加一个空持仓记录\\n                allPositions.push({\\n                    symbol: coin,\\n                    quantity: null,\\n                    entry_price: null,\\n                    current_price: null,\\n                    liquidation_price: null,\\n                    unrealized_pnl: null,\\n                    leverage: null,\\n                    exit_plan: null,\\n                    confidence: null,\\n                    risk_usd: risk_usd,\\n                    sl_oid: null,\\n                    tp_oid: null,\\n                    wait_for_fill: false,\\n                    entry_oid: null,\\n                    notional_usd: null\\n                });\\n            }\\n        } else {\\n            // 没有持仓的情况 - 返回固定字段为null\\n            allPositions.push({\\n                symbol: coin,\\n                quantity: null,\\n                entry_price: null,\\n                current_price: null,\\n                liquidation_price: null,\\n                unrealized_pnl: null,\\n                leverage: null,\\n                exit_plan: null,\\n                confidence: null,\\n                risk_usd: risk_usd,  // 仍然返回risk_usd\\n                sl_oid: null,\\n                tp_oid: null,\\n                wait_for_fill: false,\\n                entry_oid: null,\\n                notional_usd: null\\n            });\\n        }\\n    }\\n    \\n    return allPositions;\\n}\\n\\nconst positions = getAllPositions();\\nreturn {positions};\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[880,352],\"id\":\"a93895c7-6769-4e1f-bd99-6013ff55ed96\",\"name\":\"持仓数据获取\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"// 获取输入数据\\nconst inputData = $input.all();\\n\\n// 第一个输入是市场数据,第二个是持仓数据\\nconst marketData = inputData[0].json.data;\\nconst positions = inputData[1].json;\\nconst performances = inputData[2].json;\\n\\n// 返回整理后的数据\\nreturn [{\\n  json: {\\n    marketData: marketData,\\n    positions: positions,\\n    performances: performances\\n  }\\n}];\\n\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[1360,352],\"id\":\"4d997250-774c-4ac0-9b51-ddbf098e4f55\",\"name\":\"数据合并\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"// ========== 精简版交易执行系统 - 专注核心交易功能 ==========\\n// 功能:解析AI信号、执行交易、历史记录管理(无可视化)\\n\\n// ========== 配置参数 ==========\\nconst CONFIG = {\\n    // 交易参数\\n    MAX_POSITIONS: 6,           // 最大持仓数量\\n    MIN_CONFIDENCE: $vars.signalConfidence,        // 最小置信度要求\\n    DEFAULT_LEVERAGE: 10,       // 默认杠杆\\n    MAX_LEVERAGE: 20,           // 最大杠杆\\n    \\n    // 风险管理\\n    MAX_RISK_PER_TRADE: 1000,   // 单笔最大风险\\n    MAX_TOTAL_RISK: 5000,       // 总最大风险\\n};\\n\\n// ========== 工具函数 ==========\\n\\n/**\\n * 超强容错JSON解析 - 逐个提取决策对象\\n */\\nfunction parseAIOutput(output) {\\n    try {\\n        Log('📥 开始解析AI输出...');\\n        \\n        // 清理输出格式\\n        let cleaned = output.replace(/```[a-z]*\\\\n?/gi, '').trim();\\n        \\n        // 方法1:尝试标准JSON解析\\n        try {\\n            const standardResult = parseStandardJson(cleaned);\\n            if (standardResult.length > 0) {\\n                Log(`✅ 标准JSON解析成功,获得 ${standardResult.length} 个信号`);\\n                return standardResult;\\n            }\\n        } catch (e) {\\n            Log(`⚠️ 标准JSON解析失败: ${e.message}`);\\n        }\\n        \\n        // 方法2:逐个提取决策对象\\n        try {\\n            const extractResult = extractDecisionObjects(cleaned);\\n            if (extractResult.length > 0) {\\n                Log(`✅ 对象提取解析成功,获得 ${extractResult.length} 个信号`);\\n                return extractResult;\\n            }\\n        } catch (e) {\\n            Log(`⚠️ 对象提取解析失败: ${e.message}`);\\n        }\\n        \\n        // 方法3:正则表达式提取\\n        try {\\n            const regexResult = extractWithRegex(cleaned);\\n            if (regexResult.length > 0) {\\n                Log(`✅ 正则表达式解析成功,获得 ${regexResult.length} 个信号`);\\n                return regexResult;\\n            }\\n        } catch (e) {\\n            Log(`⚠️ 正则表达式解析失败: ${e.message}`);\\n        }\\n        \\n        // 方法4:关键词提取(最后手段)\\n        try {\\n            const keywordResult = extractWithKeywords(cleaned);\\n            if (keywordResult.length > 0) {\\n                Log(`✅ 关键词解析成功,获得 ${keywordResult.length} 个信号`);\\n                return keywordResult;\\n            }\\n        } catch (e) {\\n            Log(`⚠️ 关键词解析失败: ${e.message}`);\\n        }\\n        \\n        Log('❌ 所有解析方法都失败了');\\n        return [];\\n        \\n    } catch (e) {\\n        Log(`❌ parseAIOutput总体失败: ${e.message}`);\\n        return [];\\n    }\\n}\\n\\n/**\\n * 方法1:标准JSON解析(修复版)\\n */\\nfunction parseStandardJson(text) {\\n    const jsonStart = text.indexOf('{');\\n    const jsonEnd = text.lastIndexOf('}');\\n    \\n    if (jsonStart === -1 || jsonEnd === -1 || jsonEnd <= jsonStart) {\\n        throw new Error('找不到JSON结构');\\n    }\\n    \\n    let jsonStr = text.substring(jsonStart, jsonEnd + 1);\\n    \\n    // 修复常见JSON问题\\n    jsonStr = fixCommonJsonIssues(jsonStr);\\n    \\n    const parsed = JSON.parse(jsonStr);\\n    \\n    if (parsed.decisions && Array.isArray(parsed.decisions)) {\\n        return parsed.decisions.filter(d => d.signal && d.coin);\\n    } else if (parsed.signal && parsed.coin) {\\n        return [parsed];\\n    }\\n    \\n    return [];\\n}\\n\\n/**\\n * 方法2:逐个提取决策对象\\n */\\nfunction extractDecisionObjects(text) {\\n    const decisions = [];\\n    \\n    // 查找所有独立的决策对象\\n    const decisionPattern = /\\\\{\\\\s*\\\"signal\\\"[^}]*\\\"coin\\\"[^}]*\\\\}/g;\\n    let match;\\n    \\n    while ((match = decisionPattern.exec(text)) !== null) {\\n        try {\\n            let decisionStr = match[0];\\n            \\n            // 修复这个单独的对象\\n            decisionStr = fixCommonJsonIssues(decisionStr);\\n            \\n            const decision = JSON.parse(decisionStr);\\n            \\n            // 验证必要字段\\n            if (decision.signal && decision.coin) {\\n                // 补充缺失字段\\n                if (!decision.confidence) decision.confidence = 0.5;\\n                if (!decision.leverage) decision.leverage = 1;\\n                if (!decision.risk_usd) decision.risk_usd = 100;\\n                if (!decision.profit_target) decision.profit_target = 0;\\n                if (!decision.stop_loss) decision.stop_loss = 0;\\n                if (!decision.justification) decision.justification = '从部分数据恢复';\\n                \\n                decisions.push(decision);\\n                Log(`✅ 提取到决策: ${decision.coin} - ${decision.signal}`);\\n            }\\n        } catch (e) {\\n            Log(`⚠️ 解析单个决策对象失败: ${e.message}`);\\n            continue;\\n        }\\n    }\\n    \\n    return decisions;\\n}\\n\\n/**\\n * 方法3:正则表达式提取关键信息\\n */\\nfunction extractWithRegex(text) {\\n    const decisions = [];\\n    \\n    // 更灵活的正则模式\\n    const patterns = [\\n        // 模式1:完整信息\\n        /\\\"signal\\\":\\\\s*\\\"([^\\\"]+)\\\"[^}]*\\\"coin\\\":\\\\s*\\\"([^\\\"]+)\\\"[^}]*\\\"confidence\\\":\\\\s*([0-9.]+)[^}]*\\\"leverage\\\":\\\\s*([0-9]+)[^}]*\\\"profit_target\\\":\\\\s*([0-9.]+)[^}]*\\\"stop_loss\\\":\\\\s*([0-9.]+)[^}]*\\\"risk_usd\\\":\\\\s*([0-9.]+)/g,\\n        \\n        // 模式2:基本信息\\n        /\\\"coin\\\":\\\\s*\\\"([^\\\"]+)\\\"[^}]*\\\"signal\\\":\\\\s*\\\"([^\\\"]+)\\\"[^}]*\\\"confidence\\\":\\\\s*([0-9.]+)/g,\\n        \\n        // 模式3:最简信息\\n        /\\\"coin\\\":\\\\s*\\\"([^\\\"]+)\\\"[^}]*\\\"signal\\\":\\\\s*\\\"([^\\\"]+)\\\"/g\\n    ];\\n    \\n    for (let i = 0; i < patterns.length; i++) {\\n        const pattern = patterns[i];\\n        let match;\\n        \\n        while ((match = pattern.exec(text)) !== null) {\\n            let decision;\\n            \\n            if (i === 0) {\\n                // 完整信息\\n                decision = {\\n                    signal: match[1],\\n                    coin: match[2],\\n                    confidence: parseFloat(match[3]) || 0.5,\\n                    leverage: parseInt(match[4]) || 1,\\n                    profit_target: parseFloat(match[5]) || 0,\\n                    stop_loss: parseFloat(match[6]) || 0,\\n                    risk_usd: parseFloat(match[7]) || 100,\\n                    justification: \\\"正则提取完整信息\\\"\\n                };\\n            } else if (i === 1) {\\n                // 基本信息\\n                decision = {\\n                    signal: match[2],\\n                    coin: match[1],\\n                    confidence: parseFloat(match[3]) || 0.5,\\n                    leverage: 1,\\n                    profit_target: 0,\\n                    stop_loss: 0,\\n                    risk_usd: 100,\\n                    justification: \\\"正则提取基本信息\\\"\\n                };\\n            } else {\\n                // 最简信息\\n                decision = {\\n                    signal: match[2],\\n                    coin: match[1],\\n                    confidence: 0.5,\\n                    leverage: 1,\\n                    profit_target: 0,\\n                    stop_loss: 0,\\n                    risk_usd: 100,\\n                    justification: \\\"正则提取最简信息\\\"\\n                };\\n            }\\n            \\n            // 避免重复\\n            if (!decisions.find(d => d.coin === decision.coin)) {\\n                decisions.push(decision);\\n                Log(`✅ 正则提取: ${decision.coin} - ${decision.signal}`);\\n            }\\n        }\\n        \\n        // 如果找到了信号,就不尝试下一个模式\\n        if (decisions.length > 0) break;\\n    }\\n    \\n    return decisions;\\n}\\n\\n/**\\n * 方法4:关键词提取(最后手段)\\n */\\nfunction extractWithKeywords(text) {\\n    const decisions = [];\\n    const lines = text.split('\\\\n');\\n    \\n    let currentDecision = null;\\n    \\n    for (let line of lines) {\\n        line = line.trim();\\n        \\n        // 查找coin信息\\n        const coinMatch = line.match(/[\\\"']coin[\\\"']:\\\\s*[\\\"']([A-Z]+)[\\\"']/i);\\n        if (coinMatch) {\\n            if (currentDecision) {\\n                decisions.push(currentDecision);\\n            }\\n            currentDecision = {\\n                coin: coinMatch[1],\\n                signal: 'hold',\\n                confidence: 0.5,\\n                leverage: 1,\\n                profit_target: 0,\\n                stop_loss: 0,\\n                risk_usd: 100,\\n                justification: \\\"关键词提取\\\"\\n            };\\n        }\\n        \\n        // 查找signal信息\\n        const signalMatch = line.match(/[\\\"']signal[\\\"']:\\\\s*[\\\"'](buy_to_enter|sell_to_enter|close|hold)[\\\"']/i);\\n        if (signalMatch && currentDecision) {\\n            currentDecision.signal = signalMatch[1];\\n        }\\n        \\n        // 查找confidence信息\\n        const confidenceMatch = line.match(/[\\\"']confidence[\\\"']:\\\\s*([0-9.]+)/i);\\n        if (confidenceMatch && currentDecision) {\\n            currentDecision.confidence = parseFloat(confidenceMatch[1]);\\n        }\\n        \\n        // 查找其他数值信息\\n        const leverageMatch = line.match(/[\\\"']leverage[\\\"']:\\\\s*([0-9]+)/i);\\n        if (leverageMatch && currentDecision) {\\n            currentDecision.leverage = parseInt(leverageMatch[1]);\\n        }\\n        \\n        const profitMatch = line.match(/[\\\"']profit_target[\\\"']:\\\\s*([0-9.]+)/i);\\n        if (profitMatch && currentDecision) {\\n            currentDecision.profit_target = parseFloat(profitMatch[1]);\\n        }\\n        \\n        const stopMatch = line.match(/[\\\"']stop_loss[\\\"']:\\\\s*([0-9.]+)/i);\\n        if (stopMatch && currentDecision) {\\n            currentDecision.stop_loss = parseFloat(stopMatch[1]);\\n        }\\n        \\n        const riskMatch = line.match(/[\\\"']risk_usd[\\\"']:\\\\s*([0-9.]+)/i);\\n        if (riskMatch && currentDecision) {\\n            currentDecision.risk_usd = parseFloat(riskMatch[1]);\\n        }\\n    }\\n    \\n    // 添加最后一个决策\\n    if (currentDecision) {\\n        decisions.push(currentDecision);\\n    }\\n    \\n    return decisions.filter(d => d.coin && d.signal);\\n}\\n\\n/**\\n * 修复常见JSON问题\\n */\\nfunction fixCommonJsonIssues(jsonStr) {\\n    // 1. 修复属性名缺少引号\\n    jsonStr = jsonStr.replace(/([{,]\\\\s*)([a-zA-Z_][a-zA-Z0-9_]*)\\\\s*:/g, '$1\\\"$2\\\":');\\n    \\n    // 2. 修复单引号\\n    jsonStr = jsonStr.replace(/'/g, '\\\"');\\n    \\n    // 3. 修复尾随逗号\\n    jsonStr = jsonStr.replace(/,(\\\\s*[}\\\\]])/g, '$1');\\n    \\n    // 4. 修复多余的引号\\n    jsonStr = jsonStr.replace(/\\\"{2,}/g, '\\\"');\\n    \\n    // 5. 修复数字前的多余引号\\n    jsonStr = jsonStr.replace(/\\\"([0-9.]+)\\\"/g, '$1');\\n    \\n    // 6. 确保字符串值有引号\\n    jsonStr = jsonStr.replace(/:\\\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\\\s*([,}])/g, ': \\\"$1\\\"$2');\\n    \\n    // 7. 修复布尔值\\n    jsonStr = jsonStr.replace(/:\\\\s*\\\"(true|false|null)\\\"\\\\s*([,}])/g, ': $1$2');\\n    \\n    return jsonStr;\\n}\\n\\n/**\\n * 获取交易对精度信息 - 包含合约面值\\n */\\nfunction getPrecision(coin) {\\n    try {\\n        const symbol = coin + '_USDT.swap';\\n        \\n        const markets = _G('markets');\\n        \\n        if (markets && markets[symbol]) {\\n            const market = markets[symbol];\\n            \\n            return {\\n                price: market.PricePrecision,\\n                amount: market.AmountPrecision,\\n                minQty: market.MinQty,\\n                maxQty: market.MaxQty,\\n                tickSize: market.TickSize,\\n                amountSize: market.AmountSize,\\n                minNotional: market.MinNotional,\\n                ctVal: market.CtVal,  // 合约面值\\n                symbol: symbol\\n            };\\n        }\\n        \\n        // 如果未找到市场信息,返回 null 或默认值\\n        Log(`⚠️ 未找到${symbol}的市场信息`);\\n        return null;\\n        \\n    } catch (e) {\\n        Log(`⚠️ 获取${coin}精度失败: ${e.message}`);\\n        return null;\\n    }\\n}\\n\\n/**\\n * 计算交易数量 - 修复版,支持合约面值\\n */\\nfunction calculateQuantity(entryPrice, stopLoss, riskUsd, leverage, precision) {\\n    try {\\n        // 1. 计算止损百分比\\n        const stopLossPercent = Math.abs(entryPrice - stopLoss) / entryPrice;\\n        \\n        if (stopLossPercent <= 0 || stopLossPercent > 0.5) {\\n            Log(`⚠️ 止损百分比异常: ${(stopLossPercent * 100).toFixed(2)}%`);\\n            return 0;\\n        }\\n        \\n        // 2. 计算仓位价值(基于风险金额)\\n        // 公式:仓位价值 = 风险金额 / 止损百分比\\n        const positionValue = riskUsd / stopLossPercent;\\n        \\n        // 3. 计算币的数量\\n        // 公式:币数量 = 仓位价值 / 入场价格\\n        let coinQuantity = positionValue / entryPrice;\\n        \\n        // 4. 转换为合约张数\\n        // 公式:合约张数 = 币数量 / 合约面值\\n        let contractQuantity = coinQuantity / precision.ctVal;\\n        \\n        // 5. 考虑杠杆限制(账户资金约束)\\n        const account = exchange.GetAccount();\\n        const maxPositionValue = (account.Balance * leverage * 0.8); // 80%安全边际\\n        const maxCoinQuantity = maxPositionValue / entryPrice;\\n        const maxContractQuantity = maxCoinQuantity / precision.ctVal;\\n        \\n        contractQuantity = Math.min(contractQuantity, maxContractQuantity);\\n        \\n        // 6. 应用精度\\n        contractQuantity = _N(contractQuantity, precision.amount);\\n        \\n        // 7. 检查最小数量\\n        const minContracts = precision.minQty;\\n        if (contractQuantity < minContracts) {\\n            Log(`⚠️ 计算合约张数 ${contractQuantity} 小于最小要求 ${minContracts}`);\\n            return 0;\\n        }\\n        \\n        // 8. 检查最大数量\\n        const maxContracts = precision.maxQty;\\n        if (contractQuantity > maxContracts) {\\n            Log(`⚠️ 计算合约张数 ${contractQuantity} 超过最大限制 ${maxContracts}`);\\n            contractQuantity = maxContracts;\\n        }\\n        \\n        // 9. 验证实际风险和仓位价值\\n        const actualCoinQuantity = contractQuantity * precision.ctVal;\\n        const actualPositionValue = actualCoinQuantity * entryPrice;\\n        const actualRisk = actualPositionValue * stopLossPercent;\\n        \\n        // 10. 二次风险检查\\n        if (actualRisk > CONFIG.MAX_RISK_PER_TRADE) {\\n            Log(`⚠️ 实际风险 $${actualRisk.toFixed(2)} 超过最大风险 $${CONFIG.MAX_RISK_PER_TRADE}`);\\n            const adjustedPositionValue = CONFIG.MAX_RISK_PER_TRADE / stopLossPercent;\\n            const adjustedCoinQuantity = adjustedPositionValue / entryPrice;\\n            contractQuantity = adjustedCoinQuantity / precision.ctVal;\\n            contractQuantity = _N(contractQuantity, precision.amount);\\n        }\\n        \\n        // 11. 记录计算详情\\n        Log(`💡 ${entryPrice}价格 ${_N(actualRisk, 2)}风险 ${contractQuantity}张数`);\\n        \\n        return contractQuantity;\\n        \\n    } catch (e) {\\n        Log(`❌ 计算数量失败: ${e.message}`);\\n        return 0;\\n    }\\n}\\n\\n/**\\n * 验证入场条件\\n */\\nfunction validateEntry(coin, signal, currentPrice, profitTarget, stopLoss, confidence) {\\n    // 验证置信度\\n    if (confidence < CONFIG.MIN_CONFIDENCE) {\\n        Log(`⚠️ ${coin}: 置信度 ${confidence} 低于最小要求 ${CONFIG.MIN_CONFIDENCE}`);\\n        return false;\\n    }\\n    \\n    // 验证价格逻辑\\n    const isLong = signal === 'buy_to_enter';\\n    \\n    if (isLong) {\\n        if (profitTarget <= currentPrice) {\\n            Log(`⚠️ ${coin}: 多头止盈价 ${profitTarget} 应高于当前价 ${currentPrice}`);\\n            return false;\\n        }\\n        if (stopLoss >= currentPrice) {\\n            Log(`⚠️ ${coin}: 多头止损价 ${stopLoss} 应低于当前价 ${currentPrice}`);\\n            return false;\\n        }\\n    } else if (signal === 'sell_to_enter') {\\n        if (profitTarget >= currentPrice) {\\n            Log(`⚠️ ${coin}: 空头止盈价 ${profitTarget} 应低于当前价 ${currentPrice}`);\\n            return false;\\n        }\\n        if (stopLoss <= currentPrice) {\\n            Log(`⚠️ ${coin}: 空头止损价 ${stopLoss} 应高于当前价 ${currentPrice}`);\\n            return false;\\n        }\\n    }\\n    \\n    return true;\\n}\\n\\n/**\\n * 检查是否有持仓\\n */\\nfunction hasPosition(coin) {\\n    try {\\n        exchange.SetCurrency(coin + '_USDT');\\n        exchange.SetContractType(\\\"swap\\\");\\n        const positions = exchange.GetPositions();\\n        return positions && positions.some(p => p.Symbol.includes(coin) && Math.abs(p.Amount) > 0);\\n    } catch (e) {\\n        Log(`⚠️ 检查${coin}持仓失败: ${e.message}`);\\n        return false;\\n    }\\n}\\n\\n/**\\n * 保存交易记录\\n */\\nfunction saveTradeToHistory(orderDetail, signalInfo) {\\n    try {\\n        const currentTime = Date.now();\\n        \\n        // 提取币种名称\\n        const coinMatch = orderDetail.Symbol.match(/^([A-Z0-9]+)_USDT/);\\n        if (!coinMatch) {\\n            Log(`⚠️ 无法解析币种: ${orderDetail.Symbol}`);\\n            return;\\n        }\\n        const coin = coinMatch[1];\\n        \\n        // 构建交易记录\\n        const tradeRecord = {\\n            // 订单信息\\n            Id: orderDetail.Id,\\n            Price: orderDetail.Price,\\n            Amount: orderDetail.Amount,\\n            DealAmount: orderDetail.DealAmount,\\n            AvgPrice: orderDetail.AvgPrice,\\n            Status: orderDetail.Status,\\n            Type: orderDetail.Type,\\n            Offset: orderDetail.Offset,\\n            Symbol: orderDetail.Symbol,\\n            ContractType: orderDetail.ContractType,\\n            \\n            // AI信号信息\\n            aiSignal: signalInfo.signal,\\n            confidence: signalInfo.confidence,\\n            profitTarget: signalInfo.profit_target,\\n            stopLoss: signalInfo.stop_loss,\\n            leverage: signalInfo.leverage,\\n            riskUsd: signalInfo.risk_usd,\\n            justification: signalInfo.justification,\\n            \\n            // 时间戳\\n            time: currentTime,\\n            timeStr: new Date(currentTime).toISOString()\\n        };\\n        \\n        // 获取现有历史记录\\n        let tradesHistory = _G('tradesHistory') || {};\\n        \\n        // 初始化币种记录\\n        if (!tradesHistory[coin]) {\\n            tradesHistory[coin] = [];\\n        }\\n        \\n        // 添加记录\\n        tradesHistory[coin].push(tradeRecord);\\n        \\n        // 限制历史记录数量(每个币种最多保存1000条)\\n        if (tradesHistory[coin].length > 1000) {\\n            tradesHistory[coin] = tradesHistory[coin].slice(-1000);\\n        }\\n        \\n        // 保存\\n        _G('tradesHistory', tradesHistory);\\n        \\n        const typeStr = orderDetail.Type === 0 ? '买入' : '卖出';\\n        Log(`📝 ${coin} 交易记录已保存: ${typeStr} ${orderDetail.DealAmount} @ $${orderDetail.AvgPrice}`);\\n        \\n    } catch (e) {\\n        Log(`❌ 保存交易记录失败: ${e.message}`);\\n    }\\n}\\n\\n/**\\n * 保存退出计划\\n */\\nfunction saveExitPlan(coin, signalInfo) {\\n    try {\\n        const exitPlan = {\\n            profit_target: signalInfo.profit_target,\\n            stop_loss: signalInfo.stop_loss,\\n            invalidation_condition: signalInfo.invalidation_condition || \\\"\\\",\\n            confidence: signalInfo.confidence,\\n            risk_usd: signalInfo.risk_usd,\\n            leverage: signalInfo.leverage,\\n            timestamp: Date.now(),\\n            justification: signalInfo.justification\\n        };\\n        \\n        _G(`exit_plan_${coin}_USDT.swap`, exitPlan);\\n        Log(`💾 ${coin} 退出计划已保存`);\\n    } catch (e) {\\n        Log(`❌ 保存${coin}退出计划失败: ${e.message}`);\\n    }\\n}\\n\\n// ========== 交易执行函数 ==========\\n\\n/**\\n * 执行平仓\\n */\\nfunction executeClose(coin, reason = \\\"AI信号\\\") {\\n    try {\\n        exchange.SetCurrency(coin + '_USDT');\\n        exchange.SetContractType(\\\"swap\\\");\\n        \\n        // 取消所有未完成订单\\n        const orders = exchange.GetOrders();\\n        if (orders && orders.length > 0) {\\n            orders.forEach(o => {\\n                try {\\n                    exchange.CancelOrder(o.Id);\\n                } catch (e) {\\n                    Log(`⚠️ 取消订单失败: ${e.message}`);\\n                }\\n            });\\n        }\\n        \\n        // 查找持仓\\n        const positions = exchange.GetPositions();\\n        const pos = positions && positions.find(p => p.Symbol.includes(coin) && Math.abs(p.Amount) > 0);\\n        \\n        if (!pos) {\\n            Log(`⚠️ ${coin}: 未找到持仓`);\\n            return false;\\n        }\\n        \\n        const isLong = pos.Type === PD_LONG || pos.Type === 0;\\n        const precision = getPrecision(coin);\\n        const closeAmount = _N(Math.abs(pos.Amount), precision.amount);\\n        \\n        // 设置平仓方向\\n        exchange.SetDirection(isLong ? \\\"closebuy\\\" : \\\"closesell\\\");\\n        \\n        // 执行平仓\\n        const orderId = isLong ? exchange.Sell(-1, closeAmount) : exchange.Buy(-1, closeAmount);\\n        \\n        if (orderId) {\\n            const directionStr = isLong ? '多' : '空';\\n            Log(`✅ ${coin}: 平${directionStr}成功 (${reason}) 数量=${closeAmount}`);\\n            \\n            // 清除退出计划\\n            _G(`exit_plan_${coin}_USDT.swap`, null);\\n            \\n            // 获取订单详情并保存\\n            Sleep(1000);\\n            try {\\n                const orderDetail = exchange.GetOrder(orderId);\\n                if (orderDetail) {\\n                    saveTradeToHistory(orderDetail, { \\n                        signal: 'close', \\n                        confidence: 1.0, \\n                        justification: reason \\n                    });\\n                }\\n            } catch (e) {\\n                Log(`⚠️ 获取平仓订单详情失败: ${e.message}`);\\n            }\\n            \\n            return true;\\n        } else {\\n            Log(`❌ ${coin}: 平仓失败`);\\n            return false;\\n        }\\n    } catch (e) {\\n        Log(`❌ ${coin} 平仓执行失败: ${e.message}`);\\n        return false;\\n    }\\n}\\n\\n/**\\n * 执行开仓\\n */\\nfunction executeEntry(coin, signalInfo) {\\n    try {\\n        exchange.SetCurrency(coin + '_USDT');\\n        exchange.SetContractType(\\\"swap\\\");\\n        \\n        // 获取当前价格\\n        const ticker = exchange.GetTicker();\\n        if (!ticker) {\\n            Log(`❌ ${coin}: 无法获取价格信息`);\\n            return false;\\n        }\\n        \\n        const currentPrice = ticker.Last;\\n        const isLong = signalInfo.signal === 'buy_to_enter';\\n        \\n        // 验证入场条件\\n        if (!validateEntry(coin, signalInfo.signal, currentPrice, signalInfo.profit_target, signalInfo.stop_loss, signalInfo.confidence)) {\\n            return false;\\n        }\\n        \\n        // 设置杠杆\\n        const leverage = Math.min(signalInfo.leverage || CONFIG.DEFAULT_LEVERAGE, CONFIG.MAX_LEVERAGE);\\n        exchange.SetMarginLevel(leverage);\\n        \\n        // 获取精度信息\\n        const precision = getPrecision(coin);\\n        \\n        // 计算数量\\n        const quantity = calculateQuantity(\\n            currentPrice, \\n            signalInfo.stop_loss, \\n            signalInfo.risk_usd, \\n            leverage, \\n            precision\\n        );\\n        \\n        if (quantity <= 0) {\\n            Log(`⚠️ ${coin}: 计算数量无效,跳过开仓`);\\n            return false;\\n        }\\n        \\n        // 设置交易方向\\n        exchange.SetDirection(isLong ? \\\"buy\\\" : \\\"sell\\\");\\n        \\n        // 执行开仓\\n        const orderId = isLong ? exchange.Buy(-1, quantity) : exchange.Sell(-1, quantity);\\n        \\n        if (orderId) {\\n            const directionStr = isLong ? '多' : '空';\\n            Log(`✅ ${coin}: 开${directionStr}成功 数量=${quantity} 杠杆=${leverage}x 风险=$${signalInfo.risk_usd} 置信度=${signalInfo.confidence}`);\\n            \\n            // 保存退出计划\\n            saveExitPlan(coin, signalInfo);\\n            \\n            // 获取订单详情并保存\\n            Sleep(1000);\\n            try {\\n                const orderDetail = exchange.GetOrder(orderId);\\n                if (orderDetail) {\\n                    saveTradeToHistory(orderDetail, signalInfo);\\n                }\\n            } catch (e) {\\n                Log(`⚠️ 获取开仓订单详情失败: ${e.message}`);\\n            }\\n            \\n            return true;\\n        } else {\\n            Log(`❌ ${coin}: 开仓失败`);\\n            return false;\\n        }\\n    } catch (e) {\\n        Log(`❌ ${coin} 开仓执行失败: ${e.message}`);\\n        return false;\\n    }\\n}\\n\\n// ========== 主执行逻辑 ==========\\n\\nfunction main() {\\n    try {\\n        // 获取AI输出\\n        const aiOutput = $input.first().json.output;\\n        Log('调试aiOutput:', aiOutput);\\n        \\n        const signals = parseAIOutput(aiOutput);\\n      \\n        _G('AISinnal', signals)\\n        \\n        Log('🤖 AI信号解析结果:', signals);\\n        \\n        // 如果没有有效信号,退出\\n        if (!signals || signals.length === 0) {\\n            Log('⚠️ 未获取到有效的AI交易信号');\\n            \\n            // 保存空的执行结果\\n            _G('latestExecutionResults', {\\n                results: {},\\n                timestamp: Date.now(),\\n                totalSignals: 0,\\n                totalExecutions: 0,\\n                note: 'No valid signals'\\n            });\\n            \\n            return { json: { processed: false, reason: 'No valid signals' } };\\n        }\\n        \\n        // 执行交易信号\\n        const executionResults = {};\\n        let totalExecutions = 0;\\n        \\n        // 处理每个币种的信号\\n        for (let i = 0; i < signals.length; i++) {\\n            const signalInfo = signals[i];\\n            const coin = signalInfo.coin;\\n            const signal = signalInfo.signal;\\n            \\n            if (!coin || !signal) {\\n                Log(`⚠️ 跳过无效信号: ${JSON.stringify(signalInfo)}`);\\n                continue;\\n            }\\n            \\n            Log(`🎯 处理 ${coin} 的 ${signal} 信号`);\\n            \\n            const hasPos = hasPosition(coin);\\n            let executed = false;\\n            let skipReason = '';\\n            \\n            // 根据信号类型执行操作\\n            switch (signal) {\\n                case 'buy_to_enter':\\n                case 'sell_to_enter':\\n                    if (hasPos) {\\n                        skipReason = '已有持仓';\\n                    } else {\\n                        executed = executeEntry(coin, signalInfo);\\n                        if (executed) totalExecutions++;\\n                    }\\n                    break;\\n                    \\n                case 'close':\\n                    if (!hasPos) {\\n                        skipReason = '无持仓';\\n                    } else {\\n                        executed = executeClose(coin, 'AI信号');\\n                        if (executed) totalExecutions++;\\n                    }\\n                    break;\\n                    \\n                case 'hold':\\n                    skipReason = hasPos ? '持仓观望' : '空仓等待';\\n                    break;\\n                    \\n                default:\\n                    skipReason = '未知信号';\\n            }\\n            \\n            // 记录执行结果\\n            executionResults[coin] = {\\n                signal: signal,\\n                executed: executed,\\n                skipReason: skipReason,\\n                confidence: signalInfo.confidence || 0,\\n                timestamp: Date.now(),\\n                hasPosition: hasPos,\\n                // 添加更多执行细节\\n                leverage: signalInfo.leverage || 0,\\n                risk_usd: signalInfo.risk_usd || 0,\\n                profit_target: signalInfo.profit_target || 0,\\n                stop_loss: signalInfo.stop_loss || 0,\\n                justification: signalInfo.justification || ''\\n            };\\n            \\n            // 避免请求过于频繁\\n            Sleep(500);\\n        }\\n        \\n        // ===== 保存执行结果到_G =====\\n        const executionSummary = {\\n            results: executionResults,\\n            timestamp: Date.now(),\\n            totalSignals: signals.length,\\n            totalExecutions: totalExecutions,\\n            // 统计信息\\n            stats: {\\n                executed: Object.values(executionResults).filter(r => r.executed).length,\\n                skipped: Object.values(executionResults).filter(r => !r.executed && r.skipReason).length,\\n                failed: Object.values(executionResults).filter(r => !r.executed && !r.skipReason).length,\\n                holds: Object.values(executionResults).filter(r => r.signal === 'hold').length,\\n                entries: Object.values(executionResults).filter(r => ['buy_to_enter', 'sell_to_enter'].includes(r.signal)).length,\\n                closes: Object.values(executionResults).filter(r => r.signal === 'close').length\\n            }\\n        };\\n        \\n        _G('latestExecutionResults', executionSummary);\\n        \\n        Log(`💾 执行结果已保存到全局存储`);\\n        Log(`📊 执行总结: 处理了 ${signals.length} 个信号,执行了 ${totalExecutions} 个操作`);\\n        \\n        // 详细输出执行结果\\n        Object.entries(executionResults).forEach(([coin, result]) => {\\n            if (result.executed) {\\n                Log(`✅ ${coin}: ${result.signal} 执行成功 (置信度: ${(result.confidence * 100).toFixed(0)}%)`);\\n            } else if (result.skipReason) {\\n                Log(`⏭️ ${coin}: ${result.signal} 跳过执行 - ${result.skipReason}`);\\n            } else {\\n                Log(`❌ ${coin}: ${result.signal} 执行失败`);\\n            }\\n        });\\n        \\n        return { \\n            json: { \\n                processed: true, \\n                totalSignals: signals.length,\\n                totalExecutions: totalExecutions,\\n                results: executionResults,\\n                summary: executionSummary.stats\\n            } \\n        };\\n        \\n    } catch (e) {\\n        Log(`❌ 主执行流程失败: ${e.message}`);\\n        Log(`❌ 错误堆栈: ${e.stack}`);\\n        \\n        // 即使出错也保存错误信息\\n        _G('latestExecutionResults', {\\n            results: {},\\n            timestamp: Date.now(),\\n            totalSignals: 0,\\n            totalExecutions: 0,\\n            error: e.message,\\n            note: 'Execution failed'\\n        });\\n        \\n        return { json: { processed: false, error: e.message } };\\n    }\\n}\\n\\n// 执行主函数\\nreturn main();\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[1920,352],\"id\":\"80ec983c-9701-443d-bc05-43a807a3fff5\",\"name\":\"交易执行\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"function analyzePerformance(orders, coin) {\\n    if (!orders || orders.length === 0) return { coin, totalTrades: 0, message: 'No stored trade records' }\\n    \\n    const filteredOrders = orders.filter(o => o.Status === 1)\\n    const validOrders = filteredOrders.sort((a, b) => a.time - b.time)\\n    \\n    if (validOrders.length === 0) return { coin, totalTrades: 0}\\n    \\n    // 获取合约规格信息\\n    function getContractSpec(coinSymbol) {\\n        try {\\n            const markets = _G('markets');\\n            const symbol = coinSymbol + '_USDT.swap';\\n            \\n            if (markets && markets[symbol]) {\\n                const ctVal = markets[symbol].CtVal || 1; // 合约面值,默认为1\\n                return ctVal;\\n            } else {\\n                return 1;\\n            }\\n        } catch (e) {\\n            return 1;\\n        }\\n    }\\n    \\n    // 提取币种名称 (BTC_USDT.swap -> BTC)\\n    const coinMatch = coin.match(/^([A-Z0-9]+)_USDT/);\\n    const coinName = coinMatch ? coinMatch[1] : coin;\\n    \\n    // 获取该币种的合约面值\\n    const ctVal = getContractSpec(coinName);\\n    \\n    let trades = []\\n    let positions = [] // 未平仓位\\n    \\n    for (let order of validOrders) {\\n        // 注意:从_G('tradesHistory')读取的数据结构\\n        const { Type: type, DealAmount: amount, AvgPrice: price, time, Id: id } = order\\n        \\n        // 查找相反方向的仓位进行配对\\n        let matched = false\\n        let remaining = amount\\n        \\n        for (let i = 0; i < positions.length && remaining > 0.0001; i++) {\\n            const pos = positions[i]\\n            \\n            // 检查是否可以配对:买卖方向相反\\n            if ((type === 0 && pos.type === 1) || (type === 1 && pos.type === 0)) {\\n                const tradeAmount = Math.min(remaining, pos.amount)\\n                const holdTime = time - pos.time\\n                \\n                // 修正的利润计算:考虑合约面值\\n                let profit, direction\\n                if (pos.type === 0) { // 之前买入开仓,现在卖出平仓\\n                    // 多头利润 = (平仓价 - 开仓价) * 合约张数 * 合约面值\\n                    profit = (price - pos.price) * tradeAmount * ctVal\\n                    direction = 'LONG'\\n                } else { // 之前卖出开仓,现在买入平仓\\n                    // 空头利润 = (开仓价 - 平仓价) * 合约张数 * 合约面值\\n                    profit = (pos.price - price) * tradeAmount * ctVal\\n                    direction = 'SHORT'\\n                }\\n                \\n                \\n                trades.push({\\n                    direction,\\n                    openPrice: pos.price,\\n                    closePrice: price,\\n                    amount: tradeAmount,\\n                    profit,\\n                    holdTime: holdTime,\\n                    openOrderId: pos.id,\\n                    closeOrderId: id,\\n                    ctVal: ctVal,  // 记录合约面值用于验证\\n                    closeTime: time  // 添加平仓时间用于计算连续亏损\\n                })\\n                \\n                // 更新仓位\\n                pos.amount -= tradeAmount\\n                remaining -= tradeAmount\\n                matched = true\\n                \\n                // 如果仓位完全平仓,移除\\n                if (pos.amount <= 0.0001) {\\n                    positions.splice(i, 1)\\n                    i-- // 调整索引\\n                }\\n            }\\n        }\\n        \\n        // 如果还有剩余数量,作为新开仓\\n        if (remaining > 0.0001) {\\n            positions.push({\\n                type: type,\\n                price: price,\\n                amount: remaining,\\n                time: time,\\n                id: id\\n            })\\n        }\\n    }\\n    \\n    if (trades.length === 0) return { \\n        coin, \\n        totalTrades: 0, \\n        openPositions: positions.length,\\n        totalOrders: validOrders.length,\\n        ctVal: ctVal,  // 返回合约面值信息\\n        consecutiveLosses: 0,\\n        freezeStatus: 'free'\\n    }\\n    \\n    // 按平仓时间排序交易记录,确保时间顺序正确\\n    trades.sort((a, b) => a.closeTime - b.closeTime)\\n    \\n    // ======= 修改:计算最近4小时内的连续亏损次数 =======\\n    function calculateRecentConsecutiveLosses(tradesArray) {\\n        const currentTime = Date.now()\\n        const fourHoursAgo = currentTime - (4 * 60 * 60 * 1000) // 4小时前的时间戳\\n        \\n        // 筛选出最近4小时内的交易\\n        const recentTrades = tradesArray.filter(trade => trade.closeTime >= fourHoursAgo)\\n        \\n        if (recentTrades.length === 0) {\\n            return 0 // 最近4小时没有交易\\n        }\\n        \\n        // 按时间排序(确保时间顺序正确)\\n        recentTrades.sort((a, b) => a.closeTime - b.closeTime)\\n        \\n        let consecutiveLosses = 0\\n        // 从最后一笔交易开始往前计算连续亏损\\n        for (let i = recentTrades.length - 1; i >= 0; i--) {\\n            if (recentTrades[i].profit <= 0) {\\n                consecutiveLosses++\\n            } else {\\n                break  // 遇到盈利交易就停止计算\\n            }\\n        }\\n        \\n        Log(`💡 ${coinName} 最近4小时内交易: ${recentTrades.length} 笔, 连续亏损: ${consecutiveLosses} 次`)\\n        return consecutiveLosses\\n    }\\n    \\n    const consecutiveLosses = calculateRecentConsecutiveLosses(trades)\\n    \\n    // 冷却机制判断 - 基于最近4小时的连续亏损\\n    const currentTime = Date.now()\\n    let freezeStatus = 'free'\\n    let freezeStartTime = null\\n    let freezeEndTime = null\\n    \\n    if (consecutiveLosses > 2) {\\n        // 检查是否已经在冷却期\\n        const frozenData = _G(`frozen_${coinName}`)\\n        \\n        if (frozenData && frozenData.freezeEndTime > currentTime) {\\n            // 仍在冷却期\\n            freezeStatus = 'frozen'\\n            freezeStartTime = frozenData.freezeStartTime\\n            freezeEndTime = frozenData.freezeEndTime\\n            Log(`🧊 ${coinName} 仍在冷却期,剩余 ${((freezeEndTime - currentTime) / (1000 * 60 * 60)).toFixed(2)} 小时`)\\n        } else {\\n            // 检查是否是新的连续亏损(防止重复冷却)\\n            const lastTriggerLosses = frozenData ? frozenData.triggerLosses : 0\\n            \\n            if (consecutiveLosses > lastTriggerLosses || !frozenData) {\\n                // 新的冷却期开始\\n                freezeStatus = 'frozen'\\n                freezeStartTime = currentTime\\n                freezeEndTime = currentTime + (4 * 60 * 60 * 1000)  // 4小时后解冻\\n                \\n                // 保存冷却信息\\n                _G(`frozen_${coinName}`, {\\n                    freezeStartTime: freezeStartTime,\\n                    freezeEndTime: freezeEndTime,\\n                    triggerLosses: consecutiveLosses,\\n                    triggerTime: currentTime\\n                })\\n                \\n                Log(`🧊 ${coinName} 进入冷却期: 最近4小时连续亏损 ${consecutiveLosses} 次,4小时后解冻`)\\n            } else {\\n                // 连续亏损次数没有增加,保持解冻状态\\n                freezeStatus = 'free'\\n                _G(`frozen_${coinName}`, null)\\n                Log(`✅ ${coinName} 冷却期已过期,解除冻结`)\\n            }\\n        }\\n    } else {\\n        // 连续亏损次数不足,清除冷却记录\\n        const frozenData = _G(`frozen_${coinName}`)\\n        if (frozenData && frozenData.freezeEndTime <= currentTime) {\\n            _G(`frozen_${coinName}`, null)\\n            Log(`✅ ${coinName} 最近4小时连续亏损仅 ${consecutiveLosses} 次,解除冻结`)\\n        } else if (!frozenData) {\\n            // 没有冷却记录,保持自由状态\\n            freezeStatus = 'free'\\n        } else {\\n            // 仍在冷却期但连续亏损已减少,继续冷却直到时间到期\\n            freezeStatus = 'frozen'\\n            freezeStartTime = frozenData.freezeStartTime\\n            freezeEndTime = frozenData.freezeEndTime\\n        }\\n    }\\n    \\n    const wins = trades.filter(t => t.profit > 0)\\n    const losses = trades.filter(t => t.profit <= 0)\\n    const longTrades = trades.filter(t => t.direction === 'LONG')\\n    const shortTrades = trades.filter(t => t.direction === 'SHORT')\\n    \\n    // 多仓统计\\n    const longWins = longTrades.filter(t => t.profit > 0)\\n    const longLosses = longTrades.filter(t => t.profit <= 0)\\n    const longWinProfit = longWins.reduce((sum, t) => sum + t.profit, 0)\\n    const longLossProfit = Math.abs(longLosses.reduce((sum, t) => sum + t.profit, 0))\\n    \\n    // 空仓统计\\n    const shortWins = shortTrades.filter(t => t.profit > 0)\\n    const shortLosses = shortTrades.filter(t => t.profit <= 0)\\n    const shortWinProfit = shortWins.reduce((sum, t) => sum + t.profit, 0)\\n    const shortLossProfit = Math.abs(shortLosses.reduce((sum, t) => sum + t.profit, 0))\\n    \\n    const totalProfit = trades.reduce((sum, t) => sum + t.profit, 0)\\n    const totalWinProfit = wins.reduce((sum, t) => sum + t.profit, 0)\\n    const totalLossProfit = Math.abs(losses.reduce((sum, t) => sum + t.profit, 0))\\n    const winRate = (wins.length / trades.length * 100)\\n    \\n    \\n    const result = {\\n        coin,\\n        totalTrades: trades.length,\\n        totalOrders: validOrders.length,\\n        openPositions: positions.length,\\n        totalProfit: parseFloat(totalProfit.toFixed(2)),\\n        winRate: parseFloat(winRate.toFixed(2)),\\n        winCount: wins.length,\\n        lossCount: losses.length,\\n        avgProfit: parseFloat((totalProfit / trades.length).toFixed(2)),\\n        maxProfit: wins.length > 0 ? parseFloat(Math.max(...wins.map(t => t.profit)).toFixed(2)) : 0,\\n        maxLoss: parseFloat(Math.min(...trades.map(t => t.profit)).toFixed(2)),\\n        \\n        // 盈亏比\\n        profitLossRatio: totalLossProfit > 0 ? parseFloat((totalWinProfit / totalLossProfit).toFixed(2)) : (totalWinProfit > 0 ? 999 : 0),\\n        \\n        // 多仓统计\\n        longWinCount: longWins.length,\\n        longLossCount: longLosses.length,\\n        longWinProfit: parseFloat(longWinProfit.toFixed(2)),\\n        longLossProfit: parseFloat(longLossProfit.toFixed(2)),\\n        \\n        // 空仓统计  \\n        shortWinCount: shortWins.length,\\n        shortLossCount: shortLosses.length,\\n        shortWinProfit: parseFloat(shortWinProfit.toFixed(2)),\\n        shortLossProfit: parseFloat(shortLossProfit.toFixed(2)),\\n        \\n        // 持仓时间统计\\n        avgHoldTimeHours: trades.length > 0 ? parseFloat((trades.reduce((sum, t) => sum + t.holdTime, 0) / trades.length / (1000 * 60 * 60)).toFixed(2)) : 0,\\n        maxHoldTimeHours: trades.length > 0 ? parseFloat((Math.max(...trades.map(t => t.holdTime)) / (1000 * 60 * 60)).toFixed(2)) : 0,\\n        minHoldTimeHours: trades.length > 0 ? parseFloat((Math.min(...trades.map(t => t.holdTime)) / (1000 * 60 * 60)).toFixed(2)) : 0,\\n        \\n        // 添加合约规格信息\\n        ctVal: ctVal,\\n        \\n        // 修改:基于最近4小时的连续亏损和冷却机制\\n        consecutiveLosses: consecutiveLosses, // 这里现在是最近4小时的连续亏损\\n        recentLossesDescription: `最近4小时连续亏损${consecutiveLosses}次`, // 添加描述\\n        freezeStatus: freezeStatus,  // 'free' 或 'frozen'\\n        freezeStartTime: freezeStartTime,\\n        freezeEndTime: freezeEndTime\\n    }\\n    \\n    // 如果在冷却期,添加剩余冷却时间信息\\n    if (freezeStatus === 'frozen') {\\n        const remainingFreezeHours = parseFloat(((freezeEndTime - currentTime) / (1000 * 60 * 60)).toFixed(2))\\n        result.remainingFreezeHours = Math.max(0, remainingFreezeHours)\\n    }\\n    \\n    return result\\n}\\n\\nconst coins = $input.first().json.coins\\nconst results = {}\\n\\n// 从 _G('tradesHistory') 获取交易历史数据\\nconst tradesHistory = _G('tradesHistory') || {}\\n\\nLog('📊 开始分析最近4小时的交易表现...')\\n\\nfor (let coin of coins) {\\n    const symbol = coin + '_USDT.swap'\\n    try {\\n        // 获取该币种的交易记录\\n        const orders = tradesHistory[coin] || []\\n        \\n        results[symbol] = analyzePerformance(orders, symbol)\\n    } catch (e) {\\n        results[symbol] = { error: e.toString() }\\n    }\\n}\\n\\n// 按盈利排序\\nconst sorted = Object.values(results)\\n    .filter(r => !r.error && r.totalTrades > 0)\\n    .sort((a, b) => b.totalProfit - a.totalProfit)\\n\\n// 统计冷却状态\\nconst frozenCoins = sorted.filter(r => r.freezeStatus === 'frozen')\\nconst freeCoins = sorted.filter(r => r.freezeStatus === 'free')\\n\\nLog(`🧊 冷却状态统计 (基于最近4小时):`)\\nLog(`   冷却中币种: ${frozenCoins.length}`)\\nLog(`   可交易币种: ${freeCoins.length}`)\\n\\nif (frozenCoins.length > 0) {\\n    Log(`❄️ 冷却中的币种 (最近4小时连续亏损):`)\\n    frozenCoins.forEach(coin => {\\n        const coinName = coin.coin.replace('_USDT.swap', '')\\n        Log(`   ${coinName}: ${coin.recentLossesDescription}, 剩余${coin.remainingFreezeHours || 0}小时解冻`)\\n    })\\n}\\n\\nLog('币种表现统计节点:',{\\n    sorted: sorted,\\n    summary: {\\n        totalProfit: sorted.reduce((sum, r) => sum + r.totalProfit, 0).toFixed(2),\\n        avgWinRate: sorted.length > 0 ? (sorted.reduce((sum, r) => sum + r.winRate, 0) / sorted.length).toFixed(2) : 0,\\n        totalRecords: Object.values(tradesHistory).reduce((sum, coinTrades) => sum + coinTrades.length, 0),\\n        coinsWithData: Object.keys(tradesHistory).length,\\n        frozenCoinsCount: frozenCoins.length,\\n        freeCoinsCount: freeCoins.length,\\n        analysisMethod: '基于最近4小时连续亏损' // 添加分析方法说明\\n    },\\n    frozenCoins: frozenCoins.map(coin => ({\\n        coin: coin.coin.replace('_USDT.swap', ''),\\n        consecutiveLosses: coin.consecutiveLosses,\\n        recentLossesDescription: coin.recentLossesDescription,\\n        remainingFreezeHours: coin.remainingFreezeHours || 0\\n    })),\\n    freeCoins: freeCoins.map(coin => coin.coin.replace('_USDT.swap', ''))\\n})\\n\\nreturn {\\n    sorted: sorted,\\n    summary: {\\n        totalProfit: sorted.reduce((sum, r) => sum + r.totalProfit, 0).toFixed(2),\\n        avgWinRate: sorted.length > 0 ? (sorted.reduce((sum, r) => sum + r.winRate, 0) / sorted.length).toFixed(2) : 0,\\n        totalRecords: Object.values(tradesHistory).reduce((sum, coinTrades) => sum + coinTrades.length, 0),\\n        coinsWithData: Object.keys(tradesHistory).length,\\n        frozenCoinsCount: frozenCoins.length,\\n        freeCoinsCount: freeCoins.length,\\n        analysisMethod: '基于最近4小时连续亏损' // 添加分析方法说明\\n    },\\n    frozenCoins: frozenCoins.map(coin => ({\\n        coin: coin.coin.replace('_USDT.swap', ''),\\n        consecutiveLosses: coin.consecutiveLosses,\\n        recentLossesDescription: coin.recentLossesDescription,\\n        remainingFreezeHours: coin.remainingFreezeHours || 0\\n    })),\\n    freeCoins: freeCoins.map(coin => coin.coin.replace('_USDT.swap', ''))\\n}\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[880,560],\"id\":\"1d8ab6c0-3d9f-4bd5-a403-09962f4b4dfe\",\"name\":\"币种表现统计\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"// ========== 止盈止损监控系统 - 集成完整可视化仪表板 ==========\\n\\nif (_G('invoketime') === null) {\\n  return {}\\n}\\n\\n// ========== 配置参数 ==========\\nconst sltpChoice = $vars.sltpChoice;\\nconst FIXED_PROFIT_RATIO = $vars.tpPercent;  // 2% 止盈\\nconst FIXED_LOSS_RATIO = $vars.slPercent;    // 1% 止损\\n\\n// ========== 工具函数 ==========\\n\\n/**\\n * 获取交易对精度信息\\n */\\nfunction getPrecision(coin) {\\n    try {\\n        const symbol = coin + '_USDT.swap';\\n        const markets = _G('markets');\\n        \\n        if (markets && markets[symbol]) {\\n            return {\\n                price: markets[symbol].PricePrecision || 0,\\n                amount: markets[symbol].AmountPrecision || 0,\\n                minQty: markets[symbol].MinQty || 5,\\n                ctVal: markets[symbol].CtVal || 1  // 合约面值\\n            };\\n        }\\n        return { price: 0, amount: 0, minQty: 5, ctVal: 1 };\\n    } catch (e) {\\n        Log(`⚠️ 获取${coin}精度失败,使用默认值`);\\n        return { price: 0, amount: 0, minQty: 5, ctVal: 1 };\\n    }\\n}\\n\\n/**\\n * 保存交易记录到历史数据库\\n */\\nfunction saveTradeToHistory(orderDetail, coin, signalInfo) {\\n    try {\\n        const currentTime = Date.now();\\n        \\n        // 构建交易记录\\n        const tradeRecord = {\\n            // 订单信息\\n            Id: orderDetail.Id,\\n            Price: orderDetail.Price,\\n            Amount: orderDetail.Amount,\\n            DealAmount: orderDetail.DealAmount,\\n            AvgPrice: orderDetail.AvgPrice,\\n            Status: orderDetail.Status,\\n            Type: orderDetail.Type,\\n            Offset: orderDetail.Offset,\\n            Symbol: orderDetail.Symbol,\\n            ContractType: orderDetail.ContractType,\\n            \\n            // AI信号信息\\n            aiSignal: signalInfo.signal || 'auto_close',\\n            confidence: signalInfo.confidence || 1.0,\\n            profitTarget: signalInfo.profit_target,\\n            stopLoss: signalInfo.stop_loss,\\n            leverage: signalInfo.leverage,\\n            riskUsd: signalInfo.risk_usd,\\n            justification: signalInfo.justification,\\n            \\n            // 时间戳\\n            time: currentTime,\\n            timeStr: new Date(currentTime).toISOString()\\n        };\\n        \\n        // 获取现有历史记录\\n        let tradesHistory = _G('tradesHistory') || {};\\n        \\n        // 初始化币种记录\\n        if (!tradesHistory[coin]) {\\n            tradesHistory[coin] = [];\\n        }\\n        \\n        // 添加记录\\n        tradesHistory[coin].push(tradeRecord);\\n        \\n        // 限制历史记录数量(每个币种最多保存1000条)\\n        if (tradesHistory[coin].length > 1000) {\\n            tradesHistory[coin] = tradesHistory[coin].slice(-1000);\\n        }\\n        \\n        // 保存到全局存储\\n        _G('tradesHistory', tradesHistory);\\n        \\n        const typeStr = orderDetail.Type === 0 ? '买入' : '卖出';\\n        Log(`📝 ${coin} 交易记录已保存: ${typeStr} ${orderDetail.DealAmount} @ $${orderDetail.AvgPrice}`);\\n        \\n    } catch (e) {\\n        Log(`❌ 保存${coin}交易记录失败: ${e.message}`);\\n    }\\n}\\n\\n/**\\n * 执行平仓操作\\n */\\nfunction closePosition(coin, pos, isLong, reason, pnl) {\\n    const precision = getPrecision(coin);\\n    const closeAmount = _N(Math.abs(pos.Amount), precision.amount);\\n    \\n    exchange.SetDirection(isLong ? \\\"closebuy\\\" : \\\"closesell\\\");\\n    const orderId = isLong ? exchange.Sell(-1, closeAmount) : exchange.Buy(-1, closeAmount);\\n    \\n    if (orderId) {\\n        Log(`${reason === '止盈' ? '✅' : '❌'} ${coin} ${reason} ${(pnl*100).toFixed(2)}% 数量=${closeAmount}`);\\n        _G(`exit_plan_${coin}_USDT.swap`, null);\\n        \\n        // 保存交易记录到历史\\n        Sleep(1000);\\n        try {\\n            const orderDetail = exchange.GetOrder(orderId);\\n            if (orderDetail && orderDetail.Status === 1) {\\n                saveTradeToHistory(orderDetail, coin, { \\n                    signal: 'close', \\n                    confidence: 1.0, \\n                    justification: `自动${reason} PnL: ${(pnl*100).toFixed(2)}%` \\n                });\\n            }\\n        } catch (e) {\\n            Log(`⚠️ 获取${coin}${reason}订单详情失败: ${e.message}`);\\n        }\\n        return true;\\n    }\\n    return false;\\n}\\n\\n/**\\n * 监控单个持仓\\n */\\nfunction monitorPosition(coin) {\\n    exchange.SetCurrency(coin + '_USDT');\\n    exchange.SetContractType(\\\"swap\\\");\\n    \\n    const pos = exchange.GetPositions().find(p => p.Symbol.includes(coin) && Math.abs(p.Amount) > 0);\\n    if (!pos) return { status: \\\"no_position\\\" };\\n    \\n    const ticker = exchange.GetTicker();\\n    if (!ticker) return { status: \\\"no_ticker\\\" };\\n    \\n    const isLong = pos.Type === PD_LONG || pos.Type === 0;\\n    const currentPrice = ticker.Last;\\n    const pnl = (currentPrice - pos.Price) * (isLong ? 1 : -1) / pos.Price;\\n    \\n    let shouldTP = false;\\n    let shouldSL = false;\\n    let profitTarget = null;\\n    let stopLoss = null;\\n    \\n    if (sltpChoice) {\\n        shouldTP = pnl >= FIXED_PROFIT_RATIO;\\n        shouldSL = pnl <= -FIXED_LOSS_RATIO;\\n        profitTarget = pos.Price * (isLong ? (1 + FIXED_PROFIT_RATIO) : (1 - FIXED_PROFIT_RATIO));\\n        stopLoss = pos.Price * (isLong ? (1 - FIXED_LOSS_RATIO) : (1 + FIXED_LOSS_RATIO));\\n    } else {\\n        const exitPlan = _G(`exit_plan_${coin}_USDT.swap`);\\n        \\n        if (exitPlan?.profit_target && exitPlan?.stop_loss) {\\n            profitTarget = exitPlan.profit_target;\\n            stopLoss = exitPlan.stop_loss;\\n            shouldTP = isLong ? currentPrice >= profitTarget : currentPrice <= profitTarget;\\n            shouldSL = isLong ? currentPrice <= stopLoss : currentPrice >= stopLoss;\\n        } else {\\n            shouldTP = pnl >= FIXED_PROFIT_RATIO;\\n            shouldSL = pnl <= -FIXED_LOSS_RATIO;\\n            profitTarget = pos.Price * (isLong ? (1 + FIXED_PROFIT_RATIO) : (1 - FIXED_PROFIT_RATIO));\\n            stopLoss = pos.Price * (isLong ? (1 - FIXED_LOSS_RATIO) : (1 + FIXED_LOSS_RATIO));\\n        }\\n    }\\n    \\n    if (shouldTP) {\\n        return closePosition(coin, pos, isLong, \\\"止盈\\\", pnl) ? \\n            { status: \\\"closed\\\", reason: \\\"profit\\\", pnl: pnl } : \\n            { status: \\\"close_failed\\\" };\\n    }\\n    \\n    if (shouldSL) {\\n        return closePosition(coin, pos, isLong, \\\"止损\\\", pnl) ? \\n            { status: \\\"closed\\\", reason: \\\"loss\\\", pnl: pnl } : \\n            { status: \\\"close_failed\\\" };\\n    }\\n    \\n    return { \\n        status: \\\"monitoring\\\", \\n        pnl: pnl, \\n        position: pos, \\n        currentPrice: currentPrice,\\n        isLong: isLong,\\n        profitTarget: profitTarget,\\n        stopLoss: stopLoss\\n    };\\n}\\n\\n// ========== 可视化仪表板函数 ==========\\n\\n/**\\n * 获取币种表现数据\\n */\\nfunction getCoinPerformanceData() {\\n    try {\\n        const tradesHistory = _G('tradesHistory') || {};\\n        const performanceData = {};\\n        \\n        Object.keys(tradesHistory).forEach(coin => {\\n            const orders = tradesHistory[coin] || [];\\n            performanceData[coin + '_USDT.swap'] = analyzePerformance(orders, coin + '_USDT.swap');\\n        });\\n        \\n        return performanceData;\\n    } catch (e) {\\n        Log(`⚠️ 获取表现数据失败: ${e.message}`);\\n        return {};\\n    }\\n}\\n\\n/**\\n * 分析交易表现\\n */\\nfunction analyzePerformance(orders, coin) {\\n    if (!orders || orders.length === 0) {\\n        return { coin, totalTrades: 0, totalProfit: 0, freezeStatus: 'free' };\\n    }\\n    \\n    const filteredOrders = orders.filter(o => o.Status === 1);\\n    const validOrders = filteredOrders.sort((a, b) => a.time - b.time);\\n    \\n    if (validOrders.length === 0) {\\n        return { coin, totalTrades: 0, totalProfit: 0, freezeStatus: 'free' };\\n    }\\n    \\n    // 获取合约面值\\n    const coinMatch = coin.match(/^([A-Z0-9]+)_USDT/);\\n    const coinName = coinMatch ? coinMatch[1] : coin;\\n    const precision = getPrecision(coinName);\\n    const ctVal = precision.ctVal;\\n    \\n    let trades = [];\\n    let positions = [];\\n    \\n    // 交易配对逻辑\\n    for (let order of validOrders) {\\n        const { Type: type, DealAmount: amount, AvgPrice: price, time, Id: id } = order;\\n        \\n        let remaining = amount;\\n        \\n        for (let i = 0; i < positions.length && remaining > 0.0001; i++) {\\n            const pos = positions[i];\\n            \\n            if ((type === 0 && pos.type === 1) || (type === 1 && pos.type === 0)) {\\n                const tradeAmount = Math.min(remaining, pos.amount);\\n                const holdTime = time - pos.time;\\n                \\n                let profit, direction;\\n                if (pos.type === 0) {\\n                    profit = (price - pos.price) * tradeAmount * ctVal;\\n                    direction = 'LONG';\\n                } else {\\n                    profit = (pos.price - price) * tradeAmount * ctVal;\\n                    direction = 'SHORT';\\n                }\\n                \\n                trades.push({\\n                    direction,\\n                    openPrice: pos.price,\\n                    closePrice: price,\\n                    amount: tradeAmount,\\n                    profit,\\n                    holdTime: holdTime,\\n                    closeTime: time\\n                });\\n                \\n                pos.amount -= tradeAmount;\\n                remaining -= tradeAmount;\\n                \\n                if (pos.amount <= 0.0001) {\\n                    positions.splice(i, 1);\\n                    i--;\\n                }\\n            }\\n        }\\n        \\n        if (remaining > 0.0001) {\\n            positions.push({\\n                type: type,\\n                price: price,\\n                amount: remaining,\\n                time: time,\\n                id: id\\n            });\\n        }\\n    }\\n    \\n    if (trades.length === 0) {\\n        return { \\n            coin, \\n            totalTrades: 0, \\n            totalProfit: 0,\\n            winRate: 0,\\n            avgProfit: 0,\\n            maxProfit: 0,\\n            maxLoss: 0,\\n            profitLossRatio: 0,\\n            avgHoldTimeHours: 0,\\n            longWinProfit: 0,\\n            shortWinProfit: 0,\\n            freezeStatus: 'free'\\n        };\\n    }\\n    \\n    // 计算统计数据\\n    trades.sort((a, b) => a.closeTime - b.closeTime);\\n    \\n    const wins = trades.filter(t => t.profit > 0);\\n    const losses = trades.filter(t => t.profit <= 0);\\n    const longTrades = trades.filter(t => t.direction === 'LONG');\\n    const shortTrades = trades.filter(t => t.direction === 'SHORT');\\n    \\n    const longWins = longTrades.filter(t => t.profit > 0);\\n    const shortWins = shortTrades.filter(t => t.profit > 0);\\n    \\n    const totalProfit = trades.reduce((sum, t) => sum + t.profit, 0);\\n    const totalWinProfit = wins.reduce((sum, t) => sum + t.profit, 0);\\n    const totalLossProfit = Math.abs(losses.reduce((sum, t) => sum + t.profit, 0));\\n    const winRate = (wins.length / trades.length * 100);\\n    \\n    const frozenData = _G(`frozen_${coinName}`);\\n    const currentTime = Date.now();\\n    const freezeStatus = (frozenData && frozenData.freezeEndTime > currentTime) ? 'frozen' : 'free';\\n    \\n    function calculateRecentConsecutiveLosses(tradesArray) {\\n        const currentTime = Date.now()\\n        const fourHoursAgo = currentTime - (4 * 60 * 60 * 1000) // 4小时前的时间戳\\n        \\n        // 筛选出最近4小时内的交易\\n        const recentTrades = tradesArray.filter(trade => trade.closeTime >= fourHoursAgo)\\n        \\n        if (recentTrades.length === 0) {\\n            return 0 // 最近4小时没有交易\\n        }\\n        \\n        // 按时间排序(确保时间顺序正确)\\n        recentTrades.sort((a, b) => a.closeTime - b.closeTime)\\n        \\n        let consecutiveLosses = 0\\n        // 从最后一笔交易开始往前计算连续亏损\\n        for (let i = recentTrades.length - 1; i >= 0; i--) {\\n            if (recentTrades[i].profit <= 0) {\\n                consecutiveLosses++\\n            } else {\\n                break  // 遇到盈利交易就停止计算\\n            }\\n        }\\n        \\n        return consecutiveLosses\\n    }\\n    \\n    const consecutiveLosses = calculateRecentConsecutiveLosses(trades)\\n    \\n    return {\\n        coin,\\n        totalTrades: trades.length,\\n        totalProfit: parseFloat(totalProfit.toFixed(2)),\\n        winRate: parseFloat(winRate.toFixed(2)),\\n        avgProfit: parseFloat((totalProfit / trades.length).toFixed(2)),\\n        maxProfit: wins.length > 0 ? parseFloat(Math.max(...wins.map(t => t.profit)).toFixed(2)) : 0,\\n        maxLoss: parseFloat(Math.min(...trades.map(t => t.profit)).toFixed(2)),\\n        profitLossRatio: totalLossProfit > 0 ? parseFloat((totalWinProfit / totalLossProfit).toFixed(2)) : (totalWinProfit > 0 ? 999 : 0),\\n        avgHoldTimeHours: parseFloat((trades.reduce((sum, t) => sum + t.holdTime, 0) / trades.length / (1000 * 60 * 60)).toFixed(2)),\\n        longWinProfit: parseFloat(longWins.reduce((sum, t) => sum + t.profit, 0).toFixed(2)),\\n        shortWinProfit: parseFloat(shortWins.reduce((sum, t) => sum + t.profit, 0).toFixed(2)),\\n        consecutiveLosses: consecutiveLosses,\\n        freezeStatus: freezeStatus\\n    };\\n}\\n\\n/**\\n * 创建AI智能体信号分析表\\n */\\n/**\\n * 创建AI智能体信号分析表 - 从_G获取执行结果\\n */\\nfunction createMonitoringTable() {\\n    const signalTable = {\\n        type: \\\"table\\\",\\n        title: \\\"🤖 AI智能体\\\",\\n        cols: [\\\"币种\\\", \\\"信号类型\\\", \\\"执行状态\\\", \\\"置信度\\\", \\\"止盈目标\\\", \\\"止损价位\\\", \\\"风险金额\\\", \\\"理由\\\"],\\n        rows: []\\n    };\\n    \\n    try {\\n        // 从_G获取AI信号和执行结果\\n        const aiSignals = _G('AISinnal') || [];\\n        const executionData = _G('latestExecutionResults') || { results: {} };\\n        const executionResults = executionData.results || {};\\n        \\n        if (!aiSignals || aiSignals.length === 0) {\\n            signalTable.rows.push([\\n                \\\"📭 暂无信号\\\",\\n                \\\"⏳ 等待AI分析\\\",\\n                \\\"⏭️ 待分析\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"等待AI智能体生成交易信号\\\"\\n            ]);\\n            return signalTable;\\n        }\\n        \\n        // 处理每个AI信号\\n        aiSignals.forEach(aiSignal => {\\n            if (!aiSignal || !aiSignal.coin) return;\\n            \\n            const coin = aiSignal.coin;\\n            const executionResult = executionResults[coin]; // 从_G获取执行结果\\n            \\n            // 美化信号显示\\n            let signalDisplay = aiSignal.signal;\\n            let signalEmoji = \\\"⏸️\\\";\\n            \\n            switch (aiSignal.signal) {\\n                case 'buy_to_enter':\\n                    signalDisplay = \\\"🟢 做多入场\\\";\\n                    signalEmoji = \\\"📈\\\";\\n                    break;\\n                case 'sell_to_enter':\\n                    signalDisplay = \\\"🔴 做空入场\\\";\\n                    signalEmoji = \\\"📉\\\";\\n                    break;\\n                case 'close':\\n                    signalDisplay = \\\"⏹️ 平仓\\\";\\n                    signalEmoji = \\\"🔚\\\";\\n                    break;\\n                case 'hold':\\n                    signalDisplay = \\\"⏸️ 持仓观望\\\";\\n                    signalEmoji = \\\"⏳\\\";\\n                    break;\\n                default:\\n                    signalDisplay = \\\"❓ 未知信号\\\";\\n                    signalEmoji = \\\"⚠️\\\";\\n            }\\n            \\n            // ===== 修改:根据_G中的执行结果显示状态 =====\\n            let statusDisplay = \\\"\\\";\\n            if (executionResult) {\\n                if (executionResult.executed) {\\n                    statusDisplay = \\\"✅ 已执行\\\";\\n                } else if (executionResult.skipReason) {\\n                    statusDisplay = `⏭️ ${executionResult.skipReason}`;\\n                } else {\\n                    statusDisplay = \\\"❌ 执行失败\\\";\\n                }\\n            } else {\\n                // 没有执行记录,根据信号类型推断\\n                if (aiSignal.signal === 'hold') {\\n                    statusDisplay = \\\"⏭️ 持仓观望\\\";\\n                } else {\\n                    statusDisplay = \\\"⏭️ 等待执行\\\";\\n                }\\n            }\\n            \\n            // 置信度显示\\n            const confidence = aiSignal.confidence ? (aiSignal.confidence * 100).toFixed(0) : 0;\\n            let confidenceDisplay = \\\"-\\\";\\n            if (confidence >= 80) {\\n                confidenceDisplay = `🔥 ${confidence}%`;\\n            } else if (confidence >= 60) {\\n                confidenceDisplay = `⚡ ${confidence}%`;\\n            } else if (confidence > 0) {\\n                confidenceDisplay = `⚠️ ${confidence}%`;\\n            }\\n            \\n            // 历史偏向显示\\n            let biasEmoji = \\\"\\\";\\n            switch (aiSignal.historical_bias) {\\n                case 'LONG':\\n                    biasEmoji = \\\"📈\\\";\\n                    break;\\n                case 'SHORT':\\n                    biasEmoji = \\\"📉\\\";\\n                    break;\\n                case 'BALANCED':\\n                    biasEmoji = \\\"⚖️\\\";\\n                    break;\\n                default:\\n                    biasEmoji = \\\"❓\\\";\\n            }\\n            \\n            signalTable.rows.push([\\n                `💎 ${coin}`,\\n                `${signalEmoji} ${signalDisplay}`,\\n                statusDisplay, // 这里显示真实的执行状态\\n                confidenceDisplay,\\n                aiSignal.profit_target && aiSignal.profit_target > 0 ? `🎯 $${_N(aiSignal.profit_target, 4)}` : \\\"-\\\",\\n                aiSignal.stop_loss && aiSignal.stop_loss > 0 ? `🛡️ $${_N(aiSignal.stop_loss, 4)}` : \\\"-\\\",\\n                aiSignal.risk_usd && aiSignal.risk_usd > 0 ? `💰 $${aiSignal.risk_usd}` : \\\"-\\\",\\n                `${biasEmoji} ${aiSignal.justification || \\\"无详细说明\\\"}`\\n            ]);\\n        });\\n        \\n        // 添加执行汇总行\\n        if (executionData.timestamp) {\\n            const executionTime = new Date(executionData.timestamp).toLocaleTimeString();\\n            const executedCount = Object.values(executionResults).filter(r => r.executed).length;\\n            const totalSignals = executionData.totalSignals || 0;\\n            \\n            signalTable.rows.push([\\n                \\\"📊 执行汇总\\\",\\n                `${totalSignals} 个信号`,\\n                `✅ ${executedCount} 个已执行`,\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                `最后更新: ${executionTime}`\\n            ]);\\n        }\\n        \\n    } catch (e) {\\n        Log(`❌ 创建AI信号表失败: ${e.message}`);\\n        signalTable.rows.push([\\n            \\\"❌ 错误\\\",\\n            \\\"获取信号失败\\\",\\n            \\\"🚨\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            e.message.substring(0, 50)\\n        ]);\\n    }\\n    \\n    return signalTable;\\n}\\n\\n/**\\n * 创建持仓表\\n */\\nfunction createPositionTable() {\\n    const positionTable = {\\n        type: \\\"table\\\",\\n        title: \\\"💼 当前持仓状态\\\",\\n        cols: [\\\"币种\\\", \\\"方向\\\", \\\"数量\\\", \\\"入场价\\\", \\\"当前价\\\", \\\"盈亏%\\\", \\\"盈亏$\\\", \\\"杠杆\\\", \\\"止盈\\\", \\\"止损\\\"],\\n        rows: []\\n    };\\n    \\n    try {\\n        const positions = exchange.GetPositions();\\n        let totalPnl = 0;\\n        let positionCount = 0;\\n        \\n        if (positions && positions.length > 0) {\\n            positions.forEach(pos => {\\n                if (Math.abs(pos.Amount) > 0) {\\n                    const coinMatch = pos.Symbol.match(/^([A-Z0-9]+)_USDT/);\\n                    if (!coinMatch) return;\\n                    \\n                    const coin = coinMatch[1];\\n                    \\n                    // 获取当前价格\\n                    exchange.SetCurrency(coin + '_USDT');\\n                    exchange.SetContractType(\\\"swap\\\");\\n                    const symbolcode = coin + '_USDT.swap';\\n                    const ticker = exchange.GetTicker();\\n                    const coininfo = _G('markets')[symbolcode];\\n                    \\n                    if (ticker) {\\n                        const isLong = pos.Type === PD_LONG || pos.Type === 0;\\n                        const currentPrice = ticker.Last;\\n                        const pnlPercent = ((currentPrice - pos.Price) * (isLong ? 1 : -1) / pos.Price * 100);\\n                        const pnlUsd = pnlPercent / 100 * pos.Price * Math.abs(pos.Amount) * (coininfo?.CtVal || 1);\\n                        \\n                        // 盈亏显示\\n                        let pnlPercentDisplay = \\\"\\\";\\n                        let pnlUsdDisplay = \\\"\\\";\\n                        if (pnlPercent > 0) {\\n                            pnlPercentDisplay = `🟢 +${pnlPercent.toFixed(2)}%`;\\n                            pnlUsdDisplay = `🟢 +$${pnlUsd.toFixed(2)}`;\\n                        } else if (pnlPercent < 0) {\\n                            pnlPercentDisplay = `🔴 ${pnlPercent.toFixed(2)}%`;\\n                            pnlUsdDisplay = `🔴 $${pnlUsd.toFixed(2)}`;\\n                        } else {\\n                            pnlPercentDisplay = `⚪ ${pnlPercent.toFixed(2)}%`;\\n                            pnlUsdDisplay = `⚪ $${pnlUsd.toFixed(2)}`;\\n                        }\\n                        \\n                        // 获取退出计划\\n                        const exitPlan = _G(`exit_plan_${coin}_USDT.swap`);\\n                        \\n                        positionTable.rows.push([\\n                            `💎 ${coin}`,\\n                            isLong ? \\\"📈 多\\\" : \\\"📉 空\\\",\\n                            _N(Math.abs(pos.Amount), 4),\\n                            `$${_N(pos.Price, 4)}`,\\n                            `$${_N(currentPrice, 4)}`,\\n                            pnlPercentDisplay,\\n                            pnlUsdDisplay,\\n                            `${pos.MarginLevel || 1}x`,\\n                            exitPlan?.profit_target ? `$${_N(exitPlan.profit_target, 4)}` : \\\"-\\\",\\n                            exitPlan?.stop_loss ? `$${_N(exitPlan.stop_loss, 4)}` : \\\"-\\\"\\n                        ]);\\n                        \\n                        totalPnl += pnlPercent;\\n                        positionCount++;\\n                    }\\n                    \\n                    Sleep(200);\\n                }\\n            });\\n        }\\n        \\n        // 添加汇总行\\n        if (positionCount > 0) {\\n            const avgPnl = totalPnl / positionCount;\\n            let summaryEmoji = avgPnl > 0 ? \\\"📊 ✅\\\" : \\\"📊 ⚠️\\\";\\n            positionTable.rows.push([\\n                `${summaryEmoji} 汇总`,\\n                `${positionCount} 个持仓`,\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                `平均: ${avgPnl > 0 ? '🟢' : '🔴'} ${_N(avgPnl, 2)}%`,\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\"\\n            ]);\\n        } else {\\n            positionTable.rows.push([\\n                \\\"📭 空仓\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\"\\n            ]);\\n        }\\n        \\n    } catch (e) {\\n        Log(`❌ 创建持仓表失败: ${e.message}`);\\n        positionTable.rows.push([\\n            \\\"❌ 错误\\\",\\n            \\\"获取持仓失败\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\"\\n        ]);\\n    }\\n    \\n    return positionTable;\\n}\\n\\n/**\\n * 创建表现统计表\\n */\\nfunction createPerformanceTable() {\\n    const performanceTable = {\\n        type: \\\"table\\\",\\n        title: \\\"📈 各币种交易表现 (按总盈亏排序)\\\",\\n        cols: [\\\"币种\\\", \\\"总交易\\\", \\\"总盈亏\\\", \\\"胜率%\\\", \\\"平均盈亏\\\", \\\"最大盈利\\\", \\\"最大亏损\\\", \\\"盈亏比\\\", \\\"冷却状态\\\"],\\n        rows: []\\n    };\\n    \\n    try {\\n        const performanceData = getCoinPerformanceData();\\n        const coinPerformances = Object.values(performanceData)\\n            .filter(r => !r.error)\\n            .sort((a, b) => b.totalProfit - a.totalProfit);\\n        \\n        if (coinPerformances.length === 0) {\\n            performanceTable.rows.push([\\n                \\\"📭 暂无数据\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"等待交易数据\\\"\\n            ]);\\n        } else {\\n            coinPerformances.forEach(performance => {\\n                const coinMatch = performance.coin.match(/^([A-Z0-9]+)_USDT/);\\n                const coinName = coinMatch ? coinMatch[1] : performance.coin;\\n                \\n                // 冷却状态显示\\n                let freezeDisplay = \\\"🟢 正常\\\";\\n                if (performance.freezeStatus === 'frozen') {\\n                    freezeDisplay = `🧊 冷却中 (${performance.consecutiveLosses}连亏)`;\\n                }\\n                \\n                performanceTable.rows.push([\\n                    `💎 ${coinName}`,\\n                    performance.totalTrades,\\n                    performance.totalProfit > 0 ? `🟢 $${performance.totalProfit}` : \\n                    performance.totalProfit < 0 ? `🔴 $${performance.totalProfit}` : `⚪ $0`,\\n                    performance.winRate > 0 ? `${performance.winRate}%` : \\\"0%\\\",\\n                    performance.avgProfit > 0 ? `🟢 $${performance.avgProfit}` : \\n                    performance.avgProfit < 0 ? `🔴 $${performance.avgProfit}` : `⚪ $0`,\\n                    performance.maxProfit > 0 ? `$${performance.maxProfit}` : \\\"$0\\\",\\n                    performance.maxLoss < 0 ? `$${performance.maxLoss}` : \\\"$0\\\",\\n                    performance.profitLossRatio > 0 ? `${performance.profitLossRatio}` : \\\"0\\\",\\n                    freezeDisplay\\n                ]);\\n            });\\n            \\n            // 添加汇总行\\n            const totalTrades = coinPerformances.reduce((sum, p) => sum + p.totalTrades, 0);\\n            const totalProfit = coinPerformances.reduce((sum, p) => sum + p.totalProfit, 0);\\n            const frozenCount = coinPerformances.filter(p => p.freezeStatus === 'frozen').length;\\n            \\n            performanceTable.rows.push([\\n                \\\"📊 汇总\\\",\\n                totalTrades,\\n                totalProfit > 0 ? `🟢 $${_N(totalProfit, 2)}` : \\n                totalProfit < 0 ? `🔴 $${_N(totalProfit, 2)}` : `⚪ $0`,\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                `${frozenCount} 个冷却中`\\n            ]);\\n        }\\n        \\n    } catch (e) {\\n        Log(`❌ 创建表现表失败: ${e.message}`);\\n        performanceTable.rows.push([\\n            \\\"❌ 错误\\\",\\n            \\\"获取统计失败\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            \\\"-\\\",\\n            e.message.substring(0, 20)\\n        ]);\\n    }\\n    \\n    return performanceTable;\\n}\\n\\n/**\\n * 创建整体分析表\\n */\\nfunction createSystemStatusTable() {\\n    const statusTable = {\\n        type: \\\"table\\\",\\n        title: \\\"📊 整体分析表\\\",\\n        cols: [\\\"分析指标\\\", \\\"数值\\\", \\\"状态\\\", \\\"说明\\\"],\\n        rows: []\\n    };\\n    \\n    try {\\n        // 使用正确的盈利计算方式\\n        const currentAccount = exchange.GetAccount();\\n        const currentAccountValue = currentAccount.Equity;\\n        const initMoney = _G('initmoney') || currentAccountValue;\\n        const totalProfitUSD = currentAccountValue - initMoney;\\n        const totalReturnPercent = ((currentAccountValue - initMoney) / initMoney * 100);\\n\\n        LogProfit(totalProfitUSD, \\\"&\\\")\\n        \\n        // 获取交易统计\\n        const performanceData = getCoinPerformanceData();\\n        const coinPerformances = Object.values(performanceData).filter(r => !r.error);\\n        const totalTrades = coinPerformances.reduce((sum, p) => sum + p.totalTrades, 0);\\n        const avgWinRate = coinPerformances.length > 0 ? \\n            coinPerformances.reduce((sum, p) => sum + p.winRate, 0) / coinPerformances.length : 0;\\n        const frozenCount = coinPerformances.filter(p => p.freezeStatus === 'frozen').length;\\n        const activeCoins = coinPerformances.filter(p => p.totalTrades > 0).length;\\n        \\n        // 持仓统计\\n        const positions = exchange.GetPositions();\\n        const activePositions = positions ? positions.filter(p => Math.abs(p.Amount) > 0).length : 0;\\n        \\n        statusTable.rows.push([\\n            \\\"💰 账户权益\\\",\\n            `$${_N(currentAccountValue, 2)}`,\\n            \\\"📊\\\",\\n            `初始资金: $${_N(initMoney, 2)}`\\n        ]);\\n        \\n        statusTable.rows.push([\\n            \\\"💵 总盈亏(USD)\\\",\\n            totalProfitUSD > 0 ? `🟢 +$${_N(totalProfitUSD, 2)}` : \\n            totalProfitUSD < 0 ? `🔴 $${_N(totalProfitUSD, 2)}` : `⚪ $0`,\\n            totalProfitUSD > 0 ? \\\"✅ 盈利\\\" : totalProfitUSD < 0 ? \\\"⚠️ 亏损\\\" : \\\"⚪ 持平\\\",\\n            \\\"实际账户盈亏\\\"\\n        ]);\\n        \\n        statusTable.rows.push([\\n            \\\"📈 总收益率\\\",\\n            totalReturnPercent > 0 ? `🟢 +${_N(totalReturnPercent, 2)}%` : \\n            totalReturnPercent < 0 ? `🔴 ${_N(totalReturnPercent, 2)}%` : `⚪ 0%`,\\n            totalReturnPercent > 5 ? \\\"✅ 优秀\\\" : totalReturnPercent > 0 ? \\\"✅ 良好\\\" : \\\"⚠️ 需改进\\\",\\n            \\\"相对初始资金\\\"\\n        ]);\\n        \\n        statusTable.rows.push([\\n            \\\"🎲 总交易笔数\\\",\\n            totalTrades.toString(),\\n            totalTrades > 50 ? \\\"✅ 充足\\\" : totalTrades > 10 ? \\\"✅ 良好\\\" : \\\"⚠️ 偏少\\\",\\n            \\\"所有币种合计\\\"\\n        ]);\\n        \\n        statusTable.rows.push([\\n            \\\"🎯 平均胜率\\\",\\n            `${_N(avgWinRate, 1)}%`,\\n            avgWinRate > 60 ? \\\"✅ 优秀\\\" : avgWinRate > 45 ? \\\"✅ 良好\\\" : \\\"⚠️ 需改进\\\",\\n            \\\"各币种胜率平均值\\\"\\n        ]);\\n        \\n        statusTable.rows.push([\\n            \\\"💼 当前持仓\\\",\\n            `${activePositions} 个`,\\n            activePositions > 0 ? \\\"✅ 持仓中\\\" : \\\"📭 空仓\\\",\\n            \\\"活跃持仓数量\\\"\\n        ]);\\n        \\n        statusTable.rows.push([\\n            \\\"🧊 冷却币种\\\",\\n            `${frozenCount} 个`,\\n            frozenCount === 0 ? \\\"✅ 全部正常\\\" : frozenCount > 3 ? \\\"⚠️ 较多冷却\\\" : \\\"🟡 部分冷却\\\",\\n            \\\"连续亏损保护中\\\"\\n        ]);\\n        \\n        statusTable.rows.push([\\n            \\\"📊 活跃币种\\\",\\n            `${activeCoins} 个`,\\n            activeCoins > 5 ? \\\"✅ 多样化\\\" : activeCoins > 2 ? \\\"✅ 良好\\\" : \\\"⚠️ 单一\\\",\\n            \\\"有交易记录的币种\\\"\\n        ]);\\n        \\n        statusTable.rows.push([\\n            \\\"🎯 止盈止损\\\",\\n            sltpChoice ? \\\"固定模式\\\" : \\\"智能模式\\\",\\n            \\\"✅ 运行中\\\",\\n            \\\"持续监控\\\"\\n        ]);\\n        \\n    } catch (e) {\\n        Log(`❌ 创建整体分析表失败: ${e.message}`);\\n        statusTable.rows.push([\\n            \\\"❌ 错误\\\",\\n            \\\"计算失败\\\",\\n            \\\"🚨\\\",\\n            e.message.substring(0, 30)\\n        ]);\\n    }\\n    \\n    return statusTable;\\n}\\n\\n/**\\n * 显示完整的监控仪表板\\n */\\nfunction displayMonitoringDashboard(monitoringResults) {\\n    try {\\n        // 1. AI智能体信号分析表\\n        const signalTable = createMonitoringTable(monitoringResults);\\n        \\n        // 2. 当前持仓表\\n        const positionTable = createPositionTable();\\n        \\n        // 3. 币种表现表\\n        const performanceTable = createPerformanceTable();\\n        \\n        // 4. 整体分析表\\n        const systemStatusTable = createSystemStatusTable();\\n        \\n        // 组合显示\\n        const dashboardDisplay = \\n            '`' + JSON.stringify(signalTable) + '`\\\\n\\\\n' +\\n            '`' + JSON.stringify(positionTable) + '`\\\\n\\\\n' +\\n            '`' + JSON.stringify(performanceTable) + '`\\\\n\\\\n' +\\n            '`' + JSON.stringify(systemStatusTable) + '`';\\n        \\n        LogStatus(dashboardDisplay);\\n        \\n    } catch (e) {\\n        Log(`❌ 显示监控仪表板失败: ${e.message}`);\\n        // 回退到简单显示\\n        displaySimpleStatus();\\n    }\\n}\\n\\n/**\\n * 简单状态显示(备用)\\n */\\nfunction displaySimpleStatus() {\\n    try {\\n        const simpleTable = {\\n            type: \\\"table\\\",\\n            title: \\\"📊 止盈止损系统状态\\\",\\n            cols: [\\\"项目\\\", \\\"状态\\\", \\\"说明\\\"],\\n            rows: [\\n                [\\\"🔍 持仓监控\\\", \\\"✅ 运行中\\\", \\\"实时监控所有持仓\\\"],\\n                [\\\"🎯 止盈止损\\\", \\\"✅ 正常\\\", `${sltpChoice ? '智能' : '固定'}模式`],\\n                [\\\"📊 数据记录\\\", \\\"✅ 正常\\\", \\\"记录交易历史\\\"],\\n                [\\\"🧊 冷却保护\\\", \\\"✅ 启用\\\", \\\"防止连续亏损\\\"]\\n            ]\\n        };\\n        \\n        LogStatus('`' + JSON.stringify(simpleTable) + '`');\\n    } catch (e) {\\n        LogStatus('❌ 显示状态失败: ' + e.message);\\n    }\\n}\\n\\n// ========== 主执行逻辑 ==========\\n\\nfunction main() {\\n    try {\\n        \\n        // 监控结果记录\\n        const monitoringResults = {};\\n        let totalActions = 0;\\n        \\n        // 获取所有持仓进行监控\\n        const positions = exchange.GetPositions();\\n        \\n        if (positions && positions.length > 0) {\\n            positions.forEach(pos => {\\n                if (Math.abs(pos.Amount) > 0) {\\n                    const coinMatch = pos.Symbol.match(/^([A-Z0-9]+)_USDT/);\\n                    if (!coinMatch) return;\\n                    \\n                    const coin = coinMatch[1];\\n                    const result = monitorPosition(coin);\\n                    \\n                    monitoringResults[coin] = result;\\n                    \\n                    if (result.status === \\\"closed\\\") {\\n                        const reasonEmoji = result.reason === \\\"profit\\\" ? \\\"🎉\\\" : \\\"💔\\\";\\n                        Log(`${reasonEmoji} ${coin} 已自动平仓 - ${result.reason === \\\"profit\\\" ? \\\"止盈\\\" : \\\"止损\\\"} ${(result.pnl * 100).toFixed(2)}%`);\\n                        totalActions++;\\n                    }\\n                    \\n                    Sleep(500);\\n                }\\n            });\\n        } \\n        \\n        // 显示完整的监控仪表板\\n        displayMonitoringDashboard(monitoringResults);\\n        \\n        return {\\n            monitoringResults: monitoringResults,\\n            totalActions: totalActions,\\n            timestamp: Date.now()\\n        };\\n        \\n    } catch (e) {\\n        Log(`❌ 主执行流程失败: ${e.message}`);\\n        Log(`❌ 错误堆栈: ${e.stack}`);\\n        displaySimpleStatus();\\n        return { error: e.message };\\n    }\\n}\\n\\n// 执行主函数并返回结果\\nreturn main();\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[672,704],\"id\":\"ba7692d6-f8dd-45e9-bcae-0d2889db2013\",\"name\":\"止盈止损代码\"},{\"parameters\":{\"notice\":\"\",\"rule\":{\"interval\":[{\"field\":\"minutes\",\"minutesInterval\":15}]}},\"type\":\"n8n-nodes-base.scheduleTrigger\",\"typeVersion\":1.2,\"position\":[512,352],\"id\":\"d1f57f7c-afdd-4116-8070-41186d1ca562\",\"name\":\"策略执行触发器\"},{\"parameters\":{\"notice\":\"\",\"rule\":{\"interval\":[{\"field\":\"seconds\",\"secondsInterval\":15}]}},\"type\":\"n8n-nodes-base.scheduleTrigger\",\"typeVersion\":1.2,\"position\":[512,704],\"id\":\"f0981117-1774-4950-a5de-1b37cd95f63d\",\"name\":\"止盈止损触发器\",\"logLevel\":0}],\"pinData\":{},\"connections\":{\"合并\":{\"main\":[[{\"node\":\"数据合并\",\"type\":\"main\",\"index\":0}]]},\"AI 智能体\":{\"main\":[[{\"node\":\"交易执行\",\"type\":\"main\",\"index\":0}]]},\"参数重置\":{\"main\":[[{\"node\":\"市场数据获取\",\"type\":\"main\",\"index\":0},{\"node\":\"持仓数据获取\",\"type\":\"main\",\"index\":0},{\"node\":\"币种表现统计\",\"type\":\"main\",\"index\":0}]]},\"OpenAI 模型\":{\"ai_languageModel\":[[{\"node\":\"AI 智能体\",\"type\":\"ai_languageModel\",\"index\":0}]]},\"市场数据获取\":{\"main\":[[{\"node\":\"合并\",\"type\":\"main\",\"index\":0}]]},\"持仓数据获取\":{\"main\":[[{\"node\":\"合并\",\"type\":\"main\",\"index\":1}]]},\"数据合并\":{\"main\":[[{\"node\":\"AI 智能体\",\"type\":\"main\",\"index\":0}]]},\"币种表现统计\":{\"main\":[[{\"node\":\"合并\",\"type\":\"main\",\"index\":2}]]},\"策略执行触发器\":{\"main\":[[{\"node\":\"参数重置\",\"type\":\"main\",\"index\":0}]]},\"止盈止损触发器\":{\"main\":[[{\"node\":\"止盈止损代码\",\"type\":\"main\",\"index\":0}]]}},\"active\":false,\"settings\":{\"timezone\":\"Asia/Shanghai\",\"executionOrder\":\"v1\"},\"tags\":[],\"meta\":{\"templateCredsSetupCompleted\":true},\"credentials\":{},\"id\":\"b830c2aa-c71c-4e2d-bfc8-d4f78dc9a82e\",\"plugins\":{},\"mcpClients\":{}},\"startNodes\":[],\"triggerToStartFrom\":{\"name\":\"策略执行触发器\"}}"}