{ "name": "Trading Bot v4 - Execute Trade", "nodes": [ { "parameters": { "httpMethod": "POST", "path": "tradingview-webhook", "options": { "rawBody": true } }, "name": "Webhook - TradingView Alert", "type": "n8n-nodes-base.webhook", "typeVersion": 1, "position": [ 250, 300 ], "webhookId": "your-unique-webhook-id", "id": "webhook-node" }, { "parameters": { "conditions": { "string": [ { "value1": "={{$json.body.secret}}", "operation": "equals", "value2": "={{$env.TRADINGVIEW_WEBHOOK_SECRET}}" } ] } }, "name": "Validate Secret", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [ 450, 300 ], "id": "validate-secret-node" }, { "parameters": { "functionCode": "// Parse TradingView alert data\nconst body = $input.item.json.body;\n\n// Extract signal information\nconst signal = {\n symbol: body.symbol || body.ticker || 'SOLUSDT',\n action: body.action || body.signal_type || 'buy',\n timeframe: body.timeframe || body.interval || '5',\n price: body.price || body.close,\n timestamp: body.timestamp || body.timenow || new Date().toISOString(),\n strength: body.strength || 'strong',\n strategy: body.strategy || '5min_scalp_v4'\n};\n\n// Normalize action to 'long' or 'short'\nlet direction = 'long';\nif (signal.action) {\n const actionLower = signal.action.toLowerCase();\n if (actionLower.includes('sell') || actionLower.includes('short')) {\n direction = 'short';\n }\n}\n\n// Build API payload for v4 execute endpoint\nconst payload = {\n symbol: signal.symbol,\n direction: direction,\n timeframe: signal.timeframe,\n signalStrength: signal.strength,\n signalPrice: parseFloat(signal.price)\n};\n\n// Pass through original data + processed payload\nreturn {\n json: {\n original: body,\n signal: signal,\n apiPayload: payload,\n timestamp: new Date().toISOString()\n }\n};" }, "name": "Parse TradingView Signal", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [ 650, 200 ], "id": "parse-signal-node" }, { "parameters": { "url": "={{$env.TRADING_BOT_API_URL}}/api/trading/check-risk", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "Bearer {{$env.API_SECRET_KEY}}" }, { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ { "name": "symbol", "value": "={{$json.apiPayload.symbol}}" }, { "name": "direction", "value": "={{$json.apiPayload.direction}}" } ] }, "options": {} }, "name": "Check Risk Limits", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.1, "position": [ 850, 200 ], "id": "check-risk-node" }, { "parameters": { "conditions": { "boolean": [ { "value1": "={{$json.allowed}}", "value2": true } ] } }, "name": "Risk Check Passed?", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [ 1050, 200 ], "id": "risk-check-if-node" }, { "parameters": { "url": "={{$env.TRADING_BOT_API_URL}}/api/trading/execute", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "Bearer {{$env.API_SECRET_KEY}}" }, { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "contentType": "json", "body": "={{JSON.stringify($('Parse TradingView Signal').item.json.apiPayload)}}", "options": { "timeout": 30000 } }, "name": "Execute Trade on Drift", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.1, "position": [ 1250, 100 ], "id": "execute-trade-node" }, { "parameters": { "conditions": { "boolean": [ { "value1": "={{$json.success}}", "value2": true } ] } }, "name": "Trade Executed?", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [ 1450, 100 ], "id": "trade-executed-if-node" }, { "parameters": { "functionCode": "// Format success message for Telegram\nconst trade = $json.trade || {};\nconst signal = $('Parse TradingView Signal').item.json.signal;\n\nconst direction = trade.direction?.toUpperCase() || signal.action?.toUpperCase();\nconst emoji = direction === 'LONG' ? '🟢' : '🔴';\n\nconst message = `${emoji} **TRADE EXECUTED**\\n\\n` +\n `📊 **Symbol:** ${trade.symbol || signal.symbol}\\n` +\n `📈 **Direction:** ${direction}\\n` +\n `💰 **Entry Price:** $${trade.entryPrice?.toFixed(4) || signal.price}\\n` +\n `💵 **Position Size:** $${trade.positionSize?.toFixed(2) || 'N/A'}\\n` +\n `⚡ **Leverage:** ${trade.leverage || 10}x\\n` +\n `\\n` +\n `🎯 **Targets:**\\n` +\n ` Stop Loss: $${trade.stopLoss?.toFixed(4) || 'N/A'} (${trade.stopLossPercent || -1.5}%)\\n` +\n ` TP1: $${trade.takeProfit1?.toFixed(4) || 'N/A'} (+${trade.tp1Percent || 0.7}%)\\n` +\n ` TP2: $${trade.takeProfit2?.toFixed(4) || 'N/A'} (+${trade.tp2Percent || 1.5}%)\\n` +\n `\\n` +\n `📊 **Slippage:** ${trade.entrySlippage?.toFixed(3) || '0'}%\\n` +\n `⏰ **Time:** ${new Date(trade.timestamp || Date.now()).toLocaleString()}\\n` +\n `\\n` +\n `✅ Position is now being monitored automatically.\\n` +\n `Auto-exit at TP/SL levels.`;\n\nreturn {\n json: {\n message: message,\n trade: trade,\n signal: signal\n }\n};" }, "name": "Format Success Message", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [ 1650, 50 ], "id": "format-success-node" }, { "parameters": { "functionCode": "// Format error message for Telegram\nconst error = $json.error || $json.message || 'Unknown error';\nconst signal = $('Parse TradingView Signal').item.json.signal;\n\nconst message = `❌ **TRADE FAILED**\\n\\n` +\n `📊 **Symbol:** ${signal.symbol}\\n` +\n `📈 **Direction:** ${signal.action?.toUpperCase()}\\n` +\n `⏰ **Time:** ${new Date().toLocaleString()}\\n` +\n `\\n` +\n `🚫 **Error:** ${error}\\n` +\n `\\n` +\n `Please check logs and try again.`;\n\nreturn {\n json: {\n message: message,\n error: error,\n signal: signal\n }\n};" }, "name": "Format Error Message", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [ 1650, 200 ], "id": "format-error-node" }, { "parameters": { "functionCode": "// Format risk blocked message\nconst reason = $json.reason || 'Risk limit exceeded';\nconst signal = $('Parse TradingView Signal').item.json.signal;\n\nconst message = `⚠️ **TRADE BLOCKED**\\n\\n` +\n `📊 **Symbol:** ${signal.symbol}\\n` +\n `📈 **Direction:** ${signal.action?.toUpperCase()}\\n` +\n `⏰ **Time:** ${new Date().toLocaleString()}\\n` +\n `\\n` +\n `🛑 **Reason:** ${reason}\\n` +\n `\\n` +\n `Trade was not executed due to risk limits.`;\n\nreturn {\n json: {\n message: message,\n reason: reason,\n signal: signal\n }\n};" }, "name": "Format Risk Blocked Message", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [ 1250, 300 ], "id": "format-risk-blocked-node" }, { "parameters": { "chatId": "={{$env.TELEGRAM_CHAT_ID}}", "text": "={{$json.message}}", "additionalFields": { "parse_mode": "Markdown" } }, "name": "Telegram - Send Notification", "type": "n8n-nodes-base.telegram", "typeVersion": 1, "position": [ 1850, 150 ], "credentials": { "telegramApi": { "id": "1", "name": "Telegram Bot" } }, "id": "telegram-node" }, { "parameters": { "functionCode": "// Invalid webhook secret\nconst message = `🚨 **UNAUTHORIZED WEBHOOK**\\n\\n` +\n `⚠️ Someone tried to trigger a trade with invalid credentials.\\n` +\n `\\n` +\n `⏰ **Time:** ${new Date().toLocaleString()}\\n` +\n `\\n` +\n `Please check your TradingView webhook configuration.`;\n\nreturn {\n json: {\n message: message\n }\n};" }, "name": "Format Invalid Secret", "type": "n8n-nodes-base.code", "typeVersion": 1, "position": [ 650, 400 ], "id": "format-invalid-secret-node" } ], "connections": { "Webhook - TradingView Alert": { "main": [ [ { "node": "Validate Secret", "type": "main", "index": 0 } ] ] }, "Validate Secret": { "main": [ [ { "node": "Parse TradingView Signal", "type": "main", "index": 0 } ], [ { "node": "Format Invalid Secret", "type": "main", "index": 0 } ] ] }, "Parse TradingView Signal": { "main": [ [ { "node": "Check Risk Limits", "type": "main", "index": 0 } ] ] }, "Check Risk Limits": { "main": [ [ { "node": "Risk Check Passed?", "type": "main", "index": 0 } ] ] }, "Risk Check Passed?": { "main": [ [ { "node": "Execute Trade on Drift", "type": "main", "index": 0 } ], [ { "node": "Format Risk Blocked Message", "type": "main", "index": 0 } ] ] }, "Execute Trade on Drift": { "main": [ [ { "node": "Trade Executed?", "type": "main", "index": 0 } ] ] }, "Trade Executed?": { "main": [ [ { "node": "Format Success Message", "type": "main", "index": 0 } ], [ { "node": "Format Error Message", "type": "main", "index": 0 } ] ] }, "Format Success Message": { "main": [ [ { "node": "Telegram - Send Notification", "type": "main", "index": 0 } ] ] }, "Format Error Message": { "main": [ [ { "node": "Telegram - Send Notification", "type": "main", "index": 0 } ] ] }, "Format Risk Blocked Message": { "main": [ [ { "node": "Telegram - Send Notification", "type": "main", "index": 0 } ] ] }, "Format Invalid Secret": { "main": [ [ { "node": "Telegram - Send Notification", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1" } }