feat: Add n8n workflow for TradingView webhook automation

- Complete 13-node workflow connecting TradingView alerts to trade execution
- Webhook validation, risk checking, and trade execution via v4 API
- Telegram notifications for all scenarios (success/error/blocked)
- Comprehensive setup guide with testing and troubleshooting
- Supports SOL/BTC/ETH and LONG/SHORT signals from TradingView
This commit is contained in:
mindesbunister
2025-10-23 15:11:37 +02:00
parent 8bb2f64568
commit 4a9a80f045
2 changed files with 895 additions and 0 deletions

500
v4/N8N_WORKFLOW_GUIDE.md Normal file
View File

@@ -0,0 +1,500 @@
# n8n Workflow Setup Guide - Trading Bot v4
Complete guide to set up the automated trading workflow in n8n.
---
## 📋 Workflow Overview
```
TradingView Alert (Webhook)
Validate Secret
Parse Signal (SOL/BTC/ETH, LONG/SHORT)
Check Risk Limits (API call to /api/trading/check-risk)
Execute Trade (API call to /api/trading/execute)
Format Message (Success/Error/Blocked)
Send Telegram Notification
```
---
## 🚀 Quick Setup
### Step 1: Import Workflow
1. Open your n8n instance
2. Click **"+ New Workflow"**
3. Click **"⋮"** (three dots) → **"Import from File"**
4. Select `n8n-workflow-complete.json`
5. Click **"Import"**
### Step 2: Configure Environment Variables
In n8n, go to **Settings****Environment Variables** and add:
```bash
# Your trading bot API URL
TRADING_BOT_API_URL=http://your-server:3000
# API secret key (must match .env in v4)
API_SECRET_KEY=your_secret_key_from_env
# TradingView webhook validation
TRADINGVIEW_WEBHOOK_SECRET=your_tradingview_secret
# Telegram credentials
TELEGRAM_CHAT_ID=your_telegram_chat_id
```
### Step 3: Configure Telegram Credentials
1. In n8n, click **"Telegram - Send Notification"** node
2. Click **"Create New Credential"**
3. Enter your **Telegram Bot Token**
4. Save credential
### Step 4: Get Webhook URL
1. Click **"Webhook - TradingView Alert"** node
2. Click **"Test URL"** or **"Production URL"**
3. Copy the webhook URL (looks like: `https://your-n8n.com/webhook/tradingview-webhook`)
4. Save this for TradingView setup
### Step 5: Activate Workflow
1. Toggle **"Active"** switch at top right
2. Workflow is now listening for webhooks!
---
## 🔧 Detailed Configuration
### Webhook Node Configuration
**Node:** `Webhook - TradingView Alert`
- **HTTP Method:** POST
- **Path:** `tradingview-webhook` (or customize)
- **Response:** Return on Last Node
- **Raw Body:** Enabled
**What it does:** Receives TradingView alerts via webhook
### Validate Secret Node
**Node:** `Validate Secret`
- **Type:** IF condition
- **Condition:** `{{$json.body.secret}} equals {{$env.TRADINGVIEW_WEBHOOK_SECRET}}`
**What it does:** Prevents unauthorized trade execution
**Important:** Make sure TradingView webhook includes `?secret=YOUR_SECRET` in URL
### Parse TradingView Signal Node
**Node:** `Parse TradingView Signal`
- **Type:** Code (Function)
- **Language:** JavaScript
**What it does:**
- Extracts symbol, action, timeframe from TradingView alert
- Normalizes data for v4 API
- Supports various TradingView alert formats
**Supported formats:**
```json
{
"symbol": "SOLUSDT",
"action": "buy",
"timeframe": "5",
"price": "140.25",
"timestamp": "2025-10-23T10:00:00Z"
}
```
Or:
```json
{
"ticker": "SOL-PERP",
"signal_type": "long",
"interval": "5m",
"close": "140.25"
}
```
### Check Risk Limits Node
**Node:** `Check Risk Limits`
- **URL:** `{{$env.TRADING_BOT_API_URL}}/api/trading/check-risk`
- **Method:** POST
- **Headers:**
- `Authorization: Bearer {{$env.API_SECRET_KEY}}`
- `Content-Type: application/json`
- **Body:**
```json
{
"symbol": "{{$json.apiPayload.symbol}}",
"direction": "{{$json.apiPayload.direction}}"
}
```
**What it does:**
- Checks daily drawdown limits
- Validates trades per hour
- Ensures cooldown period passed
### Execute Trade Node
**Node:** `Execute Trade on Drift`
- **URL:** `{{$env.TRADING_BOT_API_URL}}/api/trading/execute`
- **Method:** POST
- **Timeout:** 30000ms (30 seconds)
- **Headers:**
- `Authorization: Bearer {{$env.API_SECRET_KEY}}`
- `Content-Type: application/json`
- **Body:**
```json
{
"symbol": "SOLUSDT",
"direction": "long",
"timeframe": "5",
"signalStrength": "strong",
"signalPrice": 140.25
}
```
**What it does:**
- Opens position on Drift Protocol
- Starts automatic monitoring
- Returns trade details (entry price, TP/SL levels)
### Format Message Nodes
**Three formatting nodes for different scenarios:**
1. **Format Success Message** - Trade executed successfully
2. **Format Error Message** - Trade execution failed
3. **Format Risk Blocked Message** - Trade blocked by risk limits
**Output example (Success):**
```
🟢 TRADE EXECUTED
📊 Symbol: SOL-PERP
📈 Direction: LONG
💰 Entry Price: $140.2350
💵 Position Size: $500.00
⚡ Leverage: 10x
🎯 Targets:
Stop Loss: $137.90 (-1.5%)
TP1: $140.98 (+0.7%)
TP2: $142.10 (+1.5%)
📊 Slippage: 0.015%
⏰ Time: 10/23/2025, 10:00:00 AM
✅ Position is now being monitored automatically.
Auto-exit at TP/SL levels.
```
### Telegram Node
**Node:** `Telegram - Send Notification`
- **Chat ID:** `{{$env.TELEGRAM_CHAT_ID}}`
- **Text:** `{{$json.message}}`
- **Parse Mode:** Markdown
**What it does:** Sends formatted notification to your Telegram
---
## 🎯 TradingView Alert Setup
### Alert Configuration
1. **In TradingView:** Right-click chart → Add Alert
2. **Condition:** Your indicator/strategy
3. **Alert Name:** "SOL Long Signal" (or similar)
4. **Webhook URL:**
```
https://your-n8n.com/webhook/tradingview-webhook?secret=YOUR_SECRET
```
### Alert Message (JSON)
Use this format in the **Message** field:
```json
{
"symbol": "{{ticker}}",
"action": "{{strategy.order.action}}",
"timeframe": "{{interval}}",
"price": "{{close}}",
"timestamp": "{{timenow}}",
"secret": "YOUR_TRADINGVIEW_SECRET",
"strategy": "5min_scalp",
"strength": "strong"
}
```
**Important fields:**
- `symbol`: Stock/crypto symbol (SOLUSDT, BTCUSD, etc.)
- `action`: "buy"/"sell" or "long"/"short"
- `secret`: Must match `TRADINGVIEW_WEBHOOK_SECRET` in n8n env
### Notification Settings
✅ **Enable:**
- Webhook URL
- Notify on app
- Play sound (optional)
❌ **Disable:**
- Send email (n8n handles notifications)
---
## 🧪 Testing
### Test 1: Webhook Connection
```bash
# Send test webhook from command line
curl -X POST https://your-n8n.com/webhook/tradingview-webhook \
-H "Content-Type: application/json" \
-d '{
"symbol": "SOLUSDT",
"action": "buy",
"timeframe": "5",
"price": "140.25",
"timestamp": "2025-10-23T10:00:00Z",
"secret": "YOUR_SECRET"
}'
```
### Test 2: Check n8n Executions
1. In n8n, click **"Executions"** tab
2. Find your test execution
3. Click to view detailed flow
4. Check each node for errors
### Test 3: Verify API Response
Expected response from `/api/trading/execute`:
```json
{
"success": true,
"trade": {
"id": "trade-1234567890",
"symbol": "SOL-PERP",
"direction": "long",
"entryPrice": 140.235,
"positionSize": 500,
"leverage": 10,
"stopLoss": 137.90,
"takeProfit1": 140.98,
"takeProfit2": 142.10
}
}
```
### Test 4: Telegram Message
You should receive a formatted Telegram message with trade details.
---
## 🔍 Troubleshooting
### Webhook Not Receiving Data
**Problem:** n8n workflow not triggering
**Solutions:**
1. Check webhook is **Active** (toggle at top)
2. Verify webhook URL in TradingView matches n8n
3. Test with curl command (see Testing section)
4. Check n8n logs for errors
### Invalid Secret Error
**Problem:** "Unauthorized Webhook" message
**Solutions:**
1. Verify `secret` in TradingView alert matches `TRADINGVIEW_WEBHOOK_SECRET`
2. Check environment variable is set in n8n
3. Secret is case-sensitive!
### API Authentication Failed
**Problem:** "401 Unauthorized" from trading bot
**Solutions:**
1. Verify `API_SECRET_KEY` in n8n matches v4 `.env`
2. Check `Authorization` header format: `Bearer YOUR_KEY`
3. Regenerate key if needed: `openssl rand -hex 32`
### Trade Not Executing
**Problem:** Risk check passed but no position opened
**Solutions:**
1. Check v4 API logs: `docker-compose logs -f trading-bot`
2. Verify Drift wallet has sufficient collateral
3. Check SOLANA_RPC_URL is working
4. Ensure DRIFT_WALLET_PRIVATE_KEY is correct
5. Test with curl:
```bash
curl -X POST http://localhost:3000/api/trading/execute \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"symbol":"SOLUSDT","direction":"long","timeframe":"5"}'
```
### Telegram Not Sending
**Problem:** No Telegram notifications
**Solutions:**
1. Verify Telegram Bot Token in credentials
2. Check TELEGRAM_CHAT_ID is correct
3. Ensure bot is started (send /start to your bot)
4. Test Telegram node individually in n8n
---
## 📊 Monitoring
### View Executions
In n8n:
1. Click **"Executions"** tab
2. Filter by **"Success"** or **"Error"**
3. Click execution to see detailed flow
### Check Active Positions
Query via API:
```bash
curl -H "Authorization: Bearer YOUR_API_KEY" \
http://localhost:3000/api/trading/positions
```
Or check Drift UI: https://drift.trade
### View Bot Logs
```bash
# Docker logs
docker-compose logs -f trading-bot
# Or if using scripts
cd v4 && ./docker-logs.sh
```
---
## 🔐 Security Best Practices
1. **Use Strong Secrets**
```bash
# Generate secure random secrets
openssl rand -hex 32 # For API keys
openssl rand -hex 16 # For webhook secrets
```
2. **Protect Environment Variables**
- Never commit `.env` files
- Use n8n's environment variable encryption
- Rotate secrets regularly
3. **IP Whitelisting** (optional)
- Restrict webhook access to TradingView IPs
- Use n8n's IP filtering if available
4. **Monitor Failed Attempts**
- Set up alerts for unauthorized webhook attempts
- Review n8n execution logs regularly
---
## 🎓 Advanced Configuration
### Custom Risk Parameters
Modify `Check Risk Limits` node to send additional parameters:
```json
{
"symbol": "SOL-PERP",
"direction": "long",
"customPositionSize": 100,
"customLeverage": 5
}
```
### Multiple Strategies
Clone the workflow for different strategies:
1. Duplicate workflow
2. Change webhook path: `/webhook/tradingview-5min` vs `/webhook/tradingview-15min`
3. Use different risk parameters per timeframe
### Advanced Notifications
Add Discord/Email nodes in parallel with Telegram:
1. Add Discord webhook node
2. Add SMTP email node
3. Connect all to message formatter nodes
---
## 📞 Support
**Workflow Issues:**
- Check n8n documentation: https://docs.n8n.io
- Review execution logs in n8n
**API Issues:**
- See `v4/TESTING.md` for API testing
- Check `v4/DOCKER.md` for container logs
**Trading Issues:**
- See `TRADING_BOT_V4_MANUAL.md` for complete guide
- Check Drift Protocol status
---
## ✅ Checklist
Before going live:
- [ ] Import workflow to n8n
- [ ] Configure all environment variables
- [ ] Add Telegram credentials
- [ ] Copy webhook URL
- [ ] Configure TradingView alert with webhook
- [ ] Test with small position size ($10-50)
- [ ] Verify Telegram notification received
- [ ] Check position opened on Drift
- [ ] Monitor first 5-10 trades closely
- [ ] Gradually increase position size
---
**Your automated trading system is now complete! 🎉**
When TradingView fires an alert → n8n executes the trade → You get a Telegram notification → Bot monitors and auto-exits at TP/SL!

View File

@@ -0,0 +1,395 @@
{
"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"
}
}