Ai Contest Model


创建日期: 2025-11-12 13:05:18 最后修改: 2025-11-12 13:05:18
复制: 0 点击次数: 118
avatar of ianzeng123 ianzeng123
2
关注
319
关注者
策略源码
{"type":"n8n","content":"{\"workflowData\":{\"nodes\":[{\"parameters\":{\"notice\":\"\",\"rule\":{\"interval\":[{\"field\":\"minutes\",\"minutesInterval\":10}]}},\"type\":\"n8n-nodes-base.scheduleTrigger\",\"typeVersion\":1.2,\"position\":[-832,1008],\"id\":\"51bf46b2-aa9d-473b-9ecb-b46c117ccc7d\",\"name\":\"Schedule Trigger\"},{\"parameters\":{\"model\":{\"__rl\":true,\"value\":\"anthropic/claude-sonnet-4.5\",\"mode\":\"list\",\"cachedResultName\":\"anthropic/claude-sonnet-4.5\"}},\"type\":\"n8n-nodes-base.lmOpenAi\",\"typeVersion\":1,\"position\":[-64,528],\"id\":\"e446f6ce-c557-446b-9046-ade09823003f\",\"name\":\"Claude4.5\",\"credentials\":{\"openAiApi\":{\"id\":\"54d0b567-b3fc-4c6a-b6be-546e0b9cd83f\",\"name\":\"openrouter\"}}},{\"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\":[-64,128],\"id\":\"7f39c609-676b-40e2-b025-2df3aaf326b1\",\"name\":\"DS3.1\",\"credentials\":{\"openAiApi\":{\"id\":\"54d0b567-b3fc-4c6a-b6be-546e0b9cd83f\",\"name\":\"openrouter\"}}},{\"parameters\":{\"text\":\"=You are a professional cryptocurrency quantitative trading analyst. Please provide trading decision recommendations based on the following multi-timeframe technical indicators, current position information, and competitive ranking.\\n\\n## Competition Status\\nYou are the {{ $json.ranking.currentModel }} AI model, currently ranked {{ $json.ranking.currentRank }} out of {{ $json.ranking.totalModels }} AI models in the trading competition.\\n{{$json.ranking.currentPnl === 0 && $json.ranking.totalTrades === 0 ? 'Competition just started! This is a great opportunity to establish profit foundation! Actively seek quality trading opportunities in the initial phase!' : ''}}\\n\\n### Current Performance\\n- Your Realized PnL: {{ $json.ranking.currentPnl }} USDT {{ $json.ranking.currentPnl === 0 ? '(Initial State)' : '' }}\\n- Your Total Asset Value: {{ $json.ranking.currentTotalValue }} USDT\\n- Total Trades: {{ $json.ranking.totalTrades }} {{ $json.ranking.totalTrades === 0 ? '(No trades yet)' : '' }}\\n- Win Rate: {{ $json.ranking.winRate }}%{{ $json.ranking.totalTrades === 0 ? ' (No data)' : '' }}\\n\\n### Competitor Rankings\\n{{ $json.ranking.rankingText }}\\n{{ $json.ranking.currentPnl === 0 && $json.ranking.totalTrades === 0 ? 'Competition begins!!!' : $json.ranking.gapInfo}}\\n\\n## Current Data Overview\\n- Trading Pair: {{ $json.symbol }}\\n- Analysis Time: {{ new Date($json.timestamp).toLocaleString() }}\\n- Current Position: {{ $json.position && $json.position.length > 0 ? 'Has Position' : 'No Position' }}\\n\\n## Technical Indicators Data (OLDEST-NEWEST)\\n### Daily Timeframe (Trend Analysis)\\n- Price: {{ $json.timeframes.day?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.day?.RSI || 'N/A' }} \\n- MACD Histogram: {{ $json.timeframes.day?.MACD.histogram || 'N/A' }} \\n- ATR: {{ $json.timeframes.day?.ATR || 'N/A' }} \\n- OBV: {{ $json.timeframes.day?.OBV || 'N/A' }} \\n\\n### Hourly Timeframe (Mid-term Trend)\\n- Price: {{ $json.timeframes.hour?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.hour?.RSI || 'N/A' }}\\n- MACD Histogram: {{ $json.timeframes.hour?.MACD.histogram || 'N/A' }}\\n- ATR: {{ $json.timeframes.hour?.ATR || 'N/A' }}\\n- OBV: {{ $json.timeframes.hour?.OBV || 'N/A' }}\\n\\n### 5-Minute Timeframe (Entry Timing)\\n- Price: {{ $json.timeframes.min5?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.min5?.RSI || 'N/A' }}\\n- MACD Histogram: {{ $json.timeframes.min5?.MACD.histogram || 'N/A' }}\\n- ATR: {{ $json.timeframes.min5?.ATR || 'N/A' }}\\n- OBV: {{ $json.timeframes.min5?.OBV || 'N/A' }}\\n\\n### Current Position Info\\n{{JSON.stringify($json.position, null, 2)}}\\n\\n## Analysis Requirements\\nDevelop optimal trading strategy based on technical indicators and your competitive ranking. Your goal is to continuously create more profit, not simply maintain ranking. {{ $json.ranking.totalTrades === 0 ? 'As the competition starts, actively seek high-quality trading opportunities to establish profit foundation.' : 'Continue seeking quality trading opportunities to expand profits, avoid being overly conservative and missing profit chances.' }}\\n\\n### Strategy Recommendations:\\n{{ $json.ranking.totalTrades === 0 ? '- Competition just started, actively find best entry timing to establish profit foundation' : $json.ranking.currentRank > 1 ? '- You are currently behind, actively seek more quality trading opportunities to catch up and create profits' : '- You are performing well, continue active trading to expand profit advantage' }}\\n- Carefully analyze multi-timeframe indicator consistency\\n- Execute trades decisively when technical signals are clear\\n- {{ $json.ranking.totalTrades === 0 ? 'First trade should establish good start' : 'Continue seeking profit opportunities, avoid being overly conservative' }}\\n- Focus on risk-reward ratio, not ranking protection\\n\\n### Executable Actions:\\n- **OPEN_LONG**: Open long position (when no position)\\n- **OPEN_SHORT**: Open short position (when no position)  \\n- **CLOSE_LONG**: Close long position (when holding long)\\n- **CLOSE_SHORT**: Close short position (when holding short)\\n- **NO_ACTION**: Wait and watch (when technical signals unclear)\\n\\n### Execution Criteria:\\n- Prioritize profit creation opportunities\\n- {{ $json.ranking.totalTrades === 0 ? 'First trade requires establishing profit foundation' : 'Continue seeking high-quality trading opportunities to expand total profits' }}\\n- Balance risk control with profit pursuit\\n- Only choose NO_ACTION when technical signals clearly conflict\\n\\n## Return Format\\n```json\\n{\\n  \\\"action\\\": \\\"OPEN_LONG | OPEN_SHORT | CLOSE_LONG | CLOSE_SHORT | NO_ACTION\\\",\\n  \\\"reasoning\\\": \\\"Concise decision rationale combining technical indicators and profit creation goals\\\",\\n  \\\"modelname\\\": \\\"{{ $json.ranking.currentModel }}\\\"\\n}\\n```\\nProvide direct judgment.\",\"options\":{}},\"type\":\"@n8n/n8n-nodes-langchain.agent\",\"typeVersion\":1,\"position\":[-160,-96],\"id\":\"ccff925e-e79a-4865-a204-6348cb37ac5f\",\"name\":\"DeepSeek\",\"retryOnFail\":true,\"onError\":\"continueRegularOutput\"},{\"parameters\":{\"text\":\"=You are a professional cryptocurrency quantitative trading analyst. Please provide trading decision recommendations based on the following multi-timeframe technical indicators, current position information, and competitive ranking.\\n\\n## Competition Status\\nYou are the {{ $json.ranking.currentModel }} AI model, currently ranked {{ $json.ranking.currentRank }} out of {{ $json.ranking.totalModels }} AI models in the trading competition.\\n{{$json.ranking.currentPnl === 0 && $json.ranking.totalTrades === 0 ? 'Competition just started! This is a great opportunity to establish profit foundation! Actively seek quality trading opportunities in the initial phase!' : ''}}\\n\\n### Current Performance\\n- Your Realized PnL: {{ $json.ranking.currentPnl }} USDT {{ $json.ranking.currentPnl === 0 ? '(Initial State)' : '' }}\\n- Your Total Asset Value: {{ $json.ranking.currentTotalValue }} USDT\\n- Total Trades: {{ $json.ranking.totalTrades }} {{ $json.ranking.totalTrades === 0 ? '(No trades yet)' : '' }}\\n- Win Rate: {{ $json.ranking.winRate }}%{{ $json.ranking.totalTrades === 0 ? ' (No data)' : '' }}\\n\\n### Competitor Rankings\\n{{ $json.ranking.rankingText }}\\n{{ $json.ranking.currentPnl === 0 && $json.ranking.totalTrades === 0 ? 'Competition begins!!!' : $json.ranking.gapInfo}}\\n\\n## Current Data Overview\\n- Trading Pair: {{ $json.symbol }}\\n- Analysis Time: {{ new Date($json.timestamp).toLocaleString() }}\\n- Current Position: {{ $json.position && $json.position.length > 0 ? 'Has Position' : 'No Position' }}\\n\\n## Technical Indicators Data (OLDEST-NEWEST)\\n### Daily Timeframe (Trend Analysis)\\n- Price: {{ $json.timeframes.day?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.day?.RSI || 'N/A' }} \\n- MACD Histogram: {{ $json.timeframes.day?.MACD.histogram || 'N/A' }} \\n- ATR: {{ $json.timeframes.day?.ATR || 'N/A' }} \\n- OBV: {{ $json.timeframes.day?.OBV || 'N/A' }} \\n\\n### Hourly Timeframe (Mid-term Trend)\\n- Price: {{ $json.timeframes.hour?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.hour?.RSI || 'N/A' }}\\n- MACD Histogram: {{ $json.timeframes.hour?.MACD.histogram || 'N/A' }}\\n- ATR: {{ $json.timeframes.hour?.ATR || 'N/A' }}\\n- OBV: {{ $json.timeframes.hour?.OBV || 'N/A' }}\\n\\n### 5-Minute Timeframe (Entry Timing)\\n- Price: {{ $json.timeframes.min5?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.min5?.RSI || 'N/A' }}\\n- MACD Histogram: {{ $json.timeframes.min5?.MACD.histogram || 'N/A' }}\\n- ATR: {{ $json.timeframes.min5?.ATR || 'N/A' }}\\n- OBV: {{ $json.timeframes.min5?.OBV || 'N/A' }}\\n\\n### Current Position Info\\n{{JSON.stringify($json.position, null, 2)}}\\n\\n## Analysis Requirements\\nDevelop optimal trading strategy based on technical indicators and your competitive ranking. Your goal is to continuously create more profit, not simply maintain ranking. {{ $json.ranking.totalTrades === 0 ? 'As the competition starts, actively seek high-quality trading opportunities to establish profit foundation.' : 'Continue seeking quality trading opportunities to expand profits, avoid being overly conservative and missing profit chances.' }}\\n\\n### Strategy Recommendations:\\n{{ $json.ranking.totalTrades === 0 ? '- Competition just started, actively find best entry timing to establish profit foundation' : $json.ranking.currentRank > 1 ? '- You are currently behind, actively seek more quality trading opportunities to catch up and create profits' : '- You are performing well, continue active trading to expand profit advantage' }}\\n- Carefully analyze multi-timeframe indicator consistency\\n- Execute trades decisively when technical signals are clear\\n- {{ $json.ranking.totalTrades === 0 ? 'First trade should establish good start' : 'Continue seeking profit opportunities, avoid being overly conservative' }}\\n- Focus on risk-reward ratio, not ranking protection\\n\\n### Executable Actions:\\n- **OPEN_LONG**: Open long position (when no position)\\n- **OPEN_SHORT**: Open short position (when no position)  \\n- **CLOSE_LONG**: Close long position (when holding long)\\n- **CLOSE_SHORT**: Close short position (when holding short)\\n- **NO_ACTION**: Wait and watch (when technical signals unclear)\\n\\n### Execution Criteria:\\n- Prioritize profit creation opportunities\\n- {{ $json.ranking.totalTrades === 0 ? 'First trade requires establishing profit foundation' : 'Continue seeking high-quality trading opportunities to expand total profits' }}\\n- Balance risk control with profit pursuit\\n- Only choose NO_ACTION when technical signals clearly conflict\\n\\n## Return Format\\n```json\\n{\\n  \\\"action\\\": \\\"OPEN_LONG | OPEN_SHORT | CLOSE_LONG | CLOSE_SHORT | NO_ACTION\\\",\\n  \\\"reasoning\\\": \\\"Concise decision rationale combining technical indicators and profit creation goals\\\",\\n  \\\"modelname\\\": \\\"{{ $json.ranking.currentModel }}\\\"\\n}\\n```\\nProvide direct judgment.\",\"options\":{}},\"type\":\"@n8n/n8n-nodes-langchain.agent\",\"typeVersion\":1,\"position\":[-160,304],\"id\":\"b0a0814f-d64b-4bb5-b1e2-bc05b03f9be3\",\"name\":\"Claude\",\"retryOnFail\":true,\"onError\":\"continueRegularOutput\"},{\"parameters\":{\"text\":\"=You are a professional cryptocurrency quantitative trading analyst. Please provide trading decision recommendations based on the following multi-timeframe technical indicators, current position information, and competitive ranking.\\n\\n## Competition Status\\nYou are the {{ $json.ranking.currentModel }} AI model, currently ranked {{ $json.ranking.currentRank }} out of {{ $json.ranking.totalModels }} AI models in the trading competition.\\n{{$json.ranking.currentPnl === 0 && $json.ranking.totalTrades === 0 ? 'Competition just started! This is a great opportunity to establish profit foundation! Actively seek quality trading opportunities in the initial phase!' : ''}}\\n\\n### Current Performance\\n- Your Realized PnL: {{ $json.ranking.currentPnl }} USDT {{ $json.ranking.currentPnl === 0 ? '(Initial State)' : '' }}\\n- Your Total Asset Value: {{ $json.ranking.currentTotalValue }} USDT\\n- Total Trades: {{ $json.ranking.totalTrades }} {{ $json.ranking.totalTrades === 0 ? '(No trades yet)' : '' }}\\n- Win Rate: {{ $json.ranking.winRate }}%{{ $json.ranking.totalTrades === 0 ? ' (No data)' : '' }}\\n\\n### Competitor Rankings\\n{{ $json.ranking.rankingText }}\\n{{ $json.ranking.currentPnl === 0 && $json.ranking.totalTrades === 0 ? 'Competition begins!!!' : $json.ranking.gapInfo}}\\n\\n## Current Data Overview\\n- Trading Pair: {{ $json.symbol }}\\n- Analysis Time: {{ new Date($json.timestamp).toLocaleString() }}\\n- Current Position: {{ $json.position && $json.position.length > 0 ? 'Has Position' : 'No Position' }}\\n\\n## Technical Indicators Data (OLDEST-NEWEST)\\n### Daily Timeframe (Trend Analysis)\\n- Price: {{ $json.timeframes.day?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.day?.RSI || 'N/A' }} \\n- MACD Histogram: {{ $json.timeframes.day?.MACD.histogram || 'N/A' }} \\n- ATR: {{ $json.timeframes.day?.ATR || 'N/A' }} \\n- OBV: {{ $json.timeframes.day?.OBV || 'N/A' }} \\n\\n### Hourly Timeframe (Mid-term Trend)\\n- Price: {{ $json.timeframes.hour?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.hour?.RSI || 'N/A' }}\\n- MACD Histogram: {{ $json.timeframes.hour?.MACD.histogram || 'N/A' }}\\n- ATR: {{ $json.timeframes.hour?.ATR || 'N/A' }}\\n- OBV: {{ $json.timeframes.hour?.OBV || 'N/A' }}\\n\\n### 5-Minute Timeframe (Entry Timing)\\n- Price: {{ $json.timeframes.min5?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.min5?.RSI || 'N/A' }}\\n- MACD Histogram: {{ $json.timeframes.min5?.MACD.histogram || 'N/A' }}\\n- ATR: {{ $json.timeframes.min5?.ATR || 'N/A' }}\\n- OBV: {{ $json.timeframes.min5?.OBV || 'N/A' }}\\n\\n### Current Position Info\\n{{JSON.stringify($json.position, null, 2)}}\\n\\n## Analysis Requirements\\nDevelop optimal trading strategy based on technical indicators and your competitive ranking. Your goal is to continuously create more profit, not simply maintain ranking. {{ $json.ranking.totalTrades === 0 ? 'As the competition starts, actively seek high-quality trading opportunities to establish profit foundation.' : 'Continue seeking quality trading opportunities to expand profits, avoid being overly conservative and missing profit chances.' }}\\n\\n### Strategy Recommendations:\\n{{ $json.ranking.totalTrades === 0 ? '- Competition just started, actively find best entry timing to establish profit foundation' : $json.ranking.currentRank > 1 ? '- You are currently behind, actively seek more quality trading opportunities to catch up and create profits' : '- You are performing well, continue active trading to expand profit advantage' }}\\n- Carefully analyze multi-timeframe indicator consistency\\n- Execute trades decisively when technical signals are clear\\n- {{ $json.ranking.totalTrades === 0 ? 'First trade should establish good start' : 'Continue seeking profit opportunities, avoid being overly conservative' }}\\n- Focus on risk-reward ratio, not ranking protection\\n\\n### Executable Actions:\\n- **OPEN_LONG**: Open long position (when no position)\\n- **OPEN_SHORT**: Open short position (when no position)  \\n- **CLOSE_LONG**: Close long position (when holding long)\\n- **CLOSE_SHORT**: Close short position (when holding short)\\n- **NO_ACTION**: Wait and watch (when technical signals unclear)\\n\\n### Execution Criteria:\\n- Prioritize profit creation opportunities\\n- {{ $json.ranking.totalTrades === 0 ? 'First trade requires establishing profit foundation' : 'Continue seeking high-quality trading opportunities to expand total profits' }}\\n- Balance risk control with profit pursuit\\n- Only choose NO_ACTION when technical signals clearly conflict\\n\\n## Return Format\\n```json\\n{\\n  \\\"action\\\": \\\"OPEN_LONG | OPEN_SHORT | CLOSE_LONG | CLOSE_SHORT | NO_ACTION\\\",\\n  \\\"reasoning\\\": \\\"Concise decision rationale combining technical indicators and profit creation goals\\\",\\n  \\\"modelname\\\": \\\"{{ $json.ranking.currentModel }}\\\"\\n}\\n```\\nProvide direct judgment.\",\"options\":{}},\"type\":\"@n8n/n8n-nodes-langchain.agent\",\"typeVersion\":1,\"position\":[-160,704],\"id\":\"c0b74a78-1494-4495-ac64-3bd4858fc3a3\",\"name\":\"QWEN\",\"retryOnFail\":true,\"onError\":\"continueRegularOutput\"},{\"parameters\":{\"model\":{\"__rl\":true,\"value\":\"qwen/qwen3-max\",\"mode\":\"list\",\"cachedResultName\":\"qwen/qwen3-max\"}},\"type\":\"n8n-nodes-base.lmOpenAi\",\"typeVersion\":1,\"position\":[-64,928],\"id\":\"4df0f0ac-9736-46ff-aeeb-5f1ddbdea9c9\",\"name\":\"OpenAI Model\",\"credentials\":{\"openAiApi\":{\"id\":\"54d0b567-b3fc-4c6a-b6be-546e0b9cd83f\",\"name\":\"openrouter\"}}},{\"parameters\":{\"text\":\"=You are a professional cryptocurrency quantitative trading analyst. Please provide trading decision recommendations based on the following multi-timeframe technical indicators, current position information, and competitive ranking.\\n\\n## Competition Status\\nYou are the {{ $json.ranking.currentModel }} AI model, currently ranked {{ $json.ranking.currentRank }} out of {{ $json.ranking.totalModels }} AI models in the trading competition.\\n{{$json.ranking.currentPnl === 0 && $json.ranking.totalTrades === 0 ? 'Competition just started! This is a great opportunity to establish profit foundation! Actively seek quality trading opportunities in the initial phase!' : ''}}\\n\\n### Current Performance\\n- Your Realized PnL: {{ $json.ranking.currentPnl }} USDT {{ $json.ranking.currentPnl === 0 ? '(Initial State)' : '' }}\\n- Your Total Asset Value: {{ $json.ranking.currentTotalValue }} USDT\\n- Total Trades: {{ $json.ranking.totalTrades }} {{ $json.ranking.totalTrades === 0 ? '(No trades yet)' : '' }}\\n- Win Rate: {{ $json.ranking.winRate }}%{{ $json.ranking.totalTrades === 0 ? ' (No data)' : '' }}\\n\\n### Competitor Rankings\\n{{ $json.ranking.rankingText }}\\n{{ $json.ranking.currentPnl === 0 && $json.ranking.totalTrades === 0 ? 'Competition begins!!!' : $json.ranking.gapInfo}}\\n\\n## Current Data Overview\\n- Trading Pair: {{ $json.symbol }}\\n- Analysis Time: {{ new Date($json.timestamp).toLocaleString() }}\\n- Current Position: {{ $json.position && $json.position.length > 0 ? 'Has Position' : 'No Position' }}\\n\\n## Technical Indicators Data (OLDEST-NEWEST)\\n### Daily Timeframe (Trend Analysis)\\n- Price: {{ $json.timeframes.day?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.day?.RSI || 'N/A' }} \\n- MACD Histogram: {{ $json.timeframes.day?.MACD.histogram || 'N/A' }} \\n- ATR: {{ $json.timeframes.day?.ATR || 'N/A' }} \\n- OBV: {{ $json.timeframes.day?.OBV || 'N/A' }} \\n\\n### Hourly Timeframe (Mid-term Trend)\\n- Price: {{ $json.timeframes.hour?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.hour?.RSI || 'N/A' }}\\n- MACD Histogram: {{ $json.timeframes.hour?.MACD.histogram || 'N/A' }}\\n- ATR: {{ $json.timeframes.hour?.ATR || 'N/A' }}\\n- OBV: {{ $json.timeframes.hour?.OBV || 'N/A' }}\\n\\n### 5-Minute Timeframe (Entry Timing)\\n- Price: {{ $json.timeframes.min5?.lastPrice || 'N/A' }}\\n- RSI(14): {{ $json.timeframes.min5?.RSI || 'N/A' }}\\n- MACD Histogram: {{ $json.timeframes.min5?.MACD.histogram || 'N/A' }}\\n- ATR: {{ $json.timeframes.min5?.ATR || 'N/A' }}\\n- OBV: {{ $json.timeframes.min5?.OBV || 'N/A' }}\\n\\n### Current Position Info\\n{{JSON.stringify($json.position, null, 2)}}\\n\\n## Analysis Requirements\\nDevelop optimal trading strategy based on technical indicators and your competitive ranking. Your goal is to continuously create more profit, not simply maintain ranking. {{ $json.ranking.totalTrades === 0 ? 'As the competition starts, actively seek high-quality trading opportunities to establish profit foundation.' : 'Continue seeking quality trading opportunities to expand profits, avoid being overly conservative and missing profit chances.' }}\\n\\n### Strategy Recommendations:\\n{{ $json.ranking.totalTrades === 0 ? '- Competition just started, actively find best entry timing to establish profit foundation' : $json.ranking.currentRank > 1 ? '- You are currently behind, actively seek more quality trading opportunities to catch up and create profits' : '- You are performing well, continue active trading to expand profit advantage' }}\\n- Carefully analyze multi-timeframe indicator consistency\\n- Execute trades decisively when technical signals are clear\\n- {{ $json.ranking.totalTrades === 0 ? 'First trade should establish good start' : 'Continue seeking profit opportunities, avoid being overly conservative' }}\\n- Focus on risk-reward ratio, not ranking protection\\n\\n### Executable Actions:\\n- **OPEN_LONG**: Open long position (when no position)\\n- **OPEN_SHORT**: Open short position (when no position)  \\n- **CLOSE_LONG**: Close long position (when holding long)\\n- **CLOSE_SHORT**: Close short position (when holding short)\\n- **NO_ACTION**: Wait and watch (when technical signals unclear)\\n\\n### Execution Criteria:\\n- Prioritize profit creation opportunities\\n- {{ $json.ranking.totalTrades === 0 ? 'First trade requires establishing profit foundation' : 'Continue seeking high-quality trading opportunities to expand total profits' }}\\n- Balance risk control with profit pursuit\\n- Only choose NO_ACTION when technical signals clearly conflict\\n\\n## Return Format\\n```json\\n{\\n  \\\"action\\\": \\\"OPEN_LONG | OPEN_SHORT | CLOSE_LONG | CLOSE_SHORT | NO_ACTION\\\",\\n  \\\"reasoning\\\": \\\"Concise decision rationale combining technical indicators and profit creation goals\\\",\\n  \\\"modelname\\\": \\\"{{ $json.ranking.currentModel }}\\\"\\n}\\n```\\nProvide direct judgment.\",\"options\":{}},\"type\":\"@n8n/n8n-nodes-langchain.agent\",\"typeVersion\":1,\"position\":[-160,1104],\"id\":\"310d7b46-2333-42c5-9c75-753f6f2e2529\",\"name\":\"Grok\",\"retryOnFail\":true,\"onError\":\"continueRegularOutput\"},{\"parameters\":{\"model\":{\"__rl\":true,\"value\":\"x-ai/grok-4\",\"mode\":\"list\",\"cachedResultName\":\"x-ai/grok-4\"}},\"type\":\"n8n-nodes-base.lmOpenAi\",\"typeVersion\":1,\"position\":[-64,1328],\"id\":\"3dabb427-58b9-47b0-ac28-6fb1df083605\",\"name\":\"Grok4\",\"credentials\":{\"openAiApi\":{\"id\":\"54d0b567-b3fc-4c6a-b6be-546e0b9cd83f\",\"name\":\"openrouter\"}}},{\"parameters\":{\"mode\":\"append\",\"numberInputs\":4},\"type\":\"n8n-nodes-base.merge\",\"typeVersion\":3.2,\"position\":[240,944],\"id\":\"ddae2251-7d25-4bee-aacd-f67ab3d8dbf0\",\"name\":\"Merge\"},{\"parameters\":{\"operation\":\"csv\",\"binaryPropertyName\":\"data\",\"options\":{}},\"type\":\"n8n-nodes-base.convertToFile\",\"typeVersion\":1.1,\"position\":[912,1104],\"id\":\"ec0705d4-47ee-4201-8019-3a1b0979b7e3\",\"name\":\"Convert to File\"},{\"parameters\":{\"info\":\"\",\"fileName\":\"tradelog.csv\",\"dataPropertyName\":\"data\",\"options\":{}},\"type\":\"n8n-nodes-base.writeFile\",\"typeVersion\":1,\"position\":[1136,1104],\"id\":\"d67538cf-24e2-47b3-9301-15067aaadcea\",\"name\":\"Write to File\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"// Get AI decision results and clean data\\nconst aiResults = $input.all().map(item => {\\n    if (item.json && item.json.output) {\\n        return { output: item.json.output };\\n    } else if (item.output) {\\n        return { output: item.output };\\n    }\\n    return null;\\n}).filter(item => item !== null);\\n\\nexchange.SetContractType('swap') \\nconst ticker = _C(exchange.GetTicker);\\nconst fixedSize = $vars.size || 0.01; // Fixed trading size\\n\\nif (!ticker || !ticker.Last) {\\n    Log(\\\"Failed to get price\\\");\\n    return $input.all();\\n}\\n\\nconst currentPrice = ticker.Last;\\nconst timestamp = Date.now();\\n\\n// Get contract value\\nconst markets = _G('markets');\\nconst ctVal = markets ? markets.CtVal : 1;\\n\\n// Get model data - use deep copy to avoid modifying original data\\nconst models = JSON.parse(JSON.stringify($node['Strategy Init'].json));\\n\\n// Process each AI's decision\\naiResults.forEach(item => {\\n    Log('Current item:', item)\\n    if (!item.output){\\n      return;\\n    }\\n    \\n    try {\\n        let decision;\\n        \\n        // Try to extract JSON wrapped in markdown\\n        const jsonMatch = item.output.match(/```json\\\\s*([\\\\s\\\\S]*?)\\\\s*```/);\\n        \\n        if (jsonMatch) {\\n            // Claude format: ```json ... ```\\n            decision = JSON.parse(jsonMatch[1]);\\n        } else {\\n            // DS format: direct JSON\\n            decision = JSON.parse(item.output);\\n        }\\n        \\n        const modelKey = decision.modelname;\\n\\n        if (!models || !models[modelKey]) {\\n            Log(`Model not found: ${modelKey}`);\\n            return;\\n        }\\n        \\n        const model = models[modelKey];\\n        \\n        // Record decision\\n        model.decisions.push({\\n            timestamp,\\n            action: decision.action,\\n            reasoning: decision.reasoning,\\n            price: currentPrice\\n        });\\n        \\n        // ============ Virtual Position Trading Logic ============\\n        \\n        if (decision.action === 'OPEN_LONG') {\\n            // Check if already has position (virtual position)\\n            if (model.positions.length === 0) {\\n                model.positions.push({\\n                    side: 'long',\\n                    size: fixedSize,\\n                    entryPrice: currentPrice,\\n                    ctVal: ctVal,\\n                    timestamp: timestamp\\n                });\\n                \\n                model.account.totalTrades++;\\n                \\n                model.tradeHistory.push({\\n                    action: 'OPEN_LONG',\\n                    price: currentPrice,\\n                    size: fixedSize,\\n                    ctVal: ctVal,\\n                    timestamp: timestamp\\n                });\\n                \\n                Log(`${modelKey} Virtual open long: ${currentPrice}, size: ${fixedSize}`);\\n            }\\n        }\\n        \\n        else if (decision.action === 'OPEN_SHORT') {\\n            // Check if already has position (virtual position)\\n            if (model.positions.length === 0) {\\n                model.positions.push({\\n                    side: 'short',\\n                    size: fixedSize,\\n                    entryPrice: currentPrice,\\n                    ctVal: ctVal,\\n                    timestamp: timestamp\\n                });\\n                \\n                model.account.totalTrades++;\\n                \\n                model.tradeHistory.push({\\n                    action: 'OPEN_SHORT',\\n                    price: currentPrice,\\n                    size: fixedSize,\\n                    ctVal: ctVal,\\n                    timestamp: timestamp\\n                });\\n                \\n                Log(`${modelKey} Virtual open short: ${currentPrice}, size: ${fixedSize}`);\\n            }\\n        }\\n        \\n        else if (decision.action === 'CLOSE_LONG' || decision.action === 'CLOSE_SHORT') {\\n            // Close position (virtual position)\\n            const targetSide = decision.action === 'CLOSE_LONG' ? 'long' : 'short';\\n            const posIndex = model.positions.findIndex(pos => pos.side === targetSide);\\n            \\n            if (posIndex !== -1) {\\n                const position = model.positions[posIndex];\\n                \\n                // ✅ Fix: Calculate absolute PnL (don't divide by entryPrice)\\n                const pnl = position.side === 'long' \\n                    ? (currentPrice - position.entryPrice) * position.size * position.ctVal\\n                    : (position.entryPrice - currentPrice) * position.size * position.ctVal;\\n                \\n                // Opening and closing fees\\n                const openFee = position.size * position.ctVal * 0.001;\\n                const closeFee = position.size * position.ctVal * 0.001;\\n                const totalFee = openFee + closeFee;\\n                \\n                const netPnl = pnl - totalFee;\\n                \\n                // Accumulate to total PnL\\n                model.account.realizedPnl += netPnl;\\n                \\n                if (netPnl > 0) model.account.winTrades++;\\n                \\n                model.tradeHistory.push({\\n                    action: decision.action,\\n                    price: currentPrice,\\n                    size: position.size,\\n                    ctVal: position.ctVal,\\n                    entryPrice: position.entryPrice,\\n                    pnl: netPnl,\\n                    fee: totalFee,\\n                    timestamp: timestamp\\n                });\\n                \\n                Log(`${modelKey} Virtual close: ${currentPrice}, PnL: ${netPnl.toFixed(2)}`);\\n                \\n                // Remove virtual position\\n                model.positions.splice(posIndex, 1);\\n            }\\n        }\\n        \\n        // ✅ Fix: Calculate unrealized PnL (don't divide by entryPrice)\\n        let unrealizedPnl = 0;\\n        model.positions.forEach(pos => {\\n            if (pos.side === 'long') {\\n                unrealizedPnl += (currentPrice - pos.entryPrice) * pos.size * pos.ctVal;\\n            } else {\\n                unrealizedPnl += (pos.entryPrice - currentPrice) * pos.size * pos.ctVal;\\n            }\\n        });\\n        \\n        model.account.totalValue = model.account.initialBalance + model.account.realizedPnl + unrealizedPnl;\\n        model.account.balance = model.account.totalValue;\\n        \\n    } catch (error) {\\n        Log(`Error processing decision: ${error.message}`);\\n        Log(`Original output: ${item.output}`);\\n    }\\n});\\n\\n// Save updated models to _G\\n_G('models', models);\\n\\nreturn models;\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[464,1008],\"id\":\"43ca06e2-2047-4005-bdb9-3aaa810881e8\",\"name\":\"Result Calculation\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"// Extract and format all models' trading data\\nconst inputData = $input.all()[0].json;\\n\\n// ✅ Automatically get model list from data\\nconst models = Object.keys(inputData);\\n\\n// Build result array\\nconst results = models.map(model => {\\n  const data = inputData[model];\\n  \\n  // ✅ Safety check\\n  if (!data || !data.account) {\\n    Log(`Warning: Model ${model} data incomplete, skipping`);\\n    return null;\\n  }\\n  \\n  // Get latest decision\\n  const latestDecision = data.decisions && data.decisions.length > 0 \\n    ? data.decisions[data.decisions.length - 1] \\n    : null;\\n  \\n  // Get current position\\n  const currentPosition = data.positions && data.positions.length > 0\\n    ? data.positions[0]\\n    : null;\\n  \\n  return {\\n    // Model name\\n    model: model,\\n    \\n    // Account info\\n    initialBalance: data.account.initialBalance,\\n    balance: data.account.balance,\\n    totalValue: data.account.totalValue,\\n    realizedPnl: data.account.realizedPnl,\\n    totalTrades: data.account.totalTrades,\\n    winTrades: data.account.winTrades,\\n    winRate: data.account.totalTrades > 0 \\n      ? ((data.account.winTrades / data.account.totalTrades) * 100).toFixed(2) + '%'\\n      : '0%',\\n    \\n    // Position info\\n    hasPosition: currentPosition ? 'YES' : 'NO',\\n    positionType: currentPosition?.type || '-',\\n    positionSize: currentPosition?.size || 0,\\n    entryPrice: currentPosition?.entryPrice || 0,\\n    currentPrice: currentPosition?.currentPrice || 0,\\n    unrealizedPnl: currentPosition?.unrealizedPnl || 0,\\n    \\n    // Latest decision\\n    latestAction: latestDecision?.action || 'NO_DECISION',\\n    latestPrice: latestDecision?.price || 0,\\n    latestTimestamp: latestDecision?.timestamp || 0,\\n    latestReasoning: latestDecision?.reasoning || '-',\\n    \\n    // Trade history stats\\n    tradeHistoryCount: data.tradeHistory.length,\\n    decisionsCount: data.decisions.length,\\n    \\n    // Add timestamp\\n    recordTime: new Date().toISOString()\\n  };\\n}).filter(item => item !== null); // ✅ Filter invalid data\\n\\nlet tradelog = _G('tradelog') || [];\\n\\n// Add current records for all models\\ntradelog.push({\\n  timestamp: new Date().toISOString(),\\n  models: results\\n});\\n\\n_G('tradelog', tradelog);\\n\\n// Return data for next node\\nreturn tradelog;\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[688,1008],\"id\":\"afd7d308-7491-4bc0-959b-71f74271452e\",\"name\":\"Trade Log Save\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"// Get all model data\\nconst inputData = $node['Result Calculation'].json;\\n\\n// Get currently active model for real trading (if any)\\nlet activeModel = _G('activeModel') || null;\\nlet highestPnl = _G('highestPnl') || 15; // Initial threshold\\n\\nLog('highestPnl:', highestPnl)\\n\\n// Iterate through all models to find best performing model\\nlet bestModel = null;\\nlet bestPnl = highestPnl;\\n\\nObject.keys(inputData).forEach(modelName => {\\n    const model = inputData[modelName];\\n    const realizedPnl = model.account.realizedPnl;\\n    \\n    // Find model with highest PnL\\n    if (realizedPnl > bestPnl) {\\n        bestPnl = realizedPnl;\\n        bestModel = modelName;\\n    }\\n});\\n\\n// Decision logic\\nlet shouldTrade = false;\\nlet tradeAction = null;\\nlet modelChanged = false;\\n\\nif (bestModel) {\\n    // If no active model and found profitable model\\n    if (!activeModel) {\\n        activeModel = bestModel;\\n        highestPnl = bestPnl;\\n        modelChanged = true;\\n        Log(`🎯 Start real trading! Selected model: ${activeModel}, PnL: ${bestPnl.toFixed(2)} USDT`);\\n    } \\n    // If current model is not the best, switch to best model\\n    else if (bestModel !== activeModel) {\\n        Log(`🔄 Model switch: ${activeModel} (${highestPnl.toFixed(2)}) -> ${bestModel} (${bestPnl.toFixed(2)})`);\\n        activeModel = bestModel;\\n        highestPnl = bestPnl;\\n        modelChanged = true;\\n    }\\n    \\n    // Get paper position status of active model\\n    const activeModelData = inputData[activeModel];\\n    const paperPositions = activeModelData.positions || [];\\n    \\n    // Get real position status\\n    const realPositions = exchange.GetPosition();\\n    const hasRealLong = realPositions && realPositions.some(p => p.Type === PD_LONG && p.Amount > 0);\\n    const hasRealShort = realPositions && realPositions.some(p => p.Type === PD_SHORT && p.Amount > 0);\\n    \\n    // Paper position status\\n    const hasPaperLong = paperPositions.some(p => p.side === 'long');\\n    const hasPaperShort = paperPositions.some(p => p.side === 'short');\\n    \\n    // Sync logic: make real position match paper position\\n    if (hasPaperLong && !hasRealLong) {\\n        // Paper has long, real doesn't have long\\n        if (hasRealShort) {\\n            // If real has short, close short first\\n            shouldTrade = true;\\n            tradeAction = {\\n                model: activeModel,\\n                action: 'CLOSE_SHORT',\\n                reason: 'Sync position: close short first',\\n                paperPosition: paperPositions[0],\\n                modelPnl: activeModelData.account.realizedPnl\\n            };\\n        } else {\\n            // Real has no position, open long\\n            shouldTrade = true;\\n            tradeAction = {\\n                model: activeModel,\\n                action: 'OPEN_LONG',\\n                reason: 'Sync position: open long',\\n                paperPosition: paperPositions[0],\\n                modelPnl: activeModelData.account.realizedPnl\\n            };\\n        }\\n    } \\n    else if (hasPaperShort && !hasRealShort) {\\n        // Paper has short, real doesn't have short\\n        if (hasRealLong) {\\n            // If real has long, close long first\\n            shouldTrade = true;\\n            tradeAction = {\\n                model: activeModel,\\n                action: 'CLOSE_LONG',\\n                reason: 'Sync position: close long first',\\n                paperPosition: paperPositions[0],\\n                modelPnl: activeModelData.account.realizedPnl\\n            };\\n        } else {\\n            // Real has no position, open short\\n            shouldTrade = true;\\n            tradeAction = {\\n                model: activeModel,\\n                action: 'OPEN_SHORT',\\n                reason: 'Sync position: open short',\\n                paperPosition: paperPositions[0],\\n                modelPnl: activeModelData.account.realizedPnl\\n            };\\n        }\\n    }\\n    else if (!hasPaperLong && !hasPaperShort && (hasRealLong || hasRealShort)) {\\n        // Paper has no position but real has position, need to close\\n        if (hasRealLong) {\\n            shouldTrade = true;\\n            tradeAction = {\\n                model: activeModel,\\n                action: 'CLOSE_LONG',\\n                reason: 'Sync position: paper already closed',\\n                modelPnl: activeModelData.account.realizedPnl\\n            };\\n        } else if (hasRealShort) {\\n            shouldTrade = true;\\n            tradeAction = {\\n                model: activeModel,\\n                action: 'CLOSE_SHORT',\\n                reason: 'Sync position: paper already closed',\\n                modelPnl: activeModelData.account.realizedPnl\\n            };\\n        }\\n    }\\n}\\n\\n// Save state\\n_G('activeModel', activeModel);\\n_G('highestPnl', highestPnl);\\n\\n// Execute real trade\\nif (shouldTrade && tradeAction) {\\n    const symbol = $vars.coin + \\\"_USDT.swap\\\";\\n    const size = $vars.size || 0.01;\\n    \\n    Log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);\\n    Log(`🤖 Real trade execution (sync paper position)`);\\n    Log(`Model: ${tradeAction.model}`);\\n    Log(`Action: ${tradeAction.action}`);\\n    Log(`Reason: ${tradeAction.reason}`);\\n    Log(`Size: ${size}`);\\n    Log(`Model PnL: ${tradeAction.modelPnl.toFixed(2)} USDT`);\\n    if (tradeAction.paperPosition) {\\n        Log(`Paper position: ${tradeAction.paperPosition.side}, entry price: ${tradeAction.paperPosition.entryPrice}`);\\n    }\\n    Log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);\\n    \\n    try {\\n        // Get current position\\n        const positions = exchange.GetPosition();\\n        const hasLongPosition = positions && positions.some(p => p.Type === PD_LONG && p.Amount > 0);\\n        const hasShortPosition = positions && positions.some(p => p.Type === PD_SHORT && p.Amount > 0);\\n        \\n        // Execute trade\\n        if (tradeAction.action === 'OPEN_LONG' && !hasLongPosition && !hasShortPosition) {\\n            exchange.SetDirection(\\\"buy\\\");\\n            const orderId = exchange.Buy(-1, size);\\n            Log(`✅ Open long success, order ID: ${orderId}`);\\n        } \\n        else if (tradeAction.action === 'OPEN_SHORT' && !hasLongPosition && !hasShortPosition) {\\n            exchange.SetDirection(\\\"sell\\\");\\n            const orderId = exchange.Sell(-1, size);\\n            Log(`✅ Open short success, order ID: ${orderId}`);\\n        }\\n        else if (tradeAction.action === 'CLOSE_LONG' && hasLongPosition) {\\n            const longPos = positions.find(p => p.Type === PD_LONG && p.Amount > 0);\\n            exchange.SetDirection(\\\"closebuy\\\");\\n            const orderId = exchange.Sell(-1, longPos.Amount);\\n            Log(`✅ Close long success, order ID: ${orderId}`);\\n        }\\n        else if (tradeAction.action === 'CLOSE_SHORT' && hasShortPosition) {\\n            const shortPos = positions.find(p => p.Type === PD_SHORT && p.Amount > 0);\\n            exchange.SetDirection(\\\"closesell\\\");\\n            const orderId = exchange.Buy(-1, shortPos.Amount);\\n            Log(`✅ Close short success, order ID: ${orderId}`);\\n        }\\n        else {\\n            Log(`⚠️ Cannot execute trade: position status mismatch`);\\n        }\\n    } catch (error) {\\n        Log(`❌ Trade execution failed: ${error.message}`);\\n    }\\n}\\n\\n// Return status info\\nreturn [{\\n    json: {\\n        activeModel: activeModel,\\n        highestPnl: highestPnl,\\n        shouldTrade: shouldTrade,\\n        modelChanged: modelChanged,\\n        tradeAction: tradeAction,\\n        allModelsStatus: Object.keys(inputData).map(modelName => {\\n            const model = inputData[modelName];\\n            return {\\n                model: modelName,\\n                realizedPnl: model.account.realizedPnl,\\n                totalValue: model.account.totalValue,\\n                isActive: modelName === activeModel,\\n                paperPosition: model.positions.length > 0 ? model.positions[0].side : 'none'\\n            };\\n        }).sort((a, b) => b.realizedPnl - a.realizedPnl)\\n    }\\n}];\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[912,912],\"id\":\"0c0712b8-3144-4516-855f-3b30876b7f0f\",\"name\":\"Best Trade\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"api_base = \\\"https://testnet.binancefuture.com\\\"\\nexchange.SetBase(api_base)\\n\\n// Get and split model list\\nconst modelListStr = $vars.modelList || '';\\nconst modelList = modelListStr.split(',').filter(name => name.trim());\\n\\nif (modelList.length === 0) {\\n    return {};\\n}\\n\\n// Initialize global container\\nif (!_G('models')) {\\n    _G('models', {});\\n    _G('tradelog')\\n\\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 symbol = $vars.coin + '_USDT.swap';\\n    _G('markets', allMarkets[symbol]);\\n    Log(_G('markets'))\\n    \\n    const initAccount = exchange.GetAccount();\\n    _G('initmoney', initAccount.Balance);\\n}\\n\\n// Create trading system for each model\\nmodelList.forEach(modelName => {\\n    const key = modelName.trim();\\n    const models = _G('models');\\n    \\n    if (!models[key]) {\\n        models[key] = {\\n            account: {\\n                initialBalance: 10000,  // Add initial capital\\n                balance: 10000,\\n                totalValue: 10000,\\n                realizedPnl: 0,\\n                totalTrades: 0,\\n                winTrades: 0\\n            },\\n            positions: [],\\n            tradeHistory: [],\\n            decisions: []\\n        };\\n        _G('models', models);\\n    }\\n});\\n\\nreturn _G('models');\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[-608,1008],\"id\":\"33ff8eab-dc47-4794-8667-55e0ea29db25\",\"name\":\"Strategy Init\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"// ========== AI Model Competition Visualization Dashboard ==========\\n\\n/**\\n * Safe formatting helper functions\\n */\\nfunction safeFormat(value, decimals = 2, prefix = '') {\\n    if (value === null || value === undefined || isNaN(value)) {\\n        return prefix + '0';\\n    }\\n    return prefix + _N(value, decimals);\\n}\\n\\nfunction safePercentage(numerator, denominator, decimals = 1) {\\n    if (!denominator || denominator === 0) return '0%';\\n    const result = (numerator / denominator) * 100;\\n    return safeFormat(result, decimals) + '%';\\n}\\n\\n/**\\n * Table 1: Model Running Status\\n */\\nfunction createModelStatusTable(allModelsStatus, models) {\\n    const statusTable = {\\n        type: \\\"table\\\",\\n        title: \\\"🤖 AI Model Real-time Status\\\",\\n        cols: [\\\"Model\\\", \\\"Active\\\", \\\"Initial\\\", \\\"Current\\\", \\\"Realized\\\", \\\"Profit%\\\", \\\"Paper Pos\\\", \\\"Trades\\\", \\\"Win%\\\", \\\"Latest Decision\\\", \\\"Decision Price\\\", \\\"Reasoning\\\"],\\n        rows: []\\n    };\\n    \\n    try {\\n        allModelsStatus.forEach(model => {\\n            const modelData = models[model.model];\\n            if (!modelData) {\\n                Log(`Warning: Model data not found ${model.model}`);\\n                return;\\n            }\\n            \\n            const latestDecision = modelData.decisions && modelData.decisions.length > 0\\n                ? modelData.decisions[modelData.decisions.length - 1]\\n                : null;\\n            \\n            const profitRate = ((modelData.account.realizedPnl || 0) / (modelData.account.initialBalance || 1)) * 100;\\n            \\n            // Profit rate display\\n            let profitRateDisplay = \\\"\\\";\\n            if (profitRate > 5) {\\n                profitRateDisplay = `🔥 +${safeFormat(profitRate)}%`;\\n            } else if (profitRate > 0) {\\n                profitRateDisplay = `🟢 +${safeFormat(profitRate)}%`;\\n            } else if (profitRate < 0) {\\n                profitRateDisplay = `🔴 ${safeFormat(profitRate)}%`;\\n            } else {\\n                profitRateDisplay = `⚪ 0%`;\\n            }\\n            \\n            // Position display\\n            let positionDisplay = \\\"\\\";\\n            if (model.paperPosition === 'none') {\\n                positionDisplay = \\\"📭 Empty\\\";\\n            } else if (model.paperPosition === 'long') {\\n                positionDisplay = \\\"📈 Long\\\";\\n            } else {\\n                positionDisplay = \\\"📉 Short\\\";\\n            }\\n            \\n            // Decision display\\n            let actionDisplay = latestDecision?.action || \\\"None\\\";\\n            switch(actionDisplay) {\\n                case 'OPEN_LONG':\\n                    actionDisplay = \\\"🟢 Open Long\\\";\\n                    break;\\n                case 'OPEN_SHORT':\\n                    actionDisplay = \\\"🔴 Open Short\\\";\\n                    break;\\n                case 'CLOSE_LONG':\\n                    actionDisplay = \\\"⏹️ Close Long\\\";\\n                    break;\\n                case 'CLOSE_SHORT':\\n                    actionDisplay = \\\"⏹️ Close Short\\\";\\n                    break;\\n                case 'NO_ACTION':\\n                    actionDisplay = \\\"⏸️ Wait\\\";\\n                    break;\\n            }\\n            \\n            const realizedPnl = modelData.account.realizedPnl || 0;\\n            let pnlDisplay = \\\"\\\";\\n            if (realizedPnl > 0) {\\n                pnlDisplay = `🟢 ${safeFormat(realizedPnl, 2, \\\"$\\\")}`;\\n            } else if (realizedPnl < 0) {\\n                pnlDisplay = `🔴 ${safeFormat(realizedPnl, 2, \\\"$\\\")}`;\\n            } else {\\n                pnlDisplay = `⚪ $0`;\\n            }\\n            \\n            statusTable.rows.push([\\n                `${model.isActive ? '⭐' : '💎'} ${model.model}`,\\n                model.isActive ? \\\"✅\\\" : \\\"❌\\\",\\n                safeFormat(modelData.account.initialBalance, 2, \\\"$\\\"),\\n                safeFormat(modelData.account.totalValue, 2, \\\"$\\\"),\\n                pnlDisplay,\\n                profitRateDisplay,\\n                positionDisplay,\\n                modelData.account.totalTrades || 0,\\n                safePercentage(modelData.account.winTrades || 0, modelData.account.totalTrades || 1),\\n                actionDisplay,\\n                latestDecision?.price ? safeFormat(latestDecision.price, 2, \\\"$\\\") : '-',\\n                latestDecision?.reasoning ? latestDecision.reasoning : '-'\\n            ]);\\n        });\\n        \\n    } catch (e) {\\n        Log(`❌ Create model status table failed: ${e.message}`);\\n        Log(`Error stack: ${e.stack}`);\\n        statusTable.rows.push([\\n            \\\"❌ Error\\\", \\\"Failed to get data\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", e.message\\n        ]);\\n    }\\n    \\n    return statusTable;\\n}\\n\\n/**\\n * Table 2: Model Performance Comparison\\n */\\nfunction createPerformanceComparisonTable(allModelsStatus, models) {\\n    const perfTable = {\\n        type: \\\"table\\\",\\n        title: \\\"📊 AI Model Performance Comparison (Sorted by PnL)\\\",\\n        cols: [\\\"Rank\\\", \\\"Model\\\", \\\"Realized\\\", \\\"Total Assets\\\", \\\"Max Profit\\\", \\\"Max Loss\\\", \\\"Max DD\\\", \\\"Sharpe\\\", \\\"Profit/Loss\\\", \\\"Trades\\\", \\\"Win%\\\", \\\"Avg Win\\\", \\\"Avg Loss\\\"],\\n        rows: []\\n    };\\n    \\n    try {\\n        const performanceData = allModelsStatus.map((model, index) => {\\n            const modelData = models[model.model];\\n            if (!modelData) {\\n                return null;\\n            }\\n            \\n            const tradeHistory = modelData.tradeHistory || [];\\n            \\n            // Filter closed trades (records with pnl)\\n            const closedTrades = tradeHistory.filter(trade => \\n                trade.pnl !== undefined && trade.pnl !== null\\n            );\\n            \\n            // Calculate max profit\\n            const maxProfit = closedTrades.length > 0\\n                ? Math.max(...closedTrades.map(t => t.pnl || 0))\\n                : 0;\\n            \\n            // Calculate max loss\\n            const maxLoss = closedTrades.length > 0\\n                ? Math.min(...closedTrades.map(t => t.pnl || 0))\\n                : 0;\\n            \\n            // Calculate max drawdown\\n            let maxDrawdown = 0;\\n            let peak = modelData.account.initialBalance || 10000;\\n            let cumulativePnl = 0;\\n            \\n            closedTrades.forEach(trade => {\\n                cumulativePnl += (trade.pnl || 0);\\n                const currentValue = (modelData.account.initialBalance || 10000) + cumulativePnl;\\n                \\n                if (currentValue > peak) {\\n                    peak = currentValue;\\n                }\\n                \\n                const drawdown = peak > 0 ? ((peak - currentValue) / peak) * 100 : 0;\\n                if (drawdown > maxDrawdown) {\\n                    maxDrawdown = drawdown;\\n                }\\n            });\\n            \\n            // Calculate Sharpe ratio\\n            let sharpeRatio = 0;\\n            if (closedTrades.length > 1) {\\n                const initialBalance = modelData.account.initialBalance || 10000;\\n                const returns = closedTrades.map(t => (t.pnl || 0) / initialBalance);\\n                const avgReturn = returns.reduce((a, b) => a + b, 0) / returns.length;\\n                \\n                const variance = returns.reduce((sum, r) => sum + Math.pow(r - avgReturn, 2), 0) / returns.length;\\n                const stdDev = Math.sqrt(variance);\\n                \\n                sharpeRatio = stdDev !== 0 ? (avgReturn / stdDev) : 0;\\n            }\\n            \\n            // Profit/Loss ratio\\n            const winTrades = closedTrades.filter(t => (t.pnl || 0) > 0);\\n            const lossTrades = closedTrades.filter(t => (t.pnl || 0) < 0);\\n            \\n            const avgWin = winTrades.length > 0\\n                ? winTrades.reduce((sum, t) => sum + (t.pnl || 0), 0) / winTrades.length\\n                : 0;\\n            \\n            const avgLoss = lossTrades.length > 0\\n                ? Math.abs(lossTrades.reduce((sum, t) => sum + (t.pnl || 0), 0) / lossTrades.length)\\n                : 0;\\n            \\n            const profitLossRatio = avgLoss !== 0 ? (avgWin / avgLoss) : 0;\\n            \\n            return {\\n                model: model.model,\\n                rank: index + 1,\\n                realizedPnl: modelData.account.realizedPnl || 0,\\n                totalValue: modelData.account.totalValue || 0,\\n                maxProfit: maxProfit,\\n                maxLoss: maxLoss,\\n                maxDrawdown: maxDrawdown,\\n                sharpeRatio: sharpeRatio,\\n                profitLossRatio: profitLossRatio,\\n                totalTrades: closedTrades.length,\\n                winRate: (modelData.account.totalTrades || 0) > 0 \\n                    ? (((modelData.account.winTrades || 0) / modelData.account.totalTrades) * 100)\\n                    : 0,\\n                avgWin: avgWin,\\n                avgLoss: avgLoss\\n            };\\n        }).filter(perf => perf !== null).sort((a, b) => b.realizedPnl - a.realizedPnl);\\n        \\n        performanceData.forEach((perf, index) => {\\n            // Rank display\\n            let rankDisplay = \\\"\\\";\\n            if (index === 0) {\\n                rankDisplay = \\\"🥇\\\";\\n            } else if (index === 1) {\\n                rankDisplay = \\\"🥈\\\";\\n            } else if (index === 2) {\\n                rankDisplay = \\\"🥉\\\";\\n            } else {\\n                rankDisplay = `${index + 1}`;\\n            }\\n            \\n            // Sharpe ratio display\\n            let sharpeDisplay = \\\"\\\";\\n            if (perf.sharpeRatio > 2) {\\n                sharpeDisplay = `🔥 ${safeFormat(perf.sharpeRatio)}`;\\n            } else if (perf.sharpeRatio > 1) {\\n                sharpeDisplay = `✅ ${safeFormat(perf.sharpeRatio)}`;\\n            } else if (perf.sharpeRatio > 0) {\\n                sharpeDisplay = `⚡ ${safeFormat(perf.sharpeRatio)}`;\\n            } else {\\n                sharpeDisplay = `⚠️ ${safeFormat(perf.sharpeRatio)}`;\\n            }\\n            \\n            perfTable.rows.push([\\n                rankDisplay,\\n                `💎 ${perf.model}`,\\n                perf.realizedPnl > 0 \\n                    ? `🟢 ${safeFormat(perf.realizedPnl, 2, \\\"$\\\")}`\\n                    : perf.realizedPnl < 0\\n                    ? `🔴 ${safeFormat(perf.realizedPnl, 2, \\\"$\\\")}`\\n                    : `⚪ $0`,\\n                safeFormat(perf.totalValue, 2, \\\"$\\\"),\\n                perf.maxProfit > 0 ? `🟢 ${safeFormat(perf.maxProfit, 2, \\\"$\\\")}` : '$0',\\n                perf.maxLoss < 0 ? `🔴 ${safeFormat(perf.maxLoss, 2, \\\"$\\\")}` : '$0',\\n                perf.maxDrawdown > 0 ? `⚠️ ${safeFormat(perf.maxDrawdown)}%` : '0%',\\n                sharpeDisplay,\\n                perf.profitLossRatio > 0 ? safeFormat(perf.profitLossRatio) : '0',\\n                perf.totalTrades,\\n                `${safeFormat(perf.winRate, 1)}%`,\\n                perf.avgWin > 0 ? safeFormat(perf.avgWin, 2, \\\"$\\\") : '$0',\\n                perf.avgLoss > 0 ? safeFormat(perf.avgLoss, 2, \\\"$\\\") : '$0'\\n            ]);\\n        });\\n        \\n        // Add summary row\\n        if (performanceData.length > 0) {\\n            const avgPnl = performanceData.reduce((sum, p) => sum + p.realizedPnl, 0) / performanceData.length;\\n            const avgSharpe = performanceData.reduce((sum, p) => sum + p.sharpeRatio, 0) / performanceData.length;\\n            const totalTrades = performanceData.reduce((sum, p) => sum + p.totalTrades, 0);\\n            \\n            perfTable.rows.push([\\n                \\\"📊\\\",\\n                \\\"Average\\\",\\n                avgPnl > 0 ? `🟢 ${safeFormat(avgPnl, 2, \\\"$\\\")}` : avgPnl < 0 ? `🔴 ${safeFormat(avgPnl, 2, \\\"$\\\")}` : `⚪ $0`,\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                safeFormat(avgSharpe),\\n                \\\"-\\\",\\n                totalTrades,\\n                \\\"-\\\",\\n                \\\"-\\\",\\n                \\\"-\\\"\\n            ]);\\n        }\\n        \\n    } catch (e) {\\n        Log(`❌ Create performance comparison table failed: ${e.message}`);\\n        Log(`Error stack: ${e.stack}`);\\n        perfTable.rows.push([\\n            \\\"❌\\\", \\\"Error\\\", \\\"Failed to get data\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", \\\"-\\\", e.message\\n        ]);\\n    }\\n    \\n    return perfTable;\\n}\\n\\n/**\\n * Table 3: Real Trading Status\\n */\\nfunction createRealTradingTable(inputData, models) {\\n    const realTable = {\\n        type: \\\"table\\\",\\n        title: \\\"💼 Real Trading Status\\\",\\n        cols: [\\\"Item\\\", \\\"Value\\\", \\\"Status\\\", \\\"Note\\\"],\\n        rows: []\\n    };\\n    \\n    try {\\n        const activeModel = inputData.activeModel;\\n        const realAccount = exchange.GetAccount();\\n        const realPositions = exchange.GetPosition();\\n        \\n        // Get real position info\\n        let realPositionInfo = {\\n            type: 'None',\\n            size: 0,\\n            entryPrice: 0,\\n            currentPrice: 0,\\n            unrealizedPnl: 0\\n        };\\n        \\n        if (realPositions && realPositions.length > 0) {\\n            const pos = realPositions[0];\\n            const ticker = exchange.GetTicker();\\n            const currentPrice = ticker ? ticker.Last : 0;\\n            \\n            realPositionInfo = {\\n                type: pos.Type === PD_LONG ? 'Long' : 'Short',\\n                size: pos.Amount || 0,\\n                entryPrice: pos.Price || 0,\\n                currentPrice: currentPrice,\\n                unrealizedPnl: pos.Profit || 0\\n            };\\n        }\\n        \\n        // Calculate real account cumulative profit\\n        const initMoney = _G('initmoney') || 10000;\\n        const currentBalance = realAccount ? (realAccount.Balance || 0) : 0;\\n        const currentEquity = realAccount ? (realAccount.Equity || 0) : 0;\\n        const realizedProfit = currentBalance - initMoney;\\n        const totalProfit = currentEquity - initMoney;\\n        const returnRate = initMoney > 0 ? ((totalProfit / initMoney) * 100) : 0;\\n\\n        LogProfit(totalProfit, \\\"&\\\");\\n        \\n        // Active model info\\n        realTable.rows.push([\\n            \\\"🤖 Active Model\\\",\\n            activeModel || \\\"Not Started\\\",\\n            activeModel ? \\\"✅ Running\\\" : \\\"⏸️ Standby\\\",\\n            activeModel && models[activeModel] \\n                ? `PnL: ${safeFormat(models[activeModel].account.realizedPnl, 2, \\\"$\\\")}` \\n                : \\\"Wait for profit > threshold to trigger\\\"\\n        ]);\\n        \\n        // Account info\\n        realTable.rows.push([\\n            \\\"💰 Initial Capital\\\",\\n            safeFormat(initMoney, 2, \\\"$\\\"),\\n            \\\"📊\\\",\\n            \\\"Real account start amount\\\"\\n        ]);\\n        \\n        realTable.rows.push([\\n            \\\"💵 Current Balance\\\",\\n            safeFormat(currentBalance, 2, \\\"$\\\"),\\n            \\\"📊\\\",\\n            \\\"Available funds\\\"\\n        ]);\\n        \\n        realTable.rows.push([\\n            \\\"💎 Account Equity\\\",\\n            safeFormat(currentEquity, 2, \\\"$\\\"),\\n            \\\"📊\\\",\\n            \\\"Balance + Position PnL\\\"\\n        ]);\\n        \\n        // PnL info\\n        let profitDisplay = \\\"\\\";\\n        let profitStatus = \\\"\\\";\\n        if (totalProfit > 0) {\\n            profitDisplay = `🟢 +${safeFormat(totalProfit, 2, \\\"$\\\")}`;\\n            profitStatus = \\\"✅ Profitable\\\";\\n        } else if (totalProfit < 0) {\\n            profitDisplay = `🔴 ${safeFormat(totalProfit, 2, \\\"$\\\")}`;\\n            profitStatus = \\\"⚠️ Loss\\\";\\n        } else {\\n            profitDisplay = `⚪ $0`;\\n            profitStatus = \\\"⚪ Breakeven\\\";\\n        }\\n        \\n        realTable.rows.push([\\n            \\\"📈 Total PnL\\\",\\n            profitDisplay,\\n            profitStatus,\\n            `Return: ${returnRate > 0 ? '+' : ''}${safeFormat(returnRate)}%`\\n        ]);\\n        \\n        // Position info\\n        realTable.rows.push([\\n            \\\"💼 Current Position\\\",\\n            realPositionInfo.type === 'None' ? \\\"📭 Empty\\\" : `${realPositionInfo.type === 'Long' ? '📈' : '📉'} ${realPositionInfo.type}`,\\n            realPositionInfo.type === 'None' ? \\\"⚪ No Position\\\" : \\\"✅ In Position\\\",\\n            realPositionInfo.type === 'None' ? \\\"-\\\" : `Size: ${safeFormat(realPositionInfo.size, 4)}`\\n        ]);\\n        \\n        if (realPositionInfo.type !== 'None') {\\n            realTable.rows.push([\\n                \\\"💰 Entry Price\\\",\\n                safeFormat(realPositionInfo.entryPrice, 4, \\\"$\\\"),\\n                \\\"📊\\\",\\n                `Current: ${safeFormat(realPositionInfo.currentPrice, 4, \\\"$\\\")}`\\n            ]);\\n            \\n            let positionPnlDisplay = \\\"\\\";\\n            let positionPnlStatus = \\\"\\\";\\n            if (realPositionInfo.unrealizedPnl > 0) {\\n                positionPnlDisplay = `🟢 +${safeFormat(realPositionInfo.unrealizedPnl, 2, \\\"$\\\")}`;\\n                positionPnlStatus = \\\"✅ Floating Profit\\\";\\n            } else if (realPositionInfo.unrealizedPnl < 0) {\\n                positionPnlDisplay = `🔴 ${safeFormat(realPositionInfo.unrealizedPnl, 2, \\\"$\\\")}`;\\n                positionPnlStatus = \\\"⚠️ Floating Loss\\\";\\n            } else {\\n                positionPnlDisplay = `⚪ $0`;\\n                positionPnlStatus = \\\"⚪ Breakeven\\\";\\n            }\\n            \\n            realTable.rows.push([\\n                \\\"📊 Position PnL\\\",\\n                positionPnlDisplay,\\n                positionPnlStatus,\\n                \\\"Unrealized PnL\\\"\\n            ]);\\n        }\\n        \\n        // Sync status\\n        realTable.rows.push([\\n            \\\"🔄 Sync Status\\\",\\n            inputData.shouldTrade ? \\\"Pending Sync\\\" : \\\"Synced\\\",\\n            inputData.shouldTrade ? \\\"🔄 Executing\\\" : \\\"✅ Synced\\\",\\n            inputData.tradeAction?.reason || \\\"Paper and real match\\\"\\n        ]);\\n        \\n        // Last trade\\n        if (inputData.tradeAction) {\\n            let actionDisplay = inputData.tradeAction.action;\\n            switch(actionDisplay) {\\n                case 'OPEN_LONG':\\n                    actionDisplay = \\\"🟢 Open Long\\\";\\n                    break;\\n                case 'OPEN_SHORT':\\n                    actionDisplay = \\\"🔴 Open Short\\\";\\n                    break;\\n                case 'CLOSE_LONG':\\n                    actionDisplay = \\\"⏹️ Close Long\\\";\\n                    break;\\n                case 'CLOSE_SHORT':\\n                    actionDisplay = \\\"⏹️ Close Short\\\";\\n                    break;\\n            }\\n            \\n            realTable.rows.push([\\n                \\\"📝 Last Trade\\\",\\n                actionDisplay,\\n                \\\"📊\\\",\\n                inputData.tradeAction.reason || \\\"-\\\"\\n            ]);\\n        }\\n        \\n        // Model comparison\\n        if (activeModel && models[activeModel]) {\\n            const modelPnl = models[activeModel].account.realizedPnl || 0;\\n            const gap = realizedProfit - modelPnl;\\n            \\n            realTable.rows.push([\\n                \\\"📊 Gap vs Model\\\",\\n                gap > 0 ? `🟢 Ahead ${safeFormat(gap, 2, \\\"$\\\")}` : gap < 0 ? `🔴 Behind ${safeFormat(Math.abs(gap), 2, \\\"$\\\")}` : `⚪ Match`,\\n                gap > 0 ? \\\"✅ Leading\\\" : gap < 0 ? \\\"⚠️ Catching Up\\\" : \\\"⚪ Synced\\\",\\n                `Model Paper: ${safeFormat(modelPnl, 2, \\\"$\\\")}`\\n            ]);\\n        }\\n        \\n    } catch (e) {\\n        Log(`❌ Create real trading table failed: ${e.message}`);\\n        Log(`Error stack: ${e.stack}`);\\n        realTable.rows.push([\\n            \\\"❌ Error\\\",\\n            \\\"Failed to get data\\\",\\n            \\\"🚨\\\",\\n            e.message\\n        ]);\\n    }\\n    \\n    return realTable;\\n}\\n\\n/**\\n * Table 4: System Statistics\\n */\\nfunction createSystemStatsTable(allModelsStatus, models, inputData) {\\n    const statsTable = {\\n        type: \\\"table\\\",\\n        title: \\\"📊 System Overall Statistics\\\",\\n        cols: [\\\"Metric\\\", \\\"Value\\\", \\\"Rating\\\", \\\"Note\\\"],\\n        rows: []\\n    };\\n    \\n    try {\\n        // Total models\\n        statsTable.rows.push([\\n            \\\"🤖 Competing Models\\\",\\n            `${allModelsStatus.length} models`,\\n            \\\"📊\\\",\\n            \\\"AI Model Competition\\\"\\n        ]);\\n        \\n        // Best model\\n        if (allModelsStatus.length > 0) {\\n            const bestModel = allModelsStatus[0];\\n            statsTable.rows.push([\\n                \\\"🥇 Best Model\\\",\\n                bestModel.model,\\n                bestModel.realizedPnl > 0 ? \\\"✅ Profitable\\\" : \\\"⚠️ Loss\\\",\\n                `PnL: ${safeFormat(bestModel.realizedPnl, 2, \\\"$\\\")}`\\n            ]);\\n        }\\n        \\n        // Average performance\\n        if (allModelsStatus.length > 0) {\\n            const avgPnl = allModelsStatus.reduce((sum, m) => sum + (m.realizedPnl || 0), 0) / allModelsStatus.length;\\n            statsTable.rows.push([\\n                \\\"📊 Average PnL\\\",\\n                avgPnl > 0 ? `🟢 ${safeFormat(avgPnl, 2, \\\"$\\\")}` : avgPnl < 0 ? `🔴 ${safeFormat(avgPnl, 2, \\\"$\\\")}` : `⚪ $0`,\\n                avgPnl > 0 ? \\\"✅ Positive\\\" : \\\"⚠️ Negative\\\",\\n                \\\"All models average\\\"\\n            ]);\\n        }\\n        \\n        // Profitable models count\\n        const profitableModels = allModelsStatus.filter(m => (m.realizedPnl || 0) > 0).length;\\n        statsTable.rows.push([\\n            \\\"✅ Profitable Models\\\",\\n            `${profitableModels} / ${allModelsStatus.length}`,\\n            profitableModels > allModelsStatus.length / 2 ? \\\"✅ Good\\\" : \\\"⚠️ Low\\\",\\n            `Ratio: ${safePercentage(profitableModels, allModelsStatus.length)}`\\n        ]);\\n        \\n        // Total trades\\n        const totalTrades = allModelsStatus.reduce((sum, m) => {\\n            const modelData = models[m.model];\\n            return sum + (modelData ? (modelData.account.totalTrades || 0) : 0);\\n        }, 0);\\n        \\n        statsTable.rows.push([\\n            \\\"🎲 Total Trades\\\",\\n            totalTrades,\\n            totalTrades > 50 ? \\\"✅ Sufficient\\\" : totalTrades > 10 ? \\\"✅ Moderate\\\" : \\\"⚠️ Low\\\",\\n            `All models combined`\\n        ]);\\n        \\n        // Average win rate\\n        let totalWinRate = 0;\\n        let validModels = 0;\\n        allModelsStatus.forEach(m => {\\n            const modelData = models[m.model];\\n            if (modelData && (modelData.account.totalTrades || 0) > 0) {\\n                totalWinRate += ((modelData.account.winTrades || 0) / modelData.account.totalTrades) * 100;\\n                validModels++;\\n            }\\n        });\\n        const avgWinRate = validModels > 0 ? totalWinRate / validModels : 0;\\n        \\n        statsTable.rows.push([\\n            \\\"🎯 Average Win Rate\\\",\\n            `${safeFormat(avgWinRate, 1)}%`,\\n            avgWinRate > 60 ? \\\"🔥 Excellent\\\" : avgWinRate > 45 ? \\\"✅ Good\\\" : \\\"⚠️ Need Improvement\\\",\\n            \\\"Valid trading models average\\\"\\n        ]);\\n        \\n        // Models with position\\n        const modelsWithPosition = allModelsStatus.filter(m => m.paperPosition !== 'none').length;\\n        statsTable.rows.push([\\n            \\\"💼 Models in Position\\\",\\n            `${modelsWithPosition} / ${allModelsStatus.length}`,\\n            modelsWithPosition > 0 ? \\\"✅ Active\\\" : \\\"📭 Empty\\\",\\n            `Ratio: ${safePercentage(modelsWithPosition, allModelsStatus.length)}`\\n        ]);\\n        \\n        // Real trading status\\n        const isRealTrading = inputData.activeModel ? true : false;\\n        statsTable.rows.push([\\n            \\\"🚀 Real Trading Status\\\",\\n            isRealTrading ? \\\"Running\\\" : \\\"Not Started\\\",\\n            isRealTrading ? \\\"✅ Active\\\" : \\\"⏸️ Standby\\\",\\n            isRealTrading ? `Following: ${inputData.activeModel}` : \\\"Wait for profit>500\\\"\\n        ]);\\n        \\n        // Last update time\\n        const updateTime = new Date().toLocaleString();\\n        statsTable.rows.push([\\n            \\\"🕐 Update Time\\\",\\n            updateTime,\\n            \\\"📊\\\",\\n            \\\"Real-time monitoring\\\"\\n        ]);\\n        \\n    } catch (e) {\\n        Log(`❌ Create stats table failed: ${e.message}`);\\n        Log(`Error stack: ${e.stack}`);\\n        statsTable.rows.push([\\n            \\\"❌ Error\\\",\\n            \\\"Calculation failed\\\",\\n            \\\"🚨\\\",\\n            e.message\\n        ]);\\n    }\\n    \\n    return statsTable;\\n}\\n\\n/**\\n * Main function - Display complete dashboard\\n */\\nfunction main() {\\n    try {\\n        Log('Visualization node execution started');\\n        \\n        // Get input data\\n        const inputData = $input.all()[0].json;\\n        Log('inputData keys:', Object.keys(inputData));\\n        \\n        const allModelsStatus = inputData.allModelsStatus;\\n        if (!allModelsStatus || !Array.isArray(allModelsStatus)) {\\n            throw new Error('allModelsStatus data invalid or not an array');\\n        }\\n        \\n        Log(`Model count: ${allModelsStatus.length}`);\\n        \\n        // Get detailed model data\\n        const models = $node['Result Calculation'].json;\\n        if (!models) {\\n            throw new Error('Unable to get Result Calculation node data');\\n        }\\n        \\n        Log('models keys:', Object.keys(models));\\n        \\n        // Create 4 tables\\n        const table1 = createModelStatusTable(allModelsStatus, models);\\n        const table2 = createPerformanceComparisonTable(allModelsStatus, models);\\n        const table3 = createRealTradingTable(inputData, models);\\n        const table4 = createSystemStatsTable(allModelsStatus, models, inputData);\\n        \\n        // Combined display\\n        const dashboardDisplay = \\n            '`' + JSON.stringify(table1) + '`\\\\n\\\\n' +\\n            '`' + JSON.stringify(table2) + '`\\\\n\\\\n' +\\n            '`' + JSON.stringify(table3) + '`\\\\n\\\\n' +\\n            '`' + JSON.stringify(table4) + '`';\\n        \\n        LogStatus(dashboardDisplay);\\n        \\n        Log('✅ Visualization display success');\\n        \\n        // Return complete data\\n        return [{\\n            json: {\\n                ...inputData,\\n                tables: {\\n                    modelStatus: table1,\\n                    performance: table2,\\n                    realTrading: table3,\\n                    systemStats: table4\\n                },\\n                timestamp: Date.now(),\\n                updateTime: new Date().toLocaleString()\\n            }\\n        }];\\n        \\n    } catch (e) {\\n        Log(`❌ Display dashboard failed: ${e.message}`);\\n        Log(`❌ Error stack: ${e.stack}`);\\n        \\n        // Show simple status on error\\n        const errorTable = {\\n            type: \\\"table\\\",\\n            title: \\\"❌ System Error\\\",\\n            cols: [\\\"Error Type\\\", \\\"Error Message\\\", \\\"Time\\\"],\\n            rows: [[\\n                \\\"Visualization Error\\\",\\n                e.message,\\n                new Date().toLocaleString()\\n            ]]\\n        };\\n        \\n        LogStatus('`' + JSON.stringify(errorTable) + '`');\\n        \\n        return [{\\n            json: {\\n                error: e.message,\\n                stack: e.stack,\\n                timestamp: Date.now()\\n            }\\n        }];\\n    }\\n}\\n\\n// Execute main function\\nreturn main();\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[1136,912],\"id\":\"939c1c0f-3c4d-43ab-be31-c2f1ece3b06c\",\"name\":\"Visualization\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"const symbol = $vars.coin + \\\"_USDT.swap\\\"\\nconst timeframes = {\\n    day: PERIOD_D1,\\n    hour: PERIOD_H1,\\n    min5: PERIOD_M5\\n}\\n\\nfunction getIndicatorsForPeriod(symbol, period, periodName) {\\n    const records = exchange.GetRecords(symbol, period)\\n    \\n    if (!records || records.length <= 10) {\\n        Log(`Warning: ${periodName} period insufficient data, only ${records ? records.length : 0} records`)\\n        return null\\n    }\\n    \\n    const macd = talib.MACD(records)\\n    const rsi = talib.RSI(records, 14)\\n    const atr = talib.ATR(records, 14)\\n    const obv = talib.OBV(records)\\n    \\n    function getLast10Values(arr) {\\n        if (!arr || arr.length === 0) return []\\n        return arr.slice(-10)\\n    }\\n    \\n    return {\\n        period: periodName,\\n        recordsCount: records.length,\\n        lastPrice: records[records.length - 1].Close,\\n        MACD: {\\n            macd: getLast10Values(macd[0]),\\n            signal: getLast10Values(macd[1]), \\n            histogram: getLast10Values(macd[2])\\n        },\\n        RSI: getLast10Values(rsi),\\n        ATR: getLast10Values(atr),\\n        OBV: getLast10Values(obv)\\n    }\\n}\\n\\nconst models = _G('models')\\nconst modelPnlData = Object.keys(models).map(modelName => ({\\n    name: modelName,\\n    realizedPnl: models[modelName].account.realizedPnl,\\n    totalValue: models[modelName].account.totalValue\\n}))\\n\\nconst sortedModels = modelPnlData.sort((a, b) => b.realizedPnl - a.realizedPnl)\\n\\nconst rankedModels = []\\nlet currentRank = 1\\nlet previousPnl = null\\n\\nsortedModels.forEach((model, index) => {\\n    if (previousPnl !== null && model.realizedPnl < previousPnl) {\\n        currentRank = index + 1\\n    }\\n    \\n    rankedModels.push({\\n        ...model,\\n        rank: currentRank\\n    })\\n    \\n    previousPnl = model.realizedPnl\\n})\\n\\nconst currentModelName = Object.keys(models)[0] // First model\\nconst currentModelRank = rankedModels.find(model => model.name === currentModelName)\\n\\nconst rankingText = rankedModels.map(model => \\n    `${model.rank}. ${model.name}: ${model.realizedPnl} USDT${model.name === currentModelName ? ' ← Your Position' : ''}`\\n).join('\\\\n')\\n\\nlet gapInfo = ''\\nif (currentModelRank.rank > 1) {\\n    const firstPlace = rankedModels[0]\\n    const gap = (firstPlace.realizedPnl - currentModelRank.realizedPnl).toFixed(2)\\n    gapInfo = `### Gap from 1st Place\\\\n1st Place PnL: ${firstPlace.realizedPnl} USDT\\\\nYou need to catch up: ${gap} USDT`\\n} else {\\n    gapInfo = '🏆 Congratulations! You are leading! Keep the advantage!'\\n}\\n\\nconst result = {\\n    symbol: symbol,\\n    timestamp: Date.now(),\\n    timeframes: {\\n        day: getIndicatorsForPeriod(symbol, timeframes.day, 'Daily'),\\n        hour: getIndicatorsForPeriod(symbol, timeframes.hour, 'Hourly'),\\n        min5: getIndicatorsForPeriod(symbol, timeframes.min5, '5-minute')\\n    },\\n    // ⚠️ Modified: Use model's own virtual position instead of real position\\n    position: models[currentModelName].positions || [],\\n    ranking: {\\n        currentModel: currentModelName,\\n        currentRank: currentModelRank.rank,\\n        currentPnl: currentModelRank.realizedPnl,\\n        currentTotalValue: currentModelRank.totalValue,\\n        totalTrades: models[currentModelName].account.totalTrades,\\n        winTrades: models[currentModelName].account.winTrades,\\n        winRate: models[currentModelName].account.totalTrades > 0 ? \\n            (models[currentModelName].account.winTrades / models[currentModelName].account.totalTrades * 100).toFixed(2) : '0',\\n        rankingText: rankingText,\\n        gapInfo: gapInfo,\\n        totalModels: Object.keys(models).length,\\n        allRankings: rankedModels\\n    }\\n}\\n\\nreturn result\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[-384,16],\"id\":\"910841e7-88cc-4ea0-9b64-c5ff2019967f\",\"name\":\"DS Processing\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"const symbol = $vars.coin + \\\"_USDT.swap\\\"\\nconst timeframes = {\\n    day: PERIOD_D1,\\n    hour: PERIOD_H1,\\n    min5: PERIOD_M5\\n}\\n\\nfunction getIndicatorsForPeriod(symbol, period, periodName) {\\n    const records = exchange.GetRecords(symbol, period)\\n    \\n    if (!records || records.length <= 10) {\\n        Log(`Warning: ${periodName} period insufficient data, only ${records ? records.length : 0} records`)\\n        return null\\n    }\\n    \\n    const macd = talib.MACD(records)\\n    const rsi = talib.RSI(records, 14)\\n    const atr = talib.ATR(records, 14)\\n    const obv = talib.OBV(records)\\n    \\n    function getLast10Values(arr) {\\n        if (!arr || arr.length === 0) return []\\n        return arr.slice(-10)\\n    }\\n    \\n    return {\\n        period: periodName,\\n        recordsCount: records.length,\\n        lastPrice: records[records.length - 1].Close,\\n        MACD: {\\n            macd: getLast10Values(macd[0]),\\n            signal: getLast10Values(macd[1]), \\n            histogram: getLast10Values(macd[2])\\n        },\\n        RSI: getLast10Values(rsi),\\n        ATR: getLast10Values(atr),\\n        OBV: getLast10Values(obv)\\n    }\\n}\\n\\nconst models = _G('models')\\nconst modelPnlData = Object.keys(models).map(modelName => ({\\n    name: modelName,\\n    realizedPnl: models[modelName].account.realizedPnl,\\n    totalValue: models[modelName].account.totalValue\\n}))\\n\\nconst sortedModels = modelPnlData.sort((a, b) => b.realizedPnl - a.realizedPnl)\\n\\nconst rankedModels = []\\nlet currentRank = 1\\nlet previousPnl = null\\n\\nsortedModels.forEach((model, index) => {\\n    if (previousPnl !== null && model.realizedPnl < previousPnl) {\\n        currentRank = index + 1\\n    }\\n    \\n    rankedModels.push({\\n        ...model,\\n        rank: currentRank\\n    })\\n    \\n    previousPnl = model.realizedPnl\\n})\\n\\nconst currentModelName = Object.keys(models)[1] // Second model\\nconst currentModelRank = rankedModels.find(model => model.name === currentModelName)\\n\\nconst rankingText = rankedModels.map(model => \\n    `${model.rank}. ${model.name}: ${model.realizedPnl} USDT${model.name === currentModelName ? ' ← Your Position' : ''}`\\n).join('\\\\n')\\n\\nlet gapInfo = ''\\nif (currentModelRank.rank > 1) {\\n    const firstPlace = rankedModels[0]\\n    const gap = (firstPlace.realizedPnl - currentModelRank.realizedPnl).toFixed(2)\\n    gapInfo = `### Gap from 1st Place\\\\n1st Place PnL: ${firstPlace.realizedPnl} USDT\\\\nYou need to catch up: ${gap} USDT`\\n} else {\\n    gapInfo = '🏆 Congratulations! You are leading! Keep the advantage!'\\n}\\n\\nconst result = {\\n    symbol: symbol,\\n    timestamp: Date.now(),\\n    timeframes: {\\n        day: getIndicatorsForPeriod(symbol, timeframes.day, 'Daily'),\\n        hour: getIndicatorsForPeriod(symbol, timeframes.hour, 'Hourly'),\\n        min5: getIndicatorsForPeriod(symbol, timeframes.min5, '5-minute')\\n    },\\n    // ⚠️ Modified: Use model's own virtual position instead of real position\\n    position: models[currentModelName].positions || [],\\n    ranking: {\\n        currentModel: currentModelName,\\n        currentRank: currentModelRank.rank,\\n        currentPnl: currentModelRank.realizedPnl,\\n        currentTotalValue: currentModelRank.totalValue,\\n        totalTrades: models[currentModelName].account.totalTrades,\\n        winTrades: models[currentModelName].account.winTrades,\\n        winRate: models[currentModelName].account.totalTrades > 0 ? \\n            (models[currentModelName].account.winTrades / models[currentModelName].account.totalTrades * 100).toFixed(2) : '0',\\n        rankingText: rankingText,\\n        gapInfo: gapInfo,\\n        totalModels: Object.keys(models).length,\\n        allRankings: rankedModels\\n    }\\n}\\n\\nreturn result\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[-384,416],\"id\":\"4854a515-d721-4d32-b7f9-fd0b3706c36a\",\"name\":\"Claude Processing\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"const symbol = $vars.coin + \\\"_USDT.swap\\\"\\nconst timeframes = {\\n    day: PERIOD_D1,\\n    hour: PERIOD_H1,\\n    min5: PERIOD_M5\\n}\\n\\nfunction getIndicatorsForPeriod(symbol, period, periodName) {\\n    const records = exchange.GetRecords(symbol, period)\\n    \\n    if (!records || records.length <= 10) {\\n        Log(`Warning: ${periodName} period insufficient data, only ${records ? records.length : 0} records`)\\n        return null\\n    }\\n    \\n    const macd = talib.MACD(records)\\n    const rsi = talib.RSI(records, 14)\\n    const atr = talib.ATR(records, 14)\\n    const obv = talib.OBV(records)\\n    \\n    function getLast10Values(arr) {\\n        if (!arr || arr.length === 0) return []\\n        return arr.slice(-10)\\n    }\\n    \\n    return {\\n        period: periodName,\\n        recordsCount: records.length,\\n        lastPrice: records[records.length - 1].Close,\\n        MACD: {\\n            macd: getLast10Values(macd[0]),\\n            signal: getLast10Values(macd[1]), \\n            histogram: getLast10Values(macd[2])\\n        },\\n        RSI: getLast10Values(rsi),\\n        ATR: getLast10Values(atr),\\n        OBV: getLast10Values(obv)\\n    }\\n}\\n\\nconst models = _G('models')\\nconst modelPnlData = Object.keys(models).map(modelName => ({\\n    name: modelName,\\n    realizedPnl: models[modelName].account.realizedPnl,\\n    totalValue: models[modelName].account.totalValue\\n}))\\n\\nconst sortedModels = modelPnlData.sort((a, b) => b.realizedPnl - a.realizedPnl)\\n\\nconst rankedModels = []\\nlet currentRank = 1\\nlet previousPnl = null\\n\\nsortedModels.forEach((model, index) => {\\n    if (previousPnl !== null && model.realizedPnl < previousPnl) {\\n        currentRank = index + 1\\n    }\\n    \\n    rankedModels.push({\\n        ...model,\\n        rank: currentRank\\n    })\\n    \\n    previousPnl = model.realizedPnl\\n})\\n\\nconst currentModelName = Object.keys(models)[2] // Third model\\nconst currentModelRank = rankedModels.find(model => model.name === currentModelName)\\n\\nconst rankingText = rankedModels.map(model => \\n    `${model.rank}. ${model.name}: ${model.realizedPnl} USDT${model.name === currentModelName ? ' ← Your Position' : ''}`\\n).join('\\\\n')\\n\\nlet gapInfo = ''\\nif (currentModelRank.rank > 1) {\\n    const firstPlace = rankedModels[0]\\n    const gap = (firstPlace.realizedPnl - currentModelRank.realizedPnl).toFixed(2)\\n    gapInfo = `### Gap from 1st Place\\\\n1st Place PnL: ${firstPlace.realizedPnl} USDT\\\\nYou need to catch up: ${gap} USDT`\\n} else {\\n    gapInfo = '🏆 Congratulations! You are leading! Keep the advantage!'\\n}\\n\\nconst result = {\\n    symbol: symbol,\\n    timestamp: Date.now(),\\n    timeframes: {\\n        day: getIndicatorsForPeriod(symbol, timeframes.day, 'Daily'),\\n        hour: getIndicatorsForPeriod(symbol, timeframes.hour, 'Hourly'),\\n        min5: getIndicatorsForPeriod(symbol, timeframes.min5, '5-minute')\\n    },\\n    // ⚠️ Modified: Use model's own virtual position instead of real position\\n    position: models[currentModelName].positions || [],\\n    ranking: {\\n        currentModel: currentModelName,\\n        currentRank: currentModelRank.rank,\\n        currentPnl: currentModelRank.realizedPnl,\\n        currentTotalValue: currentModelRank.totalValue,\\n        totalTrades: models[currentModelName].account.totalTrades,\\n        winTrades: models[currentModelName].account.winTrades,\\n        winRate: models[currentModelName].account.totalTrades > 0 ? \\n            (models[currentModelName].account.winTrades / models[currentModelName].account.totalTrades * 100).toFixed(2) : '0',\\n        rankingText: rankingText,\\n        gapInfo: gapInfo,\\n        totalModels: Object.keys(models).length,\\n        allRankings: rankedModels\\n    }\\n}\\n\\nreturn result\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[-384,816],\"id\":\"56aa5a7b-479c-47df-b3c7-d47ccdedae29\",\"name\":\"QWEN Processing\"},{\"parameters\":{\"mode\":\"runOnceForAllItems\",\"language\":\"javaScript\",\"jsCode\":\"const symbol = $vars.coin + \\\"_USDT.swap\\\"\\nconst timeframes = {\\n    day: PERIOD_D1,\\n    hour: PERIOD_H1,\\n    min5: PERIOD_M5\\n}\\n\\nfunction getIndicatorsForPeriod(symbol, period, periodName) {\\n    const records = exchange.GetRecords(symbol, period)\\n    \\n    if (!records || records.length <= 10) {\\n        Log(`Warning: ${periodName} period insufficient data, only ${records ? records.length : 0} records`)\\n        return null\\n    }\\n    \\n    const macd = talib.MACD(records)\\n    const rsi = talib.RSI(records, 14)\\n    const atr = talib.ATR(records, 14)\\n    const obv = talib.OBV(records)\\n    \\n    function getLast10Values(arr) {\\n        if (!arr || arr.length === 0) return []\\n        return arr.slice(-10)\\n    }\\n    \\n    return {\\n        period: periodName,\\n        recordsCount: records.length,\\n        lastPrice: records[records.length - 1].Close,\\n        MACD: {\\n            macd: getLast10Values(macd[0]),\\n            signal: getLast10Values(macd[1]), \\n            histogram: getLast10Values(macd[2])\\n        },\\n        RSI: getLast10Values(rsi),\\n        ATR: getLast10Values(atr),\\n        OBV: getLast10Values(obv)\\n    }\\n}\\n\\nconst models = _G('models')\\nconst modelPnlData = Object.keys(models).map(modelName => ({\\n    name: modelName,\\n    realizedPnl: models[modelName].account.realizedPnl,\\n    totalValue: models[modelName].account.totalValue\\n}))\\n\\nconst sortedModels = modelPnlData.sort((a, b) => b.realizedPnl - a.realizedPnl)\\n\\nconst rankedModels = []\\nlet currentRank = 1\\nlet previousPnl = null\\n\\nsortedModels.forEach((model, index) => {\\n    if (previousPnl !== null && model.realizedPnl < previousPnl) {\\n        currentRank = index + 1\\n    }\\n    \\n    rankedModels.push({\\n        ...model,\\n        rank: currentRank\\n    })\\n    \\n    previousPnl = model.realizedPnl\\n})\\n\\nconst currentModelName = Object.keys(models)[3] // Fourth model\\nconst currentModelRank = rankedModels.find(model => model.name === currentModelName)\\n\\nconst rankingText = rankedModels.map(model => \\n    `${model.rank}. ${model.name}: ${model.realizedPnl} USDT${model.name === currentModelName ? ' ← Your Position' : ''}`\\n).join('\\\\n')\\n\\nlet gapInfo = ''\\nif (currentModelRank.rank > 1) {\\n    const firstPlace = rankedModels[0]\\n    const gap = (firstPlace.realizedPnl - currentModelRank.realizedPnl).toFixed(2)\\n    gapInfo = `### Gap from 1st Place\\\\n1st Place PnL: ${firstPlace.realizedPnl} USDT\\\\nYou need to catch up: ${gap} USDT`\\n} else {\\n    gapInfo = '🏆 Congratulations! You are leading! Keep the advantage!'\\n}\\n\\nconst result = {\\n    symbol: symbol,\\n    timestamp: Date.now(),\\n    timeframes: {\\n        day: getIndicatorsForPeriod(symbol, timeframes.day, 'Daily'),\\n        hour: getIndicatorsForPeriod(symbol, timeframes.hour, 'Hourly'),\\n        min5: getIndicatorsForPeriod(symbol, timeframes.min5, '5-minute')\\n    },\\n    // ⚠️ Modified: Use model's own virtual position instead of real position\\n    position: models[currentModelName].positions || [],\\n    ranking: {\\n        currentModel: currentModelName,\\n        currentRank: currentModelRank.rank,\\n        currentPnl: currentModelRank.realizedPnl,\\n        currentTotalValue: currentModelRank.totalValue,\\n        totalTrades: models[currentModelName].account.totalTrades,\\n        winTrades: models[currentModelName].account.winTrades,\\n        winRate: models[currentModelName].account.totalTrades > 0 ? \\n            (models[currentModelName].account.winTrades / models[currentModelName].account.totalTrades * 100).toFixed(2) : '0',\\n        rankingText: rankingText,\\n        gapInfo: gapInfo,\\n        totalModels: Object.keys(models).length,\\n        allRankings: rankedModels\\n    }\\n}\\n\\nreturn result\",\"notice\":\"\"},\"type\":\"n8n-nodes-base.code\",\"typeVersion\":2,\"position\":[-384,1216],\"id\":\"cd92d6e1-97bf-4e48-9c0f-73d2f7ea0c03\",\"name\":\"Grok Processing\"}],\"pinData\":{},\"connections\":{\"Schedule Trigger\":{\"main\":[[{\"node\":\"Strategy Init\",\"type\":\"main\",\"index\":0}]]},\"Claude4.5\":{\"ai_languageModel\":[[{\"node\":\"Claude\",\"type\":\"ai_languageModel\",\"index\":0}]]},\"DS3.1\":{\"ai_languageModel\":[[{\"node\":\"DeepSeek\",\"type\":\"ai_languageModel\",\"index\":0}]]},\"DeepSeek\":{\"main\":[[{\"node\":\"Merge\",\"type\":\"main\",\"index\":0}]]},\"Claude\":{\"main\":[[{\"node\":\"Merge\",\"type\":\"main\",\"index\":1}]]},\"QWEN\":{\"main\":[[{\"node\":\"Merge\",\"type\":\"main\",\"index\":2}]]},\"OpenAI Model\":{\"ai_languageModel\":[[{\"node\":\"QWEN\",\"type\":\"ai_languageModel\",\"index\":0}]]},\"Grok\":{\"main\":[[{\"node\":\"Merge\",\"type\":\"main\",\"index\":3}]]},\"Grok4\":{\"ai_languageModel\":[[{\"node\":\"Grok\",\"type\":\"ai_languageModel\",\"index\":0}]]},\"Merge\":{\"main\":[[{\"node\":\"Result Calculation\",\"type\":\"main\",\"index\":0}]]},\"Convert to File\":{\"main\":[[{\"node\":\"Write to File\",\"type\":\"main\",\"index\":0}]]},\"Result Calculation\":{\"main\":[[{\"node\":\"Trade Log Save\",\"type\":\"main\",\"index\":0}]]},\"Trade Log Save\":{\"main\":[[{\"node\":\"Convert to File\",\"type\":\"main\",\"index\":0},{\"node\":\"Best Trade\",\"type\":\"main\",\"index\":0}]]},\"Best Trade\":{\"main\":[[{\"node\":\"Visualization\",\"type\":\"main\",\"index\":0}]]},\"Strategy Init\":{\"main\":[[{\"node\":\"DS Processing\",\"type\":\"main\",\"index\":0},{\"node\":\"Claude Processing\",\"type\":\"main\",\"index\":0},{\"node\":\"QWEN Processing\",\"type\":\"main\",\"index\":0},{\"node\":\"Grok Processing\",\"type\":\"main\",\"index\":0}]]},\"DS Processing\":{\"main\":[[{\"node\":\"DeepSeek\",\"type\":\"main\",\"index\":0}]]},\"Claude Processing\":{\"main\":[[{\"node\":\"Claude\",\"type\":\"main\",\"index\":0}]]},\"QWEN Processing\":{\"main\":[[{\"node\":\"QWEN\",\"type\":\"main\",\"index\":0}]]},\"Grok Processing\":{\"main\":[[{\"node\":\"Grok\",\"type\":\"main\",\"index\":0}]]}},\"active\":false,\"settings\":{\"timezone\":\"Asia/Shanghai\",\"executionOrder\":\"v1\"},\"tags\":[],\"meta\":{\"templateCredsSetupCompleted\":true},\"credentials\":{},\"id\":\"6c8dfda8-4657-42fa-b4dc-8f723e88aaa7\",\"plugins\":{},\"mcpClients\":{}},\"startNodes\":[],\"triggerToStartFrom\":{\"name\":\"Schedule Trigger\"}}"}