- Add qualityScore to ExecuteTradeResponse interface and response object - Update analytics page to always show Signal Quality card (N/A if unavailable) - Fix n8n workflow to pass context metrics and qualityScore to execute endpoint - Fix timezone in Telegram notifications (Europe/Berlin) - Fix symbol normalization in /api/trading/close endpoint - Update Drift ETH-PERP minimum order size (0.002 ETH not 0.01) - Add transaction confirmation to closePosition() to prevent phantom closes - Add 30-second grace period for new trades in Position Manager - Fix execution order: database save before Position Manager.addTrade() - Update copilot instructions with transaction confirmation pattern
505 lines
13 KiB
JSON
505 lines
13 KiB
JSON
{
|
||
"name": "Money Machine",
|
||
"nodes": [
|
||
{
|
||
"parameters": {
|
||
"httpMethod": "POST",
|
||
"path": "tradingview-bot-v4",
|
||
"options": {}
|
||
},
|
||
"id": "c762618c-fac7-4689-9356-8a78fc7160a8",
|
||
"name": "Webhook",
|
||
"type": "n8n-nodes-base.webhook",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
-980,
|
||
680
|
||
],
|
||
"webhookId": "tradingview-bot-v4"
|
||
},
|
||
{
|
||
"parameters": {
|
||
"fields": {
|
||
"values": [
|
||
{
|
||
"name": "rawMessage",
|
||
"stringValue": "={{ $json.body }}"
|
||
},
|
||
{
|
||
"name": "symbol",
|
||
"stringValue": "={{ $json.body.match(/\\bSOL\\b/i) ? 'SOL-PERP' : ($json.body.match(/\\bBTC\\b/i) ? 'BTC-PERP' : ($json.body.match(/\\bETH\\b/i) ? 'ETH-PERP' : 'SOL-PERP')) }}"
|
||
},
|
||
{
|
||
"name": "direction",
|
||
"stringValue": "={{ $json.body.match(/\\b(sell|short)\\b/i) ? 'short' : 'long' }}"
|
||
},
|
||
{
|
||
"name": "timeframe",
|
||
"stringValue": "={{ $json.body.match(/\\.P\\s+(\\d+)/)?.[1] || '15' }}"
|
||
}
|
||
]
|
||
},
|
||
"options": {}
|
||
},
|
||
"id": "97d5b0ad-d078-411f-8f34-c9a81d18d921",
|
||
"name": "Parse Signal",
|
||
"type": "n8n-nodes-base.set",
|
||
"typeVersion": 3.2,
|
||
"position": [
|
||
-780,
|
||
680
|
||
]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"conditions": {
|
||
"string": [
|
||
{
|
||
"value1": "={{ $json.timeframe }}",
|
||
"operation": "equals",
|
||
"value2": "15"
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"id": "2e0bf241-9fb6-40bd-89f6-2dceafe34ef9",
|
||
"name": "15min Chart Only?",
|
||
"type": "n8n-nodes-base.if",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
-560,
|
||
540
|
||
]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"method": "POST",
|
||
"url": "http://10.0.0.48:3001/api/trading/check-risk",
|
||
"authentication": "genericCredentialType",
|
||
"genericAuthType": "httpHeaderAuth",
|
||
"sendHeaders": true,
|
||
"headerParameters": {
|
||
"parameters": [
|
||
{
|
||
"name": "Authorization",
|
||
"value": "Bearer 2a344f0149442c857fb56c038c0c7d1b113883b830bec792c76f1e0efa15d6bb"
|
||
},
|
||
{
|
||
"name": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
]
|
||
},
|
||
"sendBody": true,
|
||
"specifyBody": "json",
|
||
"jsonBody": "={\n \"symbol\": \"{{ $json.symbol }}\",\n \"direction\": \"{{ $json.direction }}\"\n}",
|
||
"options": {}
|
||
},
|
||
"id": "c1165de4-2095-4f5f-b9b1-18e76fd8c47b",
|
||
"name": "Check Risk",
|
||
"type": "n8n-nodes-base.httpRequest",
|
||
"typeVersion": 4,
|
||
"position": [
|
||
-280,
|
||
660
|
||
],
|
||
"credentials": {
|
||
"httpHeaderAuth": {
|
||
"id": "MATuNdkZclq5ISbr",
|
||
"name": "Header Auth account"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"conditions": {
|
||
"boolean": [
|
||
{
|
||
"value1": "={{ $json.allowed }}",
|
||
"value2": true
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"id": "b9fa2b47-2acd-4be0-9d50-3f0348e04ec6",
|
||
"name": "Risk Passed?",
|
||
"type": "n8n-nodes-base.if",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
-80,
|
||
660
|
||
]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"method": "POST",
|
||
"url": "http://10.0.0.48:3001/api/trading/execute",
|
||
"authentication": "genericCredentialType",
|
||
"genericAuthType": "httpHeaderAuth",
|
||
"sendHeaders": true,
|
||
"headerParameters": {
|
||
"parameters": [
|
||
{
|
||
"name": "Authorization",
|
||
"value": "Bearer 2a344f0149442c857fb56c038c0c7d1b113883b830bec792c76f1e0efa15d6bb"
|
||
},
|
||
{
|
||
"name": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
]
|
||
},
|
||
"sendBody": true,
|
||
"specifyBody": "json",
|
||
"jsonBody": "={\n \"symbol\": \"{{ $('Parse Signal Enhanced').item.json.symbol }}\",\n \"direction\": \"{{ $('Parse Signal Enhanced').item.json.direction }}\",\n \"timeframe\": \"{{ $('Parse Signal Enhanced').item.json.timeframe }}\",\n \"signalStrength\": \"strong\",\n \"atr\": {{ $('Parse Signal Enhanced').item.json.atr }},\n \"adx\": {{ $('Parse Signal Enhanced').item.json.adx }},\n \"rsi\": {{ $('Parse Signal Enhanced').item.json.rsi }},\n \"volumeRatio\": {{ $('Parse Signal Enhanced').item.json.volumeRatio }},\n \"pricePosition\": {{ $('Parse Signal Enhanced').item.json.pricePosition }},\n \"qualityScore\": {{ $('Check Risk').item.json.qualityScore }}\n}",
|
||
"options": {
|
||
"timeout": 120000
|
||
}
|
||
},
|
||
"id": "c2ec5f8c-42d1-414f-bdd6-0a440bc8fea9",
|
||
"name": "Execute Trade",
|
||
"type": "n8n-nodes-base.httpRequest",
|
||
"typeVersion": 4,
|
||
"position": [
|
||
60,
|
||
560
|
||
],
|
||
"credentials": {
|
||
"httpHeaderAuth": {
|
||
"id": "MATuNdkZclq5ISbr",
|
||
"name": "Header Auth account"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"conditions": {
|
||
"boolean": [
|
||
{
|
||
"value1": "={{ $json.success }}",
|
||
"value2": true
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"id": "16dbf434-a07c-4666-82f2-cdc8814fe216",
|
||
"name": "Trade Success?",
|
||
"type": "n8n-nodes-base.if",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
260,
|
||
560
|
||
]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"fields": {
|
||
"values": [
|
||
{
|
||
"name": "message",
|
||
"stringValue": "={{ `🟢 TRADE OPENED\n\n📊 Symbol: ${$('Parse Signal Enhanced').item.json.symbol}\n${$('Parse Signal Enhanced').item.json.direction === 'long' ? '📈' : '📉'} Direction: ${$('Parse Signal Enhanced').item.json.direction.toUpperCase()}\n\n💵 Position: $${$('Execute Trade').item.json.positionSize}\n⚡ Leverage: ${$('Execute Trade').item.json.leverage}x${$('Execute Trade').item.json.qualityScore ? `\n⭐ Quality: ${$('Execute Trade').item.json.qualityScore}/100` : ''}\n\n💰 Entry: $${$('Execute Trade').item.json.entryPrice.toFixed(4)}\n🎯 TP1: $${$('Execute Trade').item.json.takeProfit1.toFixed(4)} (${$('Execute Trade').item.json.tp1Percent}%)\n🎯 TP2: $${$('Execute Trade').item.json.takeProfit2.toFixed(4)} (${$('Execute Trade').item.json.tp2Percent}%)\n🛑 SL: $${$('Execute Trade').item.json.stopLoss.toFixed(4)} (${$('Execute Trade').item.json.stopLossPercent}%)\n\n⏰ ${$now.setZone('Europe/Berlin').toFormat('HH:mm:ss')}\n✅ Position monitored` }}"
|
||
}
|
||
]
|
||
},
|
||
"options": {}
|
||
},
|
||
"id": "79ab6122-cbd3-4aac-97d7-6b54f64e29b5",
|
||
"name": "Format Success",
|
||
"type": "n8n-nodes-base.set",
|
||
"typeVersion": 3.2,
|
||
"position": [
|
||
460,
|
||
460
|
||
]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"fields": {
|
||
"values": [
|
||
{
|
||
"name": "message",
|
||
"stringValue": "🔴 TRADE FAILED\\n\\n{{ $('Parse Signal').item.json.rawMessage }}\\n\\n❌ Error: {{ $json.error || $json.message }}\\n⏰ {{ $now.setZone('Europe/Berlin').toFormat('HH:mm') }}"
|
||
}
|
||
]
|
||
},
|
||
"options": {}
|
||
},
|
||
"id": "41a0a8be-5004-4e6d-bdc5-9c7edf04eb51",
|
||
"name": "Format Error",
|
||
"type": "n8n-nodes-base.set",
|
||
"typeVersion": 3.2,
|
||
"position": [
|
||
460,
|
||
660
|
||
]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"mode": "manual",
|
||
"duplicateItem": false,
|
||
"assignments": {
|
||
"assignments": [
|
||
{
|
||
"id": "risk_message",
|
||
"name": "message",
|
||
"value": "={{ '⚠️ TRADE BLOCKED\\n\\n' + $('Parse Signal Enhanced').item.json.rawMessage + '\\n\\n🛑 Reason: ' + $json.reason + '\\n📋 Details: ' + ($json.details || 'N/A') + '\\n\\n📊 Quality Score: ' + ($json.qualityScore || 'N/A') + '/100' + ($json.qualityReasons && $json.qualityReasons.length > 0 ? '\\n⚠️ Issues:\\n • ' + $json.qualityReasons.join('\\n • ') : '') + '\\n\\n⏰ ' + $now.setZone('Europe/Berlin').toFormat('HH:mm:ss') }}",
|
||
"type": "string"
|
||
}
|
||
]
|
||
},
|
||
"options": {}
|
||
},
|
||
"id": "da462967-0548-4d57-a6de-cb783c96ac07",
|
||
"name": "Format Risk",
|
||
"type": "n8n-nodes-base.set",
|
||
"typeVersion": 3.4,
|
||
"position": [
|
||
60,
|
||
760
|
||
]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"chatId": "579304651",
|
||
"text": "={{ $json.message }}",
|
||
"additionalFields": {
|
||
"appendAttribution": false
|
||
}
|
||
},
|
||
"id": "254280fd-f547-4302-97a5-30b44d851e12",
|
||
"name": "Telegram Success",
|
||
"type": "n8n-nodes-base.telegram",
|
||
"typeVersion": 1.1,
|
||
"position": [
|
||
660,
|
||
460
|
||
],
|
||
"credentials": {
|
||
"telegramApi": {
|
||
"id": "Csk5cg4HtaSqP5jJ",
|
||
"name": "Telegram account"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"chatId": "579304651",
|
||
"text": "={{ $json.message }}",
|
||
"additionalFields": {
|
||
"appendAttribution": false
|
||
}
|
||
},
|
||
"id": "4ea066c9-4971-408f-b6e2-7d704c13ef55",
|
||
"name": "Telegram Error",
|
||
"type": "n8n-nodes-base.telegram",
|
||
"typeVersion": 1.1,
|
||
"position": [
|
||
660,
|
||
660
|
||
],
|
||
"credentials": {
|
||
"telegramApi": {
|
||
"id": "Csk5cg4HtaSqP5jJ",
|
||
"name": "Telegram account"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"chatId": "579304651",
|
||
"text": "={{ $json.message }}",
|
||
"additionalFields": {
|
||
"appendAttribution": false
|
||
}
|
||
},
|
||
"id": "ee6be7be-1735-4fa3-bd33-6b3fde9414d3",
|
||
"name": "Telegram Risk",
|
||
"type": "n8n-nodes-base.telegram",
|
||
"typeVersion": 1.1,
|
||
"position": [
|
||
260,
|
||
760
|
||
],
|
||
"credentials": {
|
||
"telegramApi": {
|
||
"id": "Csk5cg4HtaSqP5jJ",
|
||
"name": "Telegram account"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"conditions": {
|
||
"string": [
|
||
{
|
||
"value1": "={{ $json.timeframe }}",
|
||
"operation": "equals",
|
||
"value2": "5"
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"id": "8c680565-120d-47dc-83b2-58dcd397168b",
|
||
"name": "5min Chart Only?1",
|
||
"type": "n8n-nodes-base.if",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
-560,
|
||
800
|
||
]
|
||
}
|
||
],
|
||
"pinData": {},
|
||
"connections": {
|
||
"Webhook": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Parse Signal",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Parse Signal": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "15min Chart Only?",
|
||
"type": "main",
|
||
"index": 0
|
||
},
|
||
{
|
||
"node": "5min Chart Only?1",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Check Risk": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Risk Passed?",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Risk Passed?": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Execute Trade",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
],
|
||
[
|
||
{
|
||
"node": "Format Risk",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Execute Trade": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Trade Success?",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Trade Success?": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Format Success",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
],
|
||
[
|
||
{
|
||
"node": "Format Error",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Format Success": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Telegram Success",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Format Error": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Telegram Error",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Format Risk": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Telegram Risk",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"15min Chart Only?": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Check Risk",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"5min Chart Only?1": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Check Risk",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
}
|
||
},
|
||
"active": true,
|
||
"settings": {
|
||
"executionOrder": "v1"
|
||
},
|
||
"versionId": "1376fb3b-08fb-4d96-a038-371249d36eda",
|
||
"id": "gUDqTiHyHSfRUXv6",
|
||
"meta": {
|
||
"instanceId": "e766d4f0b5def8ee8cb8561cd9d2b9ba7733e1907990b6987bca40175f82c379"
|
||
},
|
||
"tags": []
|
||
} |