Files
trading_bot_v4/workflows/trading/money machine compare.json
mindesbunister 0558111ded feat: Update Money Machine workflow for multi-timeframe data collection
- Replaced Parse Signal node with enhanced version (regex supports buy 5, buy 15, buy 1h, buy 4h, buy D)
- Updated Execute Trade jsonBody to include all metrics: atr, adx, rsi, volumeRatio, pricePosition, indicatorVersion
- Removed 5min Chart Only filter - execute endpoint now handles routing automatically
- Flow: Webhook → Parse Signal Enhanced → Execute Trade → Telegram
- 5min signals execute trades, 15m/1h/4h/daily save to BlockedSignal for analysis
- User will manually update n8n nodes after JSON changes
2025-11-19 10:42:47 +01:00

486 lines
17 KiB
JSON
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"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": [
-1020,
660
],
"webhookId": "tradingview-bot-v4"
},
{
"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": [
-120,
660
]
},
{
"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 Trade1').item.json.positionSize}\n⚡ Leverage: ${$('Execute Trade1').item.json.leverage}x${$('Execute Trade1').item.json.qualityScore ? `\n\n⭐ Quality: ${$('Execute Trade1').item.json.qualityScore}/100` : ''}\n\n💰 Entry: $${$('Execute Trade1').item.json.entryPrice.toFixed(4)}\n🎯 TP1: $${$('Execute Trade1').item.json.takeProfit1.toFixed(4)} (${$('Execute Trade1').item.json.tp1Percent}%)\n🎯 TP2: $${$('Execute Trade1').item.json.takeProfit2.toFixed(4)} (${$('Execute Trade1').item.json.tp2Percent}%)\n🛑 SL: $${$('Execute Trade1').item.json.stopLoss.toFixed(4)} (${$('Execute Trade1').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 Enhanced')').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": {
"fields": {
"values": [
{
"name": "message",
"stringValue": "={{ '⚠️ 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') }}"
}
]
},
"options": {}
},
"id": "da462967-0548-4d57-a6de-cb783c96ac07",
"name": "Format Risk",
"type": "n8n-nodes-base.set",
"typeVersion": 3.2,
"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 }}",
"value2": "5"
}
]
}
},
"id": "8c680565-120d-47dc-83b2-58dcd397168b",
"name": "5min Chart Only?1",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
-500,
660
]
},
{
"parameters": {
"chatId": "579304651",
"text": "={{ $json.rawMessage }}",
"additionalFields": {
"appendAttribution": false
}
},
"id": "a63da8d2-e255-4933-9fba-a1999d2da31e",
"name": "Trend Signal",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.1,
"position": [
-260,
860
],
"credentials": {
"telegramApi": {
"id": "Csk5cg4HtaSqP5jJ",
"name": "Telegram account"
}
}
},
{
"parameters": {
"jsCode": "// Get the body - it might be a string or nested in an object\nlet body = $json.body || $json.query?.body || JSON.stringify($json);\n\n// If body is an object, stringify it\nif (typeof body === 'object') {\n body = JSON.stringify(body);\n}\n\n// Parse basic signal (existing logic)\nconst symbolMatch = body.match(/\\b(SOL|BTC|ETH)\\b/i);\nconst symbol = symbolMatch ? symbolMatch[1].toUpperCase() + '-PERP' : 'SOL-PERP';\n\nconst direction = body.match(/\\b(sell|short)\\b/i) ? 'short' : 'long';\n\n// Enhanced timeframe extraction supporting multiple formats:\n// - \"buy 5\" → \"5\"\n// - \"buy 15\" → \"15\"\n// - \"buy 60\" or \"buy 1h\" → \"60\"\n// - \"buy 240\" or \"buy 4h\" → \"240\"\n// - \"buy D\" or \"buy 1d\" → \"D\"\n// - \"buy W\" → \"W\"\nconst timeframeMatch = body.match(/\\b(buy|sell)\\s+(\\d+|D|W|M|1h|4h|1d)\\b/i);\nlet timeframe = '5'; // Default to 5min\n\nif (timeframeMatch) {\n const tf = timeframeMatch[2];\n // Convert hour/day notation to minutes\n if (tf === '1h' || tf === '60') {\n timeframe = '60';\n } else if (tf === '4h' || tf === '240') {\n timeframe = '240';\n } else if (tf === '1d' || tf.toUpperCase() === 'D') {\n timeframe = 'D';\n } else if (tf.toUpperCase() === 'W') {\n timeframe = 'W';\n } else if (tf.toUpperCase() === 'M') {\n timeframe = 'M';\n } else {\n timeframe = tf;\n }\n}\n\n// Parse new context metrics from enhanced format:\n// \"SOLT.P buy 15 | ATR:0.65 | ADX:14.3 | RSI:51.3 | VOL:0.87 | POS:59.3 | IND:v8\"\nconst atrMatch = body.match(/ATR:([\\d.]+)/);\nconst atr = atrMatch ? parseFloat(atrMatch[1]) : 0;\n\nconst adxMatch = body.match(/ADX:([\\d.]+)/);\nconst adx = adxMatch ? parseFloat(adxMatch[1]) : 0;\n\nconst rsiMatch = body.match(/RSI:([\\d.]+)/);\nconst rsi = rsiMatch ? parseFloat(rsiMatch[1]) : 0;\n\nconst volumeMatch = body.match(/VOL:([\\d.]+)/);\nconst volumeRatio = volumeMatch ? parseFloat(volumeMatch[1]) : 0;\n\nconst pricePositionMatch = body.match(/POS:([\\d.]+)/);\nconst pricePosition = pricePositionMatch ? parseFloat(pricePositionMatch[1]) : 0;\n\n// Parse indicator version (optional, backward compatible)\nconst indicatorVersionMatch = body.match(/IND:(v\\d+)/i);\nconst indicatorVersion = indicatorVersionMatch ? indicatorVersionMatch[1] : 'v5';\n\nreturn {\n rawMessage: body,\n symbol,\n direction,\n timeframe,\n // Context fields\n atr,\n adx,\n rsi,\n volumeRatio,\n pricePosition,\n // Version tracking (defaults to v5 for backward compatibility)\n indicatorVersion\n};"
},
"id": "81f28bc7-c96a-4021-acac-242e993d9d98",
"name": "Parse Signal Enhanced",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-760,
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 \"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 \"indicatorVersion\": \"{{ $('Parse Signal Enhanced').item.json.indicatorVersion }}\",\n \"signalPrice\": {{ $('Parse Signal Enhanced').item.json.pricePosition }}\n}",
"options": {
"timeout": 120000
}
},
"id": "9902ecc4-53b0-402f-8db9-6248e6077740",
"name": "Execute Trade1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
80,
560
],
"credentials": {
"httpHeaderAuth": {
"id": "MATuNdkZclq5ISbr",
"name": "Header Auth account"
}
}
},
{
"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 \"timeframe\": \"{{ $json.timeframe }}\",\n \"atr\": {{ $json.atr || 0 }},\n \"adx\": {{ $json.adx || 0 }},\n \"rsi\": {{ $json.rsi || 0 }},\n \"volumeRatio\": {{ $json.volumeRatio || 0 }},\n \"pricePosition\": {{ $json.pricePosition || 0 }},\n \"indicatorVersion\": \"{{ $json.indicatorVersion || 'v5' }}\"\n}",
"options": {}
},
"id": "55671044-c7c8-4566-b271-9369a1c43158",
"name": "Check Risk1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
-280,
560
],
"credentials": {
"httpHeaderAuth": {
"id": "MATuNdkZclq5ISbr",
"name": "Header Auth account"
}
}
},
{
"parameters": {
"jsCode": "// Get the body - it might be a string or nested in an object\nlet body = $json.body || $json.query?.body || JSON.stringify($json);\n\n// If body is an object, stringify it\nif (typeof body === 'object') {\n body = JSON.stringify(body);\n}\n\n// Parse basic signal (existing logic)\nconst symbolMatch = body.match(/\\b(SOL|BTC|ETH)/i);\nconst symbol = symbolMatch ? symbolMatch[1].toUpperCase() + '-PERP' : 'SOL-PERP';\n\nconst direction = body.match(/\\b(sell|short)\\b/i) ? 'short' : 'long';\n\n// Updated regex to match new format: \"ETH buy 15\" (no .P)\nconst timeframeMatch = body.match(/\\b(buy|sell)\\s+(\\d+|D|W|M)\\b/i);\nconst timeframe = timeframeMatch ? timeframeMatch[2] : '5';\n\n// Parse new context metrics from enhanced format:\n// \"ETH buy 15 | ATR:1.85 | ADX:28.3 | RSI:62.5 | VOL:1.45 | POS:75.3\"\nconst atrMatch = body.match(/ATR:([\\d.]+)/);\nconst atr = atrMatch ? parseFloat(atrMatch[1]) : 0;\n\nconst adxMatch = body.match(/ADX:([\\d.]+)/);\nconst adx = adxMatch ? parseFloat(adxMatch[1]) : 0;\n\nconst rsiMatch = body.match(/RSI:([\\d.]+)/);\nconst rsi = rsiMatch ? parseFloat(rsiMatch[1]) : 0;\n\nconst volumeMatch = body.match(/VOL:([\\d.]+)/);\nconst volumeRatio = volumeMatch ? parseFloat(volumeMatch[1]) : 0;\n\nconst pricePositionMatch = body.match(/POS:([\\d.]+)/);\nconst pricePosition = pricePositionMatch ? parseFloat(pricePositionMatch[1]) : 0;\n\nreturn {\n rawMessage: body,\n symbol,\n direction,\n timeframe,\n // New context fields\n atr,\n adx,\n rsi,\n volumeRatio,\n pricePosition\n};"
},
"id": "91448acb-70f3-45d1-8de0-497ed1cba044",
"name": "Parse Signal Enhanced _ Backup",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-760,
840
]
}
],
"pinData": {},
"connections": {
"Webhook": {
"main": [
[
{
"node": "Parse Signal Enhanced",
"type": "main",
"index": 0
}
]
]
},
"Risk Passed?": {
"main": [
[
{
"node": "Execute Trade1",
"type": "main",
"index": 0
}
],
[
{
"node": "Format Risk",
"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
}
]
]
},
"5min Chart Only?1": {
"main": [
[
{
"node": "Check Risk1",
"type": "main",
"index": 0
}
],
[
{
"node": "Trend Signal",
"type": "main",
"index": 0
}
]
]
},
"Parse Signal Enhanced": {
"main": [
[
{
"node": "5min Chart Only?1",
"type": "main",
"index": 0
}
]
]
},
"Execute Trade1": {
"main": [
[
{
"node": "Trade Success?",
"type": "main",
"index": 0
}
]
]
},
"Check Risk1": {
"main": [
[
{
"node": "Risk Passed?",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1"
},
"versionId": "450a7a8e-d141-4ba0-be79-85c06c4ae17b",
"id": "gUDqTiHyHSfRUXv6",
"meta": {
"instanceId": "e766d4f0b5def8ee8cb8561cd9d2b9ba7733e1907990b6987bca40175f82c379"
},
"tags": []
}