- Add Pyth Network price monitoring (WebSocket + polling fallback) - Add Position Manager with automatic exit logic (TP1/TP2/SL) - Implement dynamic stop-loss adjustment (breakeven + profit lock) - Add real-time P&L tracking and multi-position support - Create comprehensive test suite (3 test scripts) - Add 5 detailed documentation files (2500+ lines) - Update configuration to $50 position size for safe testing - All Phase 2 features complete and tested Core Components: - v4/lib/pyth/price-monitor.ts - Real-time price monitoring - v4/lib/trading/position-manager.ts - Autonomous position management - v4/app/api/trading/positions/route.ts - Query positions endpoint - v4/test-*.ts - Comprehensive testing suite Documentation: - PHASE_2_COMPLETE_REPORT.md - Implementation summary - v4/PHASE_2_SUMMARY.md - Detailed feature overview - v4/TESTING.md - Testing guide - v4/QUICKREF_PHASE2.md - Quick reference - install-phase2.sh - Automated installation script
367 lines
12 KiB
JSON
367 lines
12 KiB
JSON
{
|
||
"name": "Trading Bot v4 - TradingView to Drift",
|
||
"nodes": [
|
||
{
|
||
"parameters": {
|
||
"path": "tradingview-signal",
|
||
"responseMode": "responseNode",
|
||
"options": {}
|
||
},
|
||
"id": "webhook-trigger",
|
||
"name": "TradingView Webhook",
|
||
"type": "n8n-nodes-base.webhook",
|
||
"typeVersion": 1,
|
||
"position": [240, 300],
|
||
"webhookId": "tradingview-signal"
|
||
},
|
||
{
|
||
"parameters": {
|
||
"functionCode": "// Verify webhook secret\nconst secret = $input.item.json.query?.secret;\nconst expectedSecret = $env.TRADINGVIEW_WEBHOOK_SECRET || 'YOUR_SECRET_KEY';\n\nif (!secret || secret !== expectedSecret) {\n throw new Error('❌ Invalid webhook secret');\n}\n\nconsole.log('✅ Webhook secret verified');\n\nreturn {\n json: {\n verified: true,\n rawPayload: $input.item.json.body,\n timestamp: new Date().toISOString()\n }\n};"
|
||
},
|
||
"id": "verify-secret",
|
||
"name": "Verify Secret",
|
||
"type": "n8n-nodes-base.code",
|
||
"typeVersion": 2,
|
||
"position": [460, 300]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"functionCode": "// Extract and normalize signal data\nconst body = $input.item.json.rawPayload || $input.item.json;\n\nconst signal = {\n action: body.action || 'buy',\n symbol: body.symbol || 'SOLUSDT',\n timeframe: body.timeframe || body.interval || '5',\n price: parseFloat(body.price || body.close) || 0,\n timestamp: body.timestamp || body.timenow || new Date().toISOString(),\n signalType: body.signal_type || (body.action === 'buy' ? 'buy' : 'sell'),\n strength: body.strength || 'moderate',\n strategy: body.strategy || '5min_scalp_v4'\n};\n\n// Normalize symbol to Drift market format\nif (signal.symbol.includes('SOL')) {\n signal.driftSymbol = 'SOL-PERP';\n} else if (signal.symbol.includes('BTC')) {\n signal.driftSymbol = 'BTC-PERP';\n} else if (signal.symbol.includes('ETH')) {\n signal.driftSymbol = 'ETH-PERP';\n} else {\n // Default to SOL if unknown\n signal.driftSymbol = 'SOL-PERP';\n}\n\n// Determine trading direction\nsignal.direction = (signal.action === 'buy' || signal.signalType === 'buy') ? 'long' : 'short';\n\n// Add metadata\nsignal.receivedAt = new Date().toISOString();\nsignal.source = 'tradingview';\n\nconsole.log('📊 Extracted signal:', JSON.stringify(signal, null, 2));\n\nreturn { json: signal };"
|
||
},
|
||
"id": "extract-signal",
|
||
"name": "Extract Signal Data",
|
||
"type": "n8n-nodes-base.code",
|
||
"typeVersion": 2,
|
||
"position": [680, 300]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"method": "POST",
|
||
"url": "={{ $env.TRADING_BOT_API_URL }}/api/trading/check-risk",
|
||
"authentication": "predefinedCredentialType",
|
||
"nodeCredentialType": "httpHeaderAuth",
|
||
"sendHeaders": true,
|
||
"headerParameters": {
|
||
"parameters": [
|
||
{
|
||
"name": "Content-Type",
|
||
"value": "application/json"
|
||
},
|
||
{
|
||
"name": "Authorization",
|
||
"value": "={{ 'Bearer ' + $env.API_SECRET_KEY }}"
|
||
}
|
||
]
|
||
},
|
||
"sendBody": true,
|
||
"bodyParameters": {
|
||
"parameters": [
|
||
{
|
||
"name": "symbol",
|
||
"value": "={{ $json.driftSymbol }}"
|
||
},
|
||
{
|
||
"name": "direction",
|
||
"value": "={{ $json.direction }}"
|
||
}
|
||
]
|
||
},
|
||
"options": {
|
||
"timeout": 10000
|
||
}
|
||
},
|
||
"id": "check-risk",
|
||
"name": "Check Risk Limits",
|
||
"type": "n8n-nodes-base.httpRequest",
|
||
"typeVersion": 4.1,
|
||
"position": [900, 300]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"conditions": {
|
||
"options": {
|
||
"caseSensitive": true,
|
||
"leftValue": "",
|
||
"typeValidation": "strict"
|
||
},
|
||
"conditions": [
|
||
{
|
||
"id": "risk-allowed",
|
||
"leftValue": "={{ $json.allowed }}",
|
||
"rightValue": true,
|
||
"operator": {
|
||
"type": "boolean",
|
||
"operation": "equals"
|
||
}
|
||
}
|
||
],
|
||
"combinator": "and"
|
||
},
|
||
"options": {}
|
||
},
|
||
"id": "if-risk-passed",
|
||
"name": "Risk Check Passed?",
|
||
"type": "n8n-nodes-base.if",
|
||
"typeVersion": 2,
|
||
"position": [1120, 300]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"method": "POST",
|
||
"url": "={{ $env.TRADING_BOT_API_URL }}/api/trading/execute",
|
||
"authentication": "predefinedCredentialType",
|
||
"nodeCredentialType": "httpHeaderAuth",
|
||
"sendHeaders": true,
|
||
"headerParameters": {
|
||
"parameters": [
|
||
{
|
||
"name": "Content-Type",
|
||
"value": "application/json"
|
||
},
|
||
{
|
||
"name": "Authorization",
|
||
"value": "={{ 'Bearer ' + $env.API_SECRET_KEY }}"
|
||
}
|
||
]
|
||
},
|
||
"sendBody": true,
|
||
"bodyParameters": {
|
||
"parameters": [
|
||
{
|
||
"name": "symbol",
|
||
"value": "={{ $('Extract Signal Data').item.json.driftSymbol }}"
|
||
},
|
||
{
|
||
"name": "direction",
|
||
"value": "={{ $('Extract Signal Data').item.json.direction }}"
|
||
},
|
||
{
|
||
"name": "timeframe",
|
||
"value": "={{ $('Extract Signal Data').item.json.timeframe }}"
|
||
},
|
||
{
|
||
"name": "signalStrength",
|
||
"value": "={{ $('Extract Signal Data').item.json.strength }}"
|
||
},
|
||
{
|
||
"name": "signalPrice",
|
||
"value": "={{ $('Extract Signal Data').item.json.price }}"
|
||
}
|
||
]
|
||
},
|
||
"options": {
|
||
"timeout": 30000
|
||
}
|
||
},
|
||
"id": "execute-trade",
|
||
"name": "Execute Trade",
|
||
"type": "n8n-nodes-base.httpRequest",
|
||
"typeVersion": 4.1,
|
||
"position": [1340, 200]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"chatId": "={{ $env.TELEGRAM_CHAT_ID }}",
|
||
"text": "=🎯 **Trade Executed!**\n\n📊 **Symbol:** {{ $json.symbol }}\n📈 **Direction:** {{ $json.direction.toUpperCase() }}\n💰 **Entry:** ${{ $json.entryPrice }}\n🎲 **Leverage:** 10x\n💵 **Position Size:** ${{ $json.positionSize }}\n\n**Targets:**\n🔴 **Stop Loss:** ${{ $json.stopLoss }} (-{{ $json.stopLossPercent }}%)\n🟡 **TP1 (50%):** ${{ $json.takeProfit1 }} (+{{ $json.tp1Percent }}%)\n🟢 **TP2 (50%):** ${{ $json.takeProfit2 }} (+{{ $json.tp2Percent }}%)\n\n⏱️ **Time:** {{ $json.timestamp }}\n✅ **Status:** Position opened\n\n📱 Position ID: `{{ $json.positionId }}`",
|
||
"additionalFields": {
|
||
"parse_mode": "Markdown"
|
||
}
|
||
},
|
||
"id": "telegram-success",
|
||
"name": "Telegram - Trade Success",
|
||
"type": "n8n-nodes-base.telegram",
|
||
"typeVersion": 1.1,
|
||
"position": [1560, 100],
|
||
"credentials": {
|
||
"telegramApi": {
|
||
"id": "telegram-credentials",
|
||
"name": "Telegram Bot"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"chatId": "={{ $env.TELEGRAM_CHAT_ID }}",
|
||
"text": "=❌ **Trade Blocked**\n\n⚠️ **Reason:** {{ $('Check Risk Limits').item.json.reason }}\n📊 **Symbol:** {{ $('Extract Signal Data').item.json.driftSymbol }}\n📈 **Direction:** {{ $('Extract Signal Data').item.json.direction.toUpperCase() }}\n💰 **Price:** ${{ $('Extract Signal Data').item.json.price }}\n⏱️ **Time:** {{ $('Extract Signal Data').item.json.timestamp }}\n\n**Risk Status:**\n{{ $('Check Risk Limits').item.json.details || 'Check dashboard for details' }}",
|
||
"additionalFields": {
|
||
"parse_mode": "Markdown"
|
||
}
|
||
},
|
||
"id": "telegram-blocked",
|
||
"name": "Telegram - Trade Blocked",
|
||
"type": "n8n-nodes-base.telegram",
|
||
"typeVersion": 1.1,
|
||
"position": [1340, 400],
|
||
"credentials": {
|
||
"telegramApi": {
|
||
"id": "telegram-credentials",
|
||
"name": "Telegram Bot"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"method": "POST",
|
||
"url": "={{ $env.DISCORD_WEBHOOK_URL }}",
|
||
"sendBody": true,
|
||
"specifyBody": "json",
|
||
"jsonBody": "={\n \"embeds\": [{\n \"title\": \"🎯 New Trade Executed\",\n \"color\": {{ $json.direction === 'long' ? 5814783 : 15158332 }},\n \"fields\": [\n { \"name\": \"Symbol\", \"value\": \"{{ $json.symbol }}\", \"inline\": true },\n { \"name\": \"Direction\", \"value\": \"{{ $json.direction.toUpperCase() }}\", \"inline\": true },\n { \"name\": \"Leverage\", \"value\": \"10x\", \"inline\": true },\n { \"name\": \"Entry Price\", \"value\": \"${{ $json.entryPrice }}\", \"inline\": true },\n { \"name\": \"Position Size\", \"value\": \"${{ $json.positionSize }}\", \"inline\": true },\n { \"name\": \"Slippage\", \"value\": \"{{ $json.entrySlippage }}%\", \"inline\": true },\n { \"name\": \"Stop Loss\", \"value\": \"${{ $json.stopLoss }}\", \"inline\": true },\n { \"name\": \"Take Profit 1\", \"value\": \"${{ $json.takeProfit1 }}\", \"inline\": true },\n { \"name\": \"Take Profit 2\", \"value\": \"${{ $json.takeProfit2 }}\", \"inline\": true }\n ],\n \"footer\": {\n \"text\": \"Position ID: {{ $json.positionId }}\"\n },\n \"timestamp\": \"{{ $json.timestamp }}\"\n }]\n}",
|
||
"options": {}
|
||
},
|
||
"id": "discord-notification",
|
||
"name": "Discord - Trade Success",
|
||
"type": "n8n-nodes-base.httpRequest",
|
||
"typeVersion": 4.1,
|
||
"position": [1560, 200]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"respondWith": "json",
|
||
"responseBody": "={{ JSON.stringify({\n success: $json.success !== undefined ? $json.success : true,\n positionId: $json.positionId || null,\n message: $json.message || 'Trade processed',\n timestamp: new Date().toISOString()\n}) }}"
|
||
},
|
||
"id": "webhook-response",
|
||
"name": "Webhook Response",
|
||
"type": "n8n-nodes-base.respondToWebhook",
|
||
"typeVersion": 1,
|
||
"position": [1780, 300]
|
||
}
|
||
],
|
||
"pinData": {},
|
||
"connections": {
|
||
"TradingView Webhook": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Verify Secret",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Verify Secret": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Extract Signal Data",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Extract Signal Data": {
|
||
"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",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
],
|
||
[
|
||
{
|
||
"node": "Telegram - Trade Blocked",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Execute Trade": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Telegram - Trade Success",
|
||
"type": "main",
|
||
"index": 0
|
||
},
|
||
{
|
||
"node": "Discord - Trade Success",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Telegram - Trade Success": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Webhook Response",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Discord - Trade Success": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Webhook Response",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Telegram - Trade Blocked": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Webhook Response",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
}
|
||
},
|
||
"active": false,
|
||
"settings": {
|
||
"executionOrder": "v1"
|
||
},
|
||
"versionId": "trading-bot-v4-1.0.0",
|
||
"id": "trading-bot-v4",
|
||
"meta": {
|
||
"instanceId": "your-n8n-instance-id"
|
||
},
|
||
"tags": [
|
||
{
|
||
"createdAt": "2025-10-23T00:00:00.000Z",
|
||
"updatedAt": "2025-10-23T00:00:00.000Z",
|
||
"id": "1",
|
||
"name": "trading"
|
||
},
|
||
{
|
||
"createdAt": "2025-10-23T00:00:00.000Z",
|
||
"updatedAt": "2025-10-23T00:00:00.000Z",
|
||
"id": "2",
|
||
"name": "automation"
|
||
}
|
||
]
|
||
}
|