From 3e2cf2eec27511db8336feb040e263f93a966b28 Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Mon, 27 Oct 2025 00:23:09 +0100 Subject: [PATCH] feat: add Telegram bot for manual trade commands - Added telegram_command_bot.py with slash commands (/buySOL, /sellBTC, etc) - Docker compose setup with DNS configuration - Sends trades as plain text to n8n webhook (same format as TradingView) - Improved Telegram success message formatting - Only responds to authorized chat ID (579304651) - Commands: /buySOL, /sellSOL, /buyBTC, /sellBTC, /buyETH, /sellETH --- .env | 12 +- .env.telegram-bot | 11 + .github/copilot-instructions.md | 262 +++++++++++++++++ CREATE_NEW_BOT.md | 11 + Dockerfile.telegram-bot | 12 + GET_BOT_TOKEN.sh | 24 ++ Money_Machine.json | 486 +++++++++++++++++++++++++++++++ TELEGRAM_BOT_README.md | 115 ++++++++ complete_telegram_setup.sh | 64 ++++ docker-compose.telegram-bot.yml | 22 ++ quick-trade.html | 105 +++++++ send_trade.sh | 22 ++ setup_telegram_bot.sh | 60 ++++ telegram-listener-simple.json | 161 ++++++++++ telegram-manual-trade-FINAL.json | 155 ++++++++++ telegram-n8n-listener.json | 219 ++++++++++++++ telegram-polling-addon.json | 178 +++++++++++ telegram-to-webhook.py | 80 +++++ telegram-trigger-addon.json | 138 +++++++++ telegram-webhook-FINAL.json | 128 ++++++++ telegram_command_bot.py | 96 ++++++ telegram_trade_bot.py | 79 +++++ trade.sh | 19 ++ webapp-trade.html | 120 ++++++++ 24 files changed, 2573 insertions(+), 6 deletions(-) create mode 100644 .env.telegram-bot create mode 100644 .github/copilot-instructions.md create mode 100644 CREATE_NEW_BOT.md create mode 100644 Dockerfile.telegram-bot create mode 100755 GET_BOT_TOKEN.sh create mode 100644 Money_Machine.json create mode 100644 TELEGRAM_BOT_README.md create mode 100755 complete_telegram_setup.sh create mode 100644 docker-compose.telegram-bot.yml create mode 100644 quick-trade.html create mode 100755 send_trade.sh create mode 100755 setup_telegram_bot.sh create mode 100644 telegram-listener-simple.json create mode 100644 telegram-manual-trade-FINAL.json create mode 100644 telegram-n8n-listener.json create mode 100644 telegram-polling-addon.json create mode 100644 telegram-to-webhook.py create mode 100644 telegram-trigger-addon.json create mode 100644 telegram-webhook-FINAL.json create mode 100644 telegram_command_bot.py create mode 100644 telegram_trade_bot.py create mode 100755 trade.sh create mode 100644 webapp-trade.html diff --git a/.env b/.env index 2b924c0..fe1eb88 100644 --- a/.env +++ b/.env @@ -61,11 +61,11 @@ PYTH_HERMES_URL=https://hermes.pyth.network # Position sizing # Base position size in USD (default: 50 for safe testing) # Example: 50 with 10x leverage = $500 notional position -MAX_POSITION_SIZE_USD=20 +MAX_POSITION_SIZE_USD=80 # Leverage multiplier (1-20, default: 10) # Higher leverage = bigger gains AND bigger losses -LEVERAGE=5 +LEVERAGE=10 # Risk parameters (as percentages) # Stop Loss: Close 100% of position when price drops this much @@ -93,19 +93,19 @@ HARD_STOP_PERCENT=-2.5 # Take Profit 1: Close 50% of position at this profit level # Example: +0.7% on 10x = +7% account gain -TAKE_PROFIT_1_PERCENT=0.7 +TAKE_PROFIT_1_PERCENT=0.4 # Take Profit 1 Size: What % of position to close at TP1 # Example: 50 = close 50% of position -TAKE_PROFIT_1_SIZE_PERCENT=50 +TAKE_PROFIT_1_SIZE_PERCENT=75 # Take Profit 2: Close remaining 50% at this profit level # Example: +1.5% on 10x = +15% account gain -TAKE_PROFIT_2_PERCENT=1.5 +TAKE_PROFIT_2_PERCENT=0.8 # Take Profit 2 Size: What % of remaining position to close at TP2 # Example: 100 = close all remaining position -TAKE_PROFIT_2_SIZE_PERCENT=50 +TAKE_PROFIT_2_SIZE_PERCENT=100 # Emergency Stop: Hard stop if this level is breached # Example: -2.0% on 10x = -20% account loss (rare but protects from flash crashes) diff --git a/.env.telegram-bot b/.env.telegram-bot new file mode 100644 index 0000000..e5b9247 --- /dev/null +++ b/.env.telegram-bot @@ -0,0 +1,11 @@ +# Telegram Trade Bot Configuration + +# Get your bot token from @BotFather on Telegram +TELEGRAM_BOT_TOKEN=8240234365:AAEm6hg_XOm54x8ctnwpNYreFKRAEvWU3uY + +# Your n8n webhook URL (after importing telegram-manual-trade-FINAL.json, activate it and replace this URL) +# Your n8n webhook URL (public HTTPS) +N8N_WEBHOOK_URL=https://flow.egonetix.de/webhook/3371ad7c-0866-4161-90a4-f251de4aceb8 + +# Your Telegram chat ID (already set to 579304651) +TELEGRAM_CHAT_ID=579304651 diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..0d91ca8 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,262 @@ +# AI Agent Instructions for Trading Bot v4 + +## Architecture Overview + +**Type:** Autonomous cryptocurrency trading bot with Next.js 15 frontend + Solana/Drift Protocol backend + +**Data Flow:** TradingView → n8n webhook → Next.js API → Drift Protocol (Solana DEX) → Real-time monitoring → Auto-exit + +**Key Design Principle:** Dual-layer redundancy - every trade has both on-chain orders (Drift) AND software monitoring (Position Manager) as backup. + +## Critical Components + +### 1. Position Manager (`lib/trading/position-manager.ts`) +**Purpose:** Software-based monitoring loop that checks prices every 2 seconds and closes positions via market orders + +**Singleton pattern:** Always use `getPositionManager()` - never instantiate directly +```typescript +const positionManager = getPositionManager() +await positionManager.addTrade(activeTrade) +``` + +**Key behaviors:** +- Tracks `ActiveTrade` objects in a Map +- Dynamic SL adjustments: Moves to breakeven at +0.5%, locks profit at +1.2% +- Closes positions via `closePosition()` market orders when targets hit +- Acts as backup if on-chain orders don't fill + +### 2. Drift Client (`lib/drift/client.ts`) +**Purpose:** Solana/Drift Protocol SDK wrapper for order execution + +**Singleton pattern:** Use `initializeDriftService()` and `getDriftService()` - maintains single connection +```typescript +const driftService = await initializeDriftService() +const health = await driftService.getAccountHealth() +``` + +**Wallet handling:** Supports both JSON array `[91,24,...]` and base58 string formats from Phantom wallet + +### 3. Order Placement (`lib/drift/orders.ts`) +**Critical function:** `placeExitOrders()` - places TP/SL orders on-chain + +**Dual Stop System** (USE_DUAL_STOPS=true): +```typescript +// Soft stop: TRIGGER_LIMIT at -1.5% (avoids wicks) +// Hard stop: TRIGGER_MARKET at -2.5% (guarantees exit) +``` + +**Order types:** +- Entry: MARKET (immediate execution) +- TP1/TP2: LIMIT reduce-only orders +- Soft SL: TRIGGER_LIMIT reduce-only +- Hard SL: TRIGGER_MARKET reduce-only + +### 4. Database (`lib/database/trades.ts` + `prisma/schema.prisma`) +**Purpose:** PostgreSQL via Prisma ORM for trade history and analytics + +**Models:** Trade, PriceUpdate, SystemEvent, DailyStats + +**Singleton pattern:** Use `getPrismaClient()` - never instantiate PrismaClient directly + +**Key functions:** +- `createTrade()` - Save trade after execution (includes dual stop TX signatures) +- `updateTradeExit()` - Record exit with P&L +- `addPriceUpdate()` - Track price movements (called by Position Manager) +- `getTradeStats()` - Win rate, profit factor, avg win/loss + +## Configuration System + +**Three-layer merge:** +1. `DEFAULT_TRADING_CONFIG` (config/trading.ts) +2. Environment variables (.env) via `getConfigFromEnv()` +3. Runtime overrides via `getMergedConfig(overrides)` + +**Always use:** `getMergedConfig()` to get final config - never read env vars directly in business logic + +**Symbol normalization:** TradingView sends "SOLUSDT" → must convert to "SOL-PERP" for Drift +```typescript +const driftSymbol = normalizeTradingViewSymbol(body.symbol) +``` + +## API Endpoints Architecture + +**Authentication:** All `/api/trading/*` endpoints (except `/test`) require `Authorization: Bearer API_SECRET_KEY` + +**Pattern:** Each endpoint follows same flow: +1. Auth check +2. Get config via `getMergedConfig()` +3. Initialize Drift service +4. Check account health +5. Execute operation +6. Save to database +7. Add to Position Manager if applicable + +**Key endpoints:** +- `/api/trading/execute` - Main entry point from n8n (production) +- `/api/trading/test` - Test trades from settings UI (no auth required) +- `/api/trading/close` - Manual position closing +- `/api/trading/positions` - Query open positions +- `/api/settings` - Get/update config (writes to .env file) + +## Critical Workflows + +### Execute Trade (Production) +``` +n8n webhook → /api/trading/execute + ↓ normalize symbol (SOLUSDT → SOL-PERP) + ↓ getMergedConfig() + ↓ openPosition() [MARKET order] + ↓ calculate dual stop prices if enabled + ↓ placeExitOrders() [on-chain TP/SL orders] + ↓ createTrade() [save to database] + ↓ positionManager.addTrade() [start monitoring] +``` + +### Position Monitoring Loop +``` +Position Manager every 2s: + ↓ getPythPriceMonitor().getLatestPrice() + ↓ Calculate current P&L + ↓ Check TP1 hit → closePosition(75%) + ↓ Check TP2 hit → closePosition(100%) + ↓ Check SL hit → closePosition(100%) + ↓ Check dynamic adjustments (breakeven, profit lock) + ↓ addPriceUpdate() [save to database] +``` + +### Settings Update +``` +Web UI → /api/settings POST + ↓ Validate new settings + ↓ Write to .env file using string replacement + ↓ Return success + ↓ User clicks "Restart Bot" → /api/restart + ↓ Creates /tmp/trading-bot-restart.flag + ↓ watch-restart.sh detects flag + ↓ Executes: docker restart trading-bot-v4 +``` + +## Docker Context + +**Multi-stage build:** deps → builder → runner (Node 20 Alpine) + +**Critical Dockerfile steps:** +1. Install deps with `npm install --production` +2. Copy source and `npx prisma generate` (MUST happen before build) +3. `npm run build` (Next.js standalone output) +4. Runner stage copies standalone + static + node_modules + Prisma client + +**Container networking:** +- External: `trading-bot-v4` on port 3001 +- Internal: Next.js on port 3000 +- Database: `trading-bot-postgres` on 172.28.0.0/16 network + +**DATABASE_URL caveat:** Use `trading-bot-postgres` (container name) in .env for runtime, but `localhost:5432` for Prisma CLI migrations from host + +## Project-Specific Patterns + +### 1. Singleton Services +Never create multiple instances - always use getter functions: +```typescript +const driftService = await initializeDriftService() // NOT: new DriftService() +const positionManager = getPositionManager() // NOT: new PositionManager() +const prisma = getPrismaClient() // NOT: new PrismaClient() +``` + +### 2. Price Calculations +Direction matters for long vs short: +```typescript +function calculatePrice(entry: number, percent: number, direction: 'long' | 'short') { + if (direction === 'long') { + return entry * (1 + percent / 100) // Long: +1% = higher price + } else { + return entry * (1 - percent / 100) // Short: +1% = lower price + } +} +``` + +### 3. Error Handling +Database failures should not fail trades - always wrap in try/catch: +```typescript +try { + await createTrade(params) + console.log('💾 Trade saved to database') +} catch (dbError) { + console.error('❌ Failed to save trade:', dbError) + // Don't fail the trade if database save fails +} +``` + +### 4. Reduce-Only Orders +All exit orders MUST be reduce-only (can only close, not open positions): +```typescript +const orderParams = { + reduceOnly: true, // CRITICAL for TP/SL orders + // ... other params +} +``` + +## Testing Commands + +```bash +# Local development +npm run dev + +# Build production +npm run build && npm start + +# Docker build and restart +docker compose build trading-bot +docker compose up -d --force-recreate trading-bot +docker logs -f trading-bot-v4 + +# Database operations +npx prisma generate # Generate client +DATABASE_URL="postgresql://...@localhost:5432/..." npx prisma migrate dev +docker exec trading-bot-postgres psql -U postgres -d trading_bot_v4 -c "\dt" + +# Test trade from UI +# Go to http://localhost:3001/settings +# Click "Test LONG" or "Test SHORT" +``` + +## Common Pitfalls + +1. **Prisma not generated in Docker:** Must run `npx prisma generate` in Dockerfile BEFORE `npm run build` + +2. **Wrong DATABASE_URL:** Container runtime needs `trading-bot-postgres`, Prisma CLI from host needs `localhost:5432` + +3. **Symbol format mismatch:** Always normalize with `normalizeTradingViewSymbol()` before calling Drift + +4. **Missing reduce-only flag:** Exit orders without `reduceOnly: true` can accidentally open new positions + +5. **Singleton violations:** Creating multiple DriftClient or Position Manager instances causes connection/state issues + +6. **Type errors with Prisma:** The Trade type from Prisma is only available AFTER `npx prisma generate` - use explicit types or `// @ts-ignore` carefully + +## File Conventions + +- **API routes:** `app/api/[feature]/[action]/route.ts` (Next.js 15 App Router) +- **Services:** `lib/[service]/[module].ts` (drift, pyth, trading, database) +- **Config:** Single source in `config/trading.ts` with env merging +- **Types:** Define interfaces in same file as implementation (not separate types directory) +- **Console logs:** Use emojis for visual scanning: 🎯 🚀 ✅ ❌ 💰 📊 🛡️ + +## When Making Changes + +1. **Adding new config:** Update DEFAULT_TRADING_CONFIG + getConfigFromEnv() + .env file +2. **Adding database fields:** Update prisma/schema.prisma → migrate → regenerate client → rebuild Docker +3. **Changing order logic:** Test with DRY_RUN=true first, use small position sizes ($10) +4. **API endpoint changes:** Update both endpoint + corresponding n8n workflow JSON +5. **Docker changes:** Rebuild with `docker compose build trading-bot` then restart container + +## Integration Points + +- **n8n:** Expects exact response format from `/api/trading/execute` (see n8n-complete-workflow.json) +- **Drift Protocol:** Uses SDK v2.75.0 - check docs at docs.drift.trade for API changes +- **Pyth Network:** WebSocket + HTTP fallback for price feeds (handles reconnection) +- **PostgreSQL:** Version 16-alpine, must be running before bot starts + +--- + +**Key Mental Model:** Think of this as two parallel systems (on-chain orders + software monitoring) working together. The Position Manager is the "backup brain" that constantly watches and acts if on-chain orders fail. Both write to the same database for complete trade history. diff --git a/CREATE_NEW_BOT.md b/CREATE_NEW_BOT.md new file mode 100644 index 0000000..d861abe --- /dev/null +++ b/CREATE_NEW_BOT.md @@ -0,0 +1,11 @@ +# Steps to Create a NEW Telegram Bot for Manual Trades + +1. Open Telegram on your phone +2. Search for @BotFather +3. Send: /newbot +4. Name it: "Manual Trader Bot" (or anything you want) +5. Username: something like "my_manual_trader_bot" (must end in _bot) +6. Copy the TOKEN you get +7. Send that token to me and I'll configure everything + +This will be a SEPARATE bot from your n8n bot, so no conflicts! diff --git a/Dockerfile.telegram-bot b/Dockerfile.telegram-bot new file mode 100644 index 0000000..c2909e7 --- /dev/null +++ b/Dockerfile.telegram-bot @@ -0,0 +1,12 @@ +FROM python:3.11-slim + +WORKDIR /app + +# Install dependencies +RUN pip install --no-cache-dir python-telegram-bot==20.7 requests + +# Copy bot script +COPY telegram_command_bot.py . + +# Run bot +CMD ["python3", "telegram_command_bot.py"] diff --git a/GET_BOT_TOKEN.sh b/GET_BOT_TOKEN.sh new file mode 100755 index 0000000..dea2796 --- /dev/null +++ b/GET_BOT_TOKEN.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# One-time setup to get your Telegram Bot Token +# Run this and follow the instructions + +echo "🤖 Telegram Bot Setup Instructions" +echo "====================================" +echo "" +echo "1. Open Telegram on your phone" +echo "2. Search for '@BotFather'" +echo "3. Start a chat with BotFather" +echo "4. Send this message: /newbot" +echo "5. BotFather will ask for a name - choose anything like 'My Trading Bot'" +echo "6. BotFather will ask for a username - must end in 'bot', like 'mytrading_bot'" +echo "7. BotFather will give you a TOKEN that looks like:" +echo " 123456789:ABCdefGHIjklMNOpqrsTUVwxyz" +echo "" +echo "8. Copy that token and run:" +echo " nano .env.telegram-bot" +echo "" +echo "9. Replace 'your_bot_token_here' with your actual token" +echo "" +echo "10. Save (Ctrl+O, Enter, Ctrl+X)" +echo "" +echo "Then run: ./setup_telegram_bot.sh" diff --git a/Money_Machine.json b/Money_Machine.json new file mode 100644 index 0000000..a1b2435 --- /dev/null +++ b/Money_Machine.json @@ -0,0 +1,486 @@ +{ + "name": "Money Machine", + "nodes": [ + { + "parameters": { + "httpMethod": "POST", + "path": "3371ad7c-0866-4161-90a4-f251de4aceb8", + "options": {} + }, + "id": "35b54214-9761-49dc-97b6-df39543f0a7b", + "name": "Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 1, + "position": [ + -840, + 660 + ], + "webhookId": "3371ad7c-0866-4161-90a4-f251de4aceb8" + }, + { + "parameters": { + "fields": { + "values": [ + { + "name": "rawMessage", + "stringValue": "={{ $json.body }}" + }, + { + "name": "symbol", + "stringValue": "={{ ($json.body || '').toString().match(/\\bSOL\\b/i) ? 'SOL-PERP' : (($json.body || '').toString().match(/\\bBTC\\b/i) ? 'BTC-PERP' : (($json.body || '').toString().match(/\\bETH\\b/i) ? 'ETH-PERP' : 'SOL-PERP')) }}" + }, + { + "name": "direction", + "stringValue": "={{ ($json.body || '').toString().match(/\\b(sell|short)\\b/i) ? 'short' : 'long' }}" + }, + { + "name": "timeframe", + "stringValue": "5" + } + ] + }, + "options": {} + }, + "id": "99336995-2326-4575-9970-26afcf957132", + "name": "Parse Signal", + "type": "n8n-nodes-base.set", + "typeVersion": 3.2, + "position": [ + -660, + 660 + ] + }, + { + "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": "d42e7897-eadd-4202-8565-ac60759b46e1", + "name": "Check Risk", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4, + "position": [ + -340, + 660 + ], + "credentials": { + "httpHeaderAuth": { + "id": "MATuNdkZclq5ISbr", + "name": "Header Auth account" + } + } + }, + { + "parameters": { + "conditions": { + "boolean": [ + { + "value1": "={{ $json.allowed }}", + "value2": true + } + ] + } + }, + "id": "a60bfecb-d2f4-4165-a609-e6ed437aa2aa", + "name": "Risk Passed?", + "type": "n8n-nodes-base.if", + "typeVersion": 1, + "position": [ + -140, + 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').item.json.symbol }}\",\n \"direction\": \"{{ $('Parse Signal').item.json.direction }}\",\n \"timeframe\": \"{{ $('Parse Signal').item.json.timeframe }}\",\n \"signalStrength\": \"strong\"\n}", + "options": { + "timeout": 30000 + } + }, + "id": "95c46846-4b6a-4f9e-ad93-be223b73a618", + "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": "18342642-e76f-484f-b532-d29846536a9c", + "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').item.json.symbol }}\\n{{ $('Parse Signal').item.json.direction === 'long' ? '📈' : '📉' }} Direction: {{ $('Parse Signal').item.json.direction.toUpperCase() }}\\n⏰ Time: {{ $now.toFormat('HH:mm:ss') }}\\n\\n✅ Position is being monitored" + } + ] + }, + "options": {} + }, + "id": "9da40e3d-b855-4c65-a032-c6fcf88245d4", + "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.toFormat('HH:mm') }}" + } + ] + }, + "options": {} + }, + "id": "500751c7-21bb-4351-8a6a-d43a1bfb9eaa", + "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').item.json.rawMessage }}\\n\\n🛑 Risk limits exceeded\\n⏰ {{ $now.toFormat('HH:mm') }}" + } + ] + }, + "options": {} + }, + "id": "dec6cbc4-7550-40d3-9195-c4cc4f787b9b", + "name": "Format Risk", + "type": "n8n-nodes-base.set", + "typeVersion": 3.2, + "position": [ + 60, + 760 + ] + }, + { + "parameters": { + "chatId": "579304651", + "text": "={{ $json.message }}", + "additionalFields": { + "appendAttribution": false + } + }, + "id": "6267b604-d39b-4cb7-98a5-2342cdced33b", + "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": "🟢 TRADE OPENED\n\n📊 Symbol: {{ $('Parse Signal').item.json.symbol }}\n{{ $('Parse Signal').item.json.direction === 'long' ? '📈' : '📉' }} Direction: {{ $('Parse Signal').item.json.direction.toUpperCase() }}\n⏰ Time: {{ $now.toFormat('HH:mm:ss') }}\n\n✅ Position is being monitored", + "additionalFields": { + "appendAttribution": false + } + }, + "id": "88224fac-ef7a-41ec-b68a-e4bc1a5e3f31", + "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": "4eccaca4-a5e7-407f-aab9-663a98a8323b", + "name": "Telegram Risk", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1.1, + "position": [ + 260, + 760 + ], + "credentials": { + "telegramApi": { + "id": "Csk5cg4HtaSqP5jJ", + "name": "Telegram account" + } + } + }, + { + "parameters": { + "chatId": "579304651", + "text": "={{ $json.signal.startsWith(\"Buy\") ? \"🟢 \" + $json.signal : \"🔴 \" + $json.signal }}\n", + "additionalFields": { + "appendAttribution": false + } + }, + "id": "5a8eda4d-8945-4144-8672-022c9ee68bf6", + "name": "Telegram", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1.1, + "position": [ + -340, + 840 + ], + "credentials": { + "telegramApi": { + "id": "Csk5cg4HtaSqP5jJ", + "name": "Telegram account" + } + } + }, + { + "parameters": { + "fields": { + "values": [ + { + "name": "signal", + "stringValue": "={{ $json.body.split('|')[0].trim() }}" + } + ] + }, + "options": {} + }, + "id": "cce16424-fbb1-4191-b719-79ccfd59ec12", + "name": "Edit Fields", + "type": "n8n-nodes-base.set", + "typeVersion": 3.2, + "position": [ + -660, + 840 + ] + } + ], + "pinData": {}, + "connections": { + "Webhook": { + "main": [ + [ + { + "node": "Parse Signal", + "type": "main", + "index": 0 + } + ] + ] + }, + "Parse Signal": { + "main": [ + [ + { + "node": "Check Risk", + "type": "main", + "index": 0 + }, + { + "node": "Telegram", + "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 + } + ] + ] + }, + "Edit Fields": { + "main": [ + [] + ] + } + }, + "active": false, + "settings": { + "executionOrder": "v1" + }, + "versionId": "2cc10693-953a-4b97-8c86-750b3063096b", + "id": "xTCaxlyI02bQLxun", + "meta": { + "instanceId": "e766d4f0b5def8ee8cb8561cd9d2b9ba7733e1907990b6987bca40175f82c379" + }, + "tags": [] +} \ No newline at end of file diff --git a/TELEGRAM_BOT_README.md b/TELEGRAM_BOT_README.md new file mode 100644 index 0000000..63d2f9b --- /dev/null +++ b/TELEGRAM_BOT_README.md @@ -0,0 +1,115 @@ +# Telegram Trading Bot - Quick Reference + +## 🚀 Quick Setup (3 steps) + +### 1. Import n8n workflow +- Open: http://10.0.0.48:8098 +- Import: `telegram-manual-trade-FINAL.json` +- Connect last node to "Check Risk" in Money Machine +- Activate workflow + +### 2. Get Telegram Bot Token +Run on your phone: +``` +Open Telegram → @BotFather → /newbot → follow instructions +``` + +You'll get a token like: `123456789:ABCdefGHIjklMNOpqrsTUVwxyz` + +### 3. Run setup +```bash +./complete_telegram_setup.sh +``` +Paste your bot token when asked. + +--- + +## 📱 Using it on your phone + +Just send messages to your Telegram chat: +``` +buy sol +sell btc +buy eth +sell sol +``` + +The bot will: +1. ✅ Parse your message +2. ✅ Forward to n8n webhook +3. ✅ n8n sends to your trading bot +4. ✅ Trade executes with risk checks +5. ✅ You get confirmation in Telegram + +--- + +## 🔧 Management + +**View logs:** +```bash +docker logs -f telegram-trade-bot +``` + +**Restart bot:** +```bash +docker restart telegram-trade-bot +``` + +**Stop bot:** +```bash +docker-compose -f docker-compose.telegram-bot.yml down +``` + +**Start bot:** +```bash +docker-compose -f docker-compose.telegram-bot.yml --env-file .env.telegram-bot up -d +``` + +--- + +## 📋 Configuration Files + +- `.env.telegram-bot` - Bot token and webhook URL +- `docker-compose.telegram-bot.yml` - Docker configuration +- `telegram_trade_bot.py` - Bot source code + +--- + +## 🐛 Troubleshooting + +**Bot not responding?** +```bash +docker logs telegram-trade-bot +``` + +**Check if bot is running:** +```bash +docker ps | grep telegram +``` + +**Test webhook manually:** +```bash +curl -X POST http://10.0.0.48:8098/webhook/manual-trade \ + -H "Content-Type: application/json" \ + -d '{"text": "buy sol"}' +``` + +**Check n8n workflow:** +- Is it activated? +- Is the webhook URL correct? +- Is it connected to Check Risk node? + +--- + +## ✅ Supported Commands + +From your phone, send any of these: +- `buy sol` / `buy btc` / `buy eth` +- `sell sol` / `sell btc` / `sell eth` +- `long sol` / `short btc` (same as buy/sell) + +The bot extracts: +- **Symbol**: SOL, BTC, or ETH (defaults to SOL) +- **Direction**: sell/short = short position, anything else = long position + +Commands are case-insensitive: `BUY SOL`, `Buy Sol`, `buy sol` all work! diff --git a/complete_telegram_setup.sh b/complete_telegram_setup.sh new file mode 100755 index 0000000..ec0705b --- /dev/null +++ b/complete_telegram_setup.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# Complete Telegram Trading Bot Setup + +echo "🤖 Telegram Trading Bot - Complete Setup" +echo "==========================================" +echo "" + +# Step 1: Check if workflow is imported +echo "📋 Step 1: n8n Workflow" +echo "-----------------------" +echo "1. Open n8n: http://10.0.0.48:8098" +echo "2. Import telegram-manual-trade-FINAL.json" +echo "3. Connect the last node '➡️ Connect to Check Risk Node' to your Money Machine's 'Check Risk' node" +echo "4. Activate the workflow" +echo "" +read -p "Done? (y/n) " -n 1 -r +echo "" +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "❌ Complete step 1 first" + exit 1 +fi + +# Step 2: Get bot token +echo "" +echo "🤖 Step 2: Telegram Bot Token" +echo "------------------------------" +echo "Run: ./GET_BOT_TOKEN.sh for instructions" +echo "" +echo "Or if you already have a bot token:" +read -p "Paste your bot token here: " BOT_TOKEN + +if [ -z "$BOT_TOKEN" ]; then + echo "❌ Bot token required" + exit 1 +fi + +# Update .env file +sed -i "s|TELEGRAM_BOT_TOKEN=.*|TELEGRAM_BOT_TOKEN=$BOT_TOKEN|" .env.telegram-bot + +echo "✅ Bot token saved to .env.telegram-bot" + +# Step 3: Build and start +echo "" +echo "🚀 Step 3: Starting Telegram Bot Container" +echo "-------------------------------------------" + +docker-compose -f docker-compose.telegram-bot.yml --env-file .env.telegram-bot up -d --build + +if [ $? -eq 0 ]; then + echo "" + echo "✅ SUCCESS! Telegram bot is running!" + echo "" + echo "📱 Test it now:" + echo " Open Telegram and send to your chat (579304651):" + echo " • buy sol" + echo " • sell btc" + echo " • buy eth" + echo "" + echo "📊 View logs: docker logs -f telegram-trade-bot" + echo "" +else + echo "❌ Failed to start container" + echo "Check logs: docker logs telegram-trade-bot" +fi diff --git a/docker-compose.telegram-bot.yml b/docker-compose.telegram-bot.yml new file mode 100644 index 0000000..575e5e3 --- /dev/null +++ b/docker-compose.telegram-bot.yml @@ -0,0 +1,22 @@ +version: '3.3' + +services: + telegram-trade-bot: + build: + context: . + dockerfile: Dockerfile.telegram-bot + container_name: telegram-trade-bot + restart: unless-stopped + dns: + - 8.8.8.8 + - 8.8.4.4 + environment: + - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} + - N8N_WEBHOOK_URL=${N8N_WEBHOOK_URL} + - TELEGRAM_CHAT_ID=579304651 + networks: + - traderv4_trading-net + +networks: + traderv4_trading-net: + external: true diff --git a/quick-trade.html b/quick-trade.html new file mode 100644 index 0000000..38598cc --- /dev/null +++ b/quick-trade.html @@ -0,0 +1,105 @@ + + + + + Quick Trade + + + +

📱 Quick Trade

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + + diff --git a/send_trade.sh b/send_trade.sh new file mode 100755 index 0000000..1a7c51f --- /dev/null +++ b/send_trade.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# Quick script to trigger manual trades via n8n webhook +# Usage: ./send_trade.sh "buy SOL" +# ./send_trade.sh "sell BTC" + +WEBHOOK_URL="https://YOUR_N8N_URL/webhook/manual-trade" + +if [ -z "$1" ]; then + echo "Usage: $0 \"buy SOL\" or \"sell BTC\"" + exit 1 +fi + +COMMAND="$1" + +echo "📤 Sending command: $COMMAND" + +curl -X POST "$WEBHOOK_URL" \ + -H "Content-Type: application/json" \ + -d "{\"text\": \"$COMMAND\"}" + +echo "" +echo "✅ Command sent!" diff --git a/setup_telegram_bot.sh b/setup_telegram_bot.sh new file mode 100755 index 0000000..e5bfce2 --- /dev/null +++ b/setup_telegram_bot.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# Setup Telegram Trade Bot + +echo "🤖 Telegram Trade Bot Setup" +echo "============================" +echo "" + +# Check if .env.telegram-bot exists +if [ ! -f .env.telegram-bot ]; then + echo "❌ .env.telegram-bot not found!" + echo "Create it with your bot token and webhook URL" + exit 1 +fi + +# Source the env file +source .env.telegram-bot + +# Check required vars +if [ "$TELEGRAM_BOT_TOKEN" = "your_bot_token_here" ]; then + echo "❌ Please set TELEGRAM_BOT_TOKEN in .env.telegram-bot" + echo "" + echo "Steps:" + echo "1. Message @BotFather on Telegram" + echo "2. Send /newbot" + echo "3. Follow instructions to get your bot token" + echo "4. Put the token in .env.telegram-bot" + exit 1 +fi + +if [[ "$N8N_WEBHOOK_URL" == *"your-n8n-url"* ]]; then + echo "❌ Please set N8N_WEBHOOK_URL in .env.telegram-bot" + echo "" + echo "Steps:" + echo "1. Import telegram-manual-trade-FINAL.json into n8n" + echo "2. Activate the workflow" + echo "3. Copy the webhook URL from the first node" + echo "4. Put the URL in .env.telegram-bot" + exit 1 +fi + +echo "✅ Configuration looks good!" +echo "" +echo "📱 Chat ID: $TELEGRAM_CHAT_ID" +echo "🔗 Webhook: $N8N_WEBHOOK_URL" +echo "" +echo "Building and starting bot..." +echo "" + +# Build and start +docker-compose -f docker-compose.telegram-bot.yml --env-file .env.telegram-bot up -d --build + +echo "" +echo "✅ Bot started!" +echo "" +echo "Test it by sending to your Telegram chat:" +echo " buy sol" +echo " sell btc" +echo " buy eth" +echo "" +echo "View logs: docker logs -f telegram-trade-bot" diff --git a/telegram-listener-simple.json b/telegram-listener-simple.json new file mode 100644 index 0000000..8adcdfa --- /dev/null +++ b/telegram-listener-simple.json @@ -0,0 +1,161 @@ +{ + "name": "ADD THIS TO MONEY MACHINE - Manual Trade Listener", + "nodes": [ + { + "parameters": { + "rule": { + "interval": [ + { + "triggerAtMinute": 10 + } + ] + } + }, + "id": "schedule-check-telegram", + "name": "Check Every 10 Seconds", + "type": "n8n-nodes-base.scheduleTrigger", + "typeVersion": 1.1, + "position": [ + -1040, + 280 + ] + }, + { + "parameters": { + "resource": "message", + "operation": "getMany", + "chatId": "579304651", + "returnAll": false, + "limit": 5 + }, + "id": "get-recent-messages", + "name": "Get Recent Messages", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1.1, + "position": [ + -860, + 280 + ], + "credentials": { + "telegramApi": { + "id": "Csk5cg4HtaSqP5jJ", + "name": "Telegram account" + } + } + }, + { + "parameters": { + "conditions": { + "string": [ + { + "value1": "={{ $json.text }}", + "operation": "regex", + "value2": "^(buy|sell|long|short)\\s+(SOL|BTC|ETH)" + } + ] + } + }, + "id": "filter-commands", + "name": "Is Trade Command?", + "type": "n8n-nodes-base.if", + "typeVersion": 1, + "position": [ + -680, + 280 + ] + }, + { + "parameters": { + "fields": { + "values": [ + { + "name": "symbol", + "stringValue": "={{ $json.text.match(/\\b(SOL|BTC|ETH)\\b/i)[0].toUpperCase() }}-PERP" + }, + { + "name": "direction", + "stringValue": "={{ $json.text.match(/^(sell|short)\\b/i) ? 'short' : 'long' }}" + }, + { + "name": "timeframe", + "stringValue": "5" + } + ] + } + }, + "id": "parse-trade", + "name": "Parse Trade", + "type": "n8n-nodes-base.set", + "typeVersion": 3.2, + "position": [ + -500, + 280 + ] + }, + { + "parameters": { + "mode": "raw", + "jsonOutput": "={{ $json }}" + }, + "id": "output-to-check-risk", + "name": "➡️ Merge with Check Risk", + "type": "n8n-nodes-base.set", + "typeVersion": 3.3, + "position": [ + -320, + 280 + ], + "notes": "Connect this to the SAME point where your TradingView webhook connects (before Check Risk node)" + } + ], + "connections": { + "Check Every 10 Seconds": { + "main": [ + [ + { + "node": "Get Recent Messages", + "type": "main", + "index": 0 + } + ] + ] + }, + "Get Recent Messages": { + "main": [ + [ + { + "node": "Is Trade Command?", + "type": "main", + "index": 0 + } + ] + ] + }, + "Is Trade Command?": { + "main": [ + [ + { + "node": "Parse Trade", + "type": "main", + "index": 0 + } + ] + ] + }, + "Parse Trade": { + "main": [ + [ + { + "node": "➡️ Merge with Check Risk", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": false, + "settings": { + "executionOrder": "v1" + } +} diff --git a/telegram-manual-trade-FINAL.json b/telegram-manual-trade-FINAL.json new file mode 100644 index 0000000..254c4eb --- /dev/null +++ b/telegram-manual-trade-FINAL.json @@ -0,0 +1,155 @@ +{ + "name": "Manual Trade Command - ADD TO MONEY MACHINE", + "nodes": [ + { + "parameters": { + "httpMethod": "POST", + "path": "manual-trade", + "responseMode": "responseNode", + "options": {} + }, + "id": "webhook-manual-trade", + "name": "Manual Trade Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 1.1, + "position": [ + -840, + 280 + ], + "webhookId": "manual-trade-webhook" + }, + { + "parameters": { + "fields": { + "values": [ + { + "name": "command", + "stringValue": "={{ $json.body.text || $json.body.message || $json.body }}" + }, + { + "name": "symbol", + "stringValue": "={{ ($json.body.text || $json.body.message || $json.body).toString().match(/\\b(SOL|BTC|ETH)\\b/i) ? ($json.body.text || $json.body.message || $json.body).toString().match(/\\b(SOL|BTC|ETH)\\b/i)[0].toUpperCase() + '-PERP' : 'SOL-PERP' }}" + }, + { + "name": "direction", + "stringValue": "={{ ($json.body.text || $json.body.message || $json.body).toString().match(/\\b(sell|short)\\b/i) ? 'short' : 'long' }}" + }, + { + "name": "timeframe", + "stringValue": "5" + }, + { + "name": "source", + "stringValue": "manual" + } + ] + }, + "options": {} + }, + "id": "parse-manual-command", + "name": "Parse Command", + "type": "n8n-nodes-base.set", + "typeVersion": 3.2, + "position": [ + -660, + 280 + ] + }, + { + "parameters": { + "chatId": "579304651", + "text": "🤖 Manual Trade Command\n\n📊 {{ $json.symbol }}\n{{ $json.direction === 'long' ? '📈' : '📉' }} {{ $json.direction.toUpperCase() }}\n⏰ {{ $now.toFormat('HH:mm:ss') }}\n\n✅ Sending to bot...", + "additionalFields": { + "appendAttribution": false + } + }, + "id": "telegram-confirm", + "name": "Send Telegram Confirmation", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1.1, + "position": [ + -480, + 280 + ], + "credentials": { + "telegramApi": { + "id": "Csk5cg4HtaSqP5jJ", + "name": "Telegram account" + } + } + }, + { + "parameters": { + "respondWith": "json", + "responseBody": "={{ { \"status\": \"received\", \"symbol\": $json.symbol, \"direction\": $json.direction } }}" + }, + "id": "webhook-response", + "name": "Webhook Response", + "type": "n8n-nodes-base.respondToWebhook", + "typeVersion": 1, + "position": [ + -480, + 380 + ] + }, + { + "parameters": { + "mode": "raw", + "jsonOutput": "={{ { \"symbol\": $json.symbol, \"direction\": $json.direction, \"timeframe\": $json.timeframe } }}" + }, + "id": "output-to-check-risk", + "name": "➡️ Connect to Check Risk Node", + "type": "n8n-nodes-base.set", + "typeVersion": 3.3, + "position": [ + -300, + 280 + ], + "notes": "Connect this node to your Money Machine's Check Risk node (same place as TradingView webhook)" + } + ], + "connections": { + "Manual Trade Webhook": { + "main": [ + [ + { + "node": "Parse Command", + "type": "main", + "index": 0 + } + ] + ] + }, + "Parse Command": { + "main": [ + [ + { + "node": "Send Telegram Confirmation", + "type": "main", + "index": 0 + }, + { + "node": "Webhook Response", + "type": "main", + "index": 0 + } + ] + ] + }, + "Send Telegram Confirmation": { + "main": [ + [ + { + "node": "➡️ Connect to Check Risk Node", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": false, + "settings": { + "executionOrder": "v1" + } +} diff --git a/telegram-n8n-listener.json b/telegram-n8n-listener.json new file mode 100644 index 0000000..e1d00d9 --- /dev/null +++ b/telegram-n8n-listener.json @@ -0,0 +1,219 @@ +{ + "name": "Telegram Manual Trade - ADD TO MONEY MACHINE", + "nodes": [ + { + "parameters": { + "httpMethod": "POST", + "path": "telegram-trade", + "responseMode": "responseNode", + "options": {} + }, + "id": "webhook", + "name": "Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 1.1, + "position": [200, 300], + "webhookId": "telegram-trade-webhook" + }, + { + "parameters": { + "conditions": { + "string": [ + { + "value1": "={{ $json.body.message || $json.body.text || '' }}", + "operation": "regex", + "value2": "^(buy|sell|long|short)\\s+(sol|btc|eth)" + } + ] + } + }, + "id": "filter-trades", + "name": "Is Trade Command?", + "type": "n8n-nodes-base.if", + "typeVersion": 1, + "position": [400, 300] + }, + { + "parameters": { + "values": { + "string": [ + { + "name": "symbol", + "value": "={{ ($json.body.message || $json.body.text).match(/\\b(SOL|BTC|ETH)\\b/i)[0].toUpperCase() }}-PERP" + }, + { + "name": "direction", + "value": "={{ ($json.body.message || $json.body.text).match(/^(sell|short)\\b/i) ? 'short' : 'long' }}" + }, + { + "name": "timeframe", + "value": "5" + } + ] + } + }, + "id": "parse-command", + "name": "Parse Trade", + "type": "n8n-nodes-base.set", + "typeVersion": 1, + "position": [600, 300] + }, + { + "parameters": { + "respondWith": "json", + "responseBody": "={{ { status: 'received', symbol: $json.symbol, direction: $json.direction } }}" + }, + "id": "webhook-response", + "name": "Webhook Response", + "type": "n8n-nodes-base.respondToWebhook", + "typeVersion": 1, + "position": [600, 450] + }, + { + "parameters": { + "chatId": "579304651", + "text": "🤖 Manual Trade\n\n📊 {{ $json.symbol }}\n{{ $json.direction === 'long' ? '📈' : '📉' }} {{ $json.direction.toUpperCase() }}\n⏰ {{ $now.format('HH:mm:ss') }}\n\n✅ Executing...", + "additionalFields": { + "appendAttribution": false + } + }, + "id": "confirm", + "name": "Send Confirmation", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1.1, + "position": [800, 300], + "credentials": { + "telegramApi": { + "id": "Csk5cg4HtaSqP5jJ", + "name": "Telegram account" + } + } + }, + { + "parameters": {}, + "id": "output", + "name": "➡️ Connect to Check Risk", + "type": "n8n-nodes-base.noOp", + "typeVersion": 1, + "position": [1000, 300], + "notes": "Connect this to your Money Machine's Check Risk node" + } + ], + "connections": { + "Webhook": { + "main": [[ + {"node": "Is Trade Command?", "type": "main", "index": 0} + ]] + }, + "Is Trade Command?": { + "main": [[ + {"node": "Parse Trade", "type": "main", "index": 0} + ]] + }, + "Parse Trade": { + "main": [[ + {"node": "Webhook Response", "type": "main", "index": 0}, + {"node": "Send Confirmation", "type": "main", "index": 0} + ]] + }, + "Send Confirmation": { + "main": [[ + {"node": "➡️ Connect to Check Risk", "type": "main", "index": 0} + ]] + } + }, + "active": false, + "settings": {}, + "versionId": "telegram-webhook-v2" +} + { + "parameters": { + "conditions": { + "string": [ + { + "value1": "={{ $json.message.text }}", + "operation": "regex", + "value2": "^(buy|sell|long|short)\\s+(sol|btc|eth)$" + } + ] + } + }, + "id": "filter-trades", + "name": "Is Trade Command?", + "type": "n8n-nodes-base.if", + "typeVersion": 1, + "position": [400, 300] + }, + { + "parameters": { + "values": { + "string": [ + { + "name": "symbol", + "value": "={{ $json.message.text.match(/\\b(SOL|BTC|ETH)\\b/i)[0].toUpperCase() }}-PERP" + }, + { + "name": "direction", + "value": "={{ $json.message.text.match(/^(sell|short)\\b/i) ? 'short' : 'long' }}" + }, + { + "name": "timeframe", + "value": "5" + } + ] + } + }, + "id": "parse-command", + "name": "Parse Trade", + "type": "n8n-nodes-base.set", + "typeVersion": 1, + "position": [600, 300] + }, + { + "parameters": { + "chatId": "579304651", + "text": "🤖 Manual Trade\n\n📊 {{ $json.symbol }}\n{{ $json.direction === 'long' ? '📈' : '📉' }} {{ $json.direction.toUpperCase() }}\n⏰ {{ $now.format('HH:mm:ss') }}\n\n✅ Executing...", + "additionalFields": { + "appendAttribution": false + } + }, + "id": "confirm", + "name": "Send Confirmation", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1.1, + "position": [800, 300], + "credentials": { + "telegramApi": { + "id": "Csk5cg4HtaSqP5jJ", + "name": "Telegram account" + } + } + }, + { + "parameters": {}, + "id": "output", + "name": "➡️ Connect to Check Risk", + "type": "n8n-nodes-base.noOp", + "typeVersion": 1, + "position": [1000, 300], + "notes": "Connect this to your Money Machine's Check Risk node" + } + ], + "connections": { + "Telegram Messages": { + "main": [[{"node": "Is Trade Command?", "type": "main", "index": 0}]] + }, + "Is Trade Command?": { + "main": [[{"node": "Parse Trade", "type": "main", "index": 0}]] + }, + "Parse Trade": { + "main": [[{"node": "Send Confirmation", "type": "main", "index": 0}]] + }, + "Send Confirmation": { + "main": [[{"node": "➡️ Connect to Check Risk", "type": "main", "index": 0}]] + } + }, + "active": false, + "settings": {}, + "versionId": "telegram-n8n-listener-v1" +} diff --git a/telegram-polling-addon.json b/telegram-polling-addon.json new file mode 100644 index 0000000..f76209b --- /dev/null +++ b/telegram-polling-addon.json @@ -0,0 +1,178 @@ +{ + "name": "Telegram Manual Trade (Polling) - Import to Money Machine", + "nodes": [ + { + "parameters": { + "resource": "message", + "operation": "get", + "chatId": "579304651", + "returnAll": false, + "limit": 1, + "options": {} + }, + "id": "telegram-poll-messages", + "name": "Poll Telegram Messages", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1.1, + "position": [ + -1020, + 460 + ], + "credentials": { + "telegramApi": { + "id": "Csk5cg4HtaSqP5jJ", + "name": "Telegram account" + } + } + }, + { + "parameters": { + "conditions": { + "string": [ + { + "value1": "={{ $json.text }}", + "operation": "regex", + "value2": "\\b(buy|sell|long|short)\\b" + } + ] + } + }, + "id": "filter-trade-commands", + "name": "Filter Trade Commands", + "type": "n8n-nodes-base.if", + "typeVersion": 1, + "position": [ + -840, + 460 + ] + }, + { + "parameters": { + "fields": { + "values": [ + { + "name": "rawMessage", + "stringValue": "={{ $json.text }}" + }, + { + "name": "symbol", + "stringValue": "={{ $json.text.match(/\\b(SOL|BTC|ETH)\\b/i) ? $json.text.match(/\\b(SOL|BTC|ETH)\\b/i)[0].toUpperCase() + '-PERP' : 'SOL-PERP' }}" + }, + { + "name": "direction", + "stringValue": "={{ $json.text.match(/\\b(sell|short)\\b/i) ? 'short' : 'long' }}" + }, + { + "name": "timeframe", + "stringValue": "5" + } + ] + }, + "options": {} + }, + "id": "parse-command", + "name": "Parse Trade Command", + "type": "n8n-nodes-base.set", + "typeVersion": 3.2, + "position": [ + -660, + 460 + ] + }, + { + "parameters": { + "chatId": "579304651", + "text": "🤖 Manual trade:\n\n📊 {{ $json.symbol }}\n{{ $json.direction === 'long' ? '📈' : '📉' }} {{ $json.direction.toUpperCase() }}\n⏰ {{ $now.toFormat('HH:mm:ss') }}\n\n⏳ Processing...", + "additionalFields": { + "appendAttribution": false + } + }, + "id": "send-ack", + "name": "Send Acknowledgment", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1.1, + "position": [ + -480, + 460 + ], + "credentials": { + "telegramApi": { + "id": "Csk5cg4HtaSqP5jJ", + "name": "Telegram account" + } + } + }, + { + "parameters": { + "mode": "raw", + "jsonOutput": "={{ $json }}", + "options": {} + }, + "id": "output-node", + "name": "➡️ Connect to Check Risk", + "type": "n8n-nodes-base.set", + "typeVersion": 3.3, + "position": [ + -300, + 460 + ], + "notes": "Connect this node's output to Money Machine's Check Risk node" + } + ], + "pinData": {}, + "connections": { + "Poll Telegram Messages": { + "main": [ + [ + { + "node": "Filter Trade Commands", + "type": "main", + "index": 0 + } + ] + ] + }, + "Filter Trade Commands": { + "main": [ + [ + { + "node": "Parse Trade Command", + "type": "main", + "index": 0 + } + ] + ] + }, + "Parse Trade Command": { + "main": [ + [ + { + "node": "Send Acknowledgment", + "type": "main", + "index": 0 + } + ] + ] + }, + "Send Acknowledgment": { + "main": [ + [ + { + "node": "➡️ Connect to Check Risk", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": false, + "settings": { + "executionOrder": "v1" + }, + "versionId": "telegram-polling-v1", + "meta": { + "instanceId": "e766d4f0b5def8ee8cb8561cd9d2b9ba7733e1907990b6987bca40175f82c379" + }, + "tags": [] +} diff --git a/telegram-to-webhook.py b/telegram-to-webhook.py new file mode 100644 index 0000000..fe049ff --- /dev/null +++ b/telegram-to-webhook.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +""" +Telegram to n8n Webhook Bridge +Monitors your Telegram chat for trade commands and forwards to n8n webhook +""" +import os +import requests +from telegram import Update +from telegram.ext import Application, MessageHandler, filters, ContextTypes + +# Configuration +TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN', 'YOUR_BOT_TOKEN') +N8N_WEBHOOK_URL = os.getenv('N8N_WEBHOOK_URL', 'https://your-n8n.com/webhook/manual-telegram-trade') +ALLOWED_CHAT_ID = int(os.getenv('TELEGRAM_CHAT_ID', '579304651')) + +async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Handle incoming Telegram messages""" + + # Only process messages from your chat + if update.message.chat_id != ALLOWED_CHAT_ID: + return + + message_text = update.message.text.lower() + + # Only process trade commands (containing buy/sell/long/short) + if not any(word in message_text for word in ['buy', 'sell', 'long', 'short']): + return + + print(f"📨 Received trade command: {message_text}") + + # Forward to n8n webhook + try: + response = requests.post( + N8N_WEBHOOK_URL, + json={'message': message_text}, + timeout=10 + ) + + if response.status_code == 200: + print(f"✅ Forwarded to n8n: {message_text}") + # Send confirmation + await update.message.reply_text( + f"🤖 Processing: {message_text}\n" + f"Forwarded to trading bot..." + ) + else: + print(f"❌ Webhook error: {response.status_code}") + await update.message.reply_text(f"❌ Error: Webhook returned {response.status_code}") + + except Exception as e: + print(f"❌ Error forwarding to webhook: {e}") + await update.message.reply_text(f"❌ Error: {str(e)}") + +def main(): + """Start the bot""" + + if TELEGRAM_BOT_TOKEN == 'YOUR_BOT_TOKEN': + print("❌ Error: Set TELEGRAM_BOT_TOKEN environment variable") + return + + if N8N_WEBHOOK_URL == 'https://your-n8n.com/webhook/manual-telegram-trade': + print("❌ Error: Set N8N_WEBHOOK_URL environment variable") + return + + print(f"🚀 Starting Telegram to n8n bridge...") + print(f"📱 Monitoring chat ID: {ALLOWED_CHAT_ID}") + print(f"🔗 Webhook URL: {N8N_WEBHOOK_URL}") + + # Create application + application = Application.builder().token(TELEGRAM_BOT_TOKEN).build() + + # Add message handler + application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message)) + + # Start polling + print("✅ Bot started! Send trade commands to your Telegram chat.") + application.run_polling(allowed_updates=Update.ALL_TYPES) + +if __name__ == '__main__': + main() diff --git a/telegram-trigger-addon.json b/telegram-trigger-addon.json new file mode 100644 index 0000000..a4d1925 --- /dev/null +++ b/telegram-trigger-addon.json @@ -0,0 +1,138 @@ +{ + "name": "Telegram Trade Trigger (Import to Money Machine)", + "nodes": [ + { + "parameters": { + "httpMethod": "POST", + "path": "manual-telegram-trade", + "options": {} + }, + "id": "webhook-telegram-manual", + "name": "Telegram Command Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 1, + "position": [ + -840, + 460 + ], + "webhookId": "manual-telegram-trade-webhook" + }, + { + "parameters": { + "fields": { + "values": [ + { + "name": "rawMessage", + "stringValue": "={{ $json.body.message || $json.body.text || $json.body }}" + }, + { + "name": "symbol", + "stringValue": "={{ ($json.body.message || $json.body.text || $json.body).toString().match(/\\b(SOL|BTC|ETH)\\b/i) ? ($json.body.message || $json.body.text || $json.body).toString().match(/\\b(SOL|BTC|ETH)\\b/i)[0].toUpperCase() + '-PERP' : 'SOL-PERP' }}" + }, + { + "name": "direction", + "stringValue": "={{ ($json.body.message || $json.body.text || $json.body).toString().match(/\\b(sell|short)\\b/i) ? 'short' : 'long' }}" + }, + { + "name": "timeframe", + "stringValue": "5" + } + ] + }, + "options": {} + }, + "id": "parse-telegram-manual", + "name": "Parse Manual Command", + "type": "n8n-nodes-base.set", + "typeVersion": 3.2, + "position": [ + -660, + 460 + ] + }, + { + "parameters": { + "chatId": "579304651", + "text": "🤖 Manual trade command:\n\n📊 {{ $json.symbol }}\n📈 {{ $json.direction.toUpperCase() }}\n⏰ {{ $now.toFormat('HH:mm') }}\n\n⏳ Processing...", + "additionalFields": { + "appendAttribution": false + } + }, + "id": "ack-manual-command", + "name": "Send Acknowledgment", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1.1, + "position": [ + -480, + 460 + ], + "credentials": { + "telegramApi": { + "id": "Csk5cg4HtaSqP5jJ", + "name": "Telegram account" + } + } + }, + { + "parameters": { + "mode": "raw", + "jsonOutput": "={{ $json }}", + "options": {} + }, + "id": "ready-for-check-risk", + "name": "➡️ Connect to Check Risk", + "type": "n8n-nodes-base.set", + "typeVersion": 3.3, + "position": [ + -300, + 460 + ], + "notes": "Connect this output to the 'Check Risk' node in Money Machine" + } + ], + "pinData": {}, + "connections": { + "Telegram Command Webhook": { + "main": [ + [ + { + "node": "Parse Manual Command", + "type": "main", + "index": 0 + } + ] + ] + }, + "Parse Manual Command": { + "main": [ + [ + { + "node": "Send Acknowledgment", + "type": "main", + "index": 0 + } + ] + ] + }, + "Send Acknowledgment": { + "main": [ + [ + { + "node": "➡️ Connect to Check Risk", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": false, + "settings": { + "executionOrder": "v1" + }, + "versionId": "telegram-webhook-v1", + "meta": { + "instanceId": "e766d4f0b5def8ee8cb8561cd9d2b9ba7733e1907990b6987bca40175f82c379" + }, + "tags": [] +} diff --git a/telegram-webhook-FINAL.json b/telegram-webhook-FINAL.json new file mode 100644 index 0000000..61ba3b5 --- /dev/null +++ b/telegram-webhook-FINAL.json @@ -0,0 +1,128 @@ +{ + "name": "Telegram Manual Trade - ADD TO MONEY MACHINE", + "nodes": [ + { + "parameters": { + "httpMethod": "POST", + "path": "telegram-trade", + "responseMode": "responseNode", + "options": {} + }, + "id": "webhook", + "name": "Webhook Receiver", + "type": "n8n-nodes-base.webhook", + "typeVersion": 1.1, + "position": [200, 300], + "webhookId": "telegram-trade-webhook" + }, + { + "parameters": { + "conditions": { + "string": [ + { + "value1": "={{ $json.body.message || $json.body.text || '' }}", + "operation": "regex", + "value2": "(buy|sell|long|short).*(sol|btc|eth)" + } + ] + } + }, + "id": "filter-trades", + "name": "Is Trade Command?", + "type": "n8n-nodes-base.if", + "typeVersion": 1, + "position": [400, 300] + }, + { + "parameters": { + "values": { + "string": [ + { + "name": "symbol", + "value": "={{ ($json.body.message || $json.body.text).toString().match(/\\b(SOL|BTC|ETH)\\b/i)[0].toUpperCase() }}-PERP" + }, + { + "name": "direction", + "value": "={{ ($json.body.message || $json.body.text).toString().match(/\\b(sell|short)\\b/i) ? 'short' : 'long' }}" + }, + { + "name": "timeframe", + "value": "5" + } + ] + } + }, + "id": "parse-command", + "name": "Parse Trade", + "type": "n8n-nodes-base.set", + "typeVersion": 1, + "position": [600, 300] + }, + { + "parameters": { + "respondWith": "json", + "responseBody": "={{ { \"status\": \"received\", \"symbol\": $json.symbol, \"direction\": $json.direction } }}" + }, + "id": "webhook-response", + "name": "Webhook Response", + "type": "n8n-nodes-base.respondToWebhook", + "typeVersion": 1, + "position": [800, 450] + }, + { + "parameters": { + "chatId": "579304651", + "text": "🤖 Manual Trade\\n\\n📊 {{ $json.symbol }}\\n{{ $json.direction === 'long' ? '📈' : '📉' }} {{ $json.direction.toUpperCase() }}\\n⏰ {{ $now.format('HH:mm:ss') }}\\n\\n✅ Executing...", + "additionalFields": { + "appendAttribution": false + } + }, + "id": "confirm", + "name": "Send Telegram Confirm", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1.1, + "position": [800, 300], + "credentials": { + "telegramApi": { + "id": "Csk5cg4HtaSqP5jJ", + "name": "Telegram account" + } + } + }, + { + "parameters": {}, + "id": "output", + "name": "➡️ Connect to Check Risk", + "type": "n8n-nodes-base.noOp", + "typeVersion": 1, + "position": [1000, 300], + "notes": "Connect this output to your Money Machine's Check Risk node" + } + ], + "connections": { + "Webhook Receiver": { + "main": [[ + {"node": "Is Trade Command?", "type": "main", "index": 0} + ]] + }, + "Is Trade Command?": { + "main": [[ + {"node": "Parse Trade", "type": "main", "index": 0} + ]] + }, + "Parse Trade": { + "main": [[ + {"node": "Webhook Response", "type": "main", "index": 0}, + {"node": "Send Telegram Confirm", "type": "main", "index": 0} + ]] + }, + "Send Telegram Confirm": { + "main": [[ + {"node": "➡️ Connect to Check Risk", "type": "main", "index": 0} + ]] + } + }, + "active": false, + "settings": {}, + "versionId": "telegram-webhook-final" +} diff --git a/telegram_command_bot.py b/telegram_command_bot.py new file mode 100644 index 0000000..28a2304 --- /dev/null +++ b/telegram_command_bot.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +""" +Telegram Trade Bot - SECURE Command-based +Only responds to YOUR commands in YOUR chat +""" +import os +import requests +from telegram import Update +from telegram.ext import Application, CommandHandler, ContextTypes + +# Configuration +TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN') +N8N_WEBHOOK_URL = os.getenv('N8N_WEBHOOK_URL') +ALLOWED_CHAT_ID = int(os.getenv('TELEGRAM_CHAT_ID', '579304651')) + +async def trade_command(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Handle trade commands like /buySOL, /sellBTC, etc.""" + + # Only process from YOUR chat + if update.message.chat_id != ALLOWED_CHAT_ID: + await update.message.reply_text("❌ Unauthorized") + return + + # Extract command (remove the /) + command = update.message.text[1:].lower() # e.g., "buysol" + + # Parse action and symbol + if command.startswith('buy'): + action = 'buy' + symbol = command[3:] # e.g., "sol" + elif command.startswith('sell'): + action = 'sell' + symbol = command[4:] # e.g., "btc" + else: + await update.message.reply_text("❓ Unknown command") + return + + message = f"{action} {symbol}" + print(f"📨 Command: {message}", flush=True) + + # Forward to n8n webhook - send as plain text body like TradingView does + try: + print(f"📤 Sending: {message}", flush=True) + + response = requests.post( + N8N_WEBHOOK_URL, + data=message, # Plain text, not JSON + headers={'Content-Type': 'text/plain'}, + timeout=10 + ) + + print(f"📥 Response status: {response.status_code}", flush=True) + print(f"📥 Response body: {response.text[:200]}", flush=True) + + if response.ok: + print(f"✅ Sent: {message}", flush=True) + await update.message.reply_text( + f"🤖 {action.upper()} {symbol.upper()}\n" + f"✅ Trade command sent!" + ) + else: + print(f"❌ Error: {response.status_code}", flush=True) + await update.message.reply_text(f"❌ Error: {response.status_code}") + + except Exception as e: + print(f"❌ Error: {e}", flush=True) + await update.message.reply_text(f"❌ Error: {str(e)}") + +def main(): + """Start the bot""" + + print(f"🚀 Telegram Trade Bot Starting...", flush=True) + print(f"📱 Allowed Chat ID: {ALLOWED_CHAT_ID}", flush=True) + print(f"🔗 Webhook: {N8N_WEBHOOK_URL}", flush=True) + print(f"\n✅ Commands:", flush=True) + print(f" /buySOL, /sellSOL", flush=True) + print(f" /buyBTC, /sellBTC", flush=True) + print(f" /buyETH, /sellETH", flush=True) + + # Create application + application = Application.builder().token(TELEGRAM_BOT_TOKEN).build() + + # Add command handlers + application.add_handler(CommandHandler("buySOL", trade_command)) + application.add_handler(CommandHandler("sellSOL", trade_command)) + application.add_handler(CommandHandler("buyBTC", trade_command)) + application.add_handler(CommandHandler("sellBTC", trade_command)) + application.add_handler(CommandHandler("buyETH", trade_command)) + application.add_handler(CommandHandler("sellETH", trade_command)) + + # Start polling + print("\n🤖 Bot ready! Send commands to your Telegram.\n", flush=True) + application.run_polling(allowed_updates=Update.ALL_TYPES) + +if __name__ == '__main__': + main() diff --git a/telegram_trade_bot.py b/telegram_trade_bot.py new file mode 100644 index 0000000..9ce58d4 --- /dev/null +++ b/telegram_trade_bot.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +""" +Simple Telegram bot that forwards trade commands to n8n webhook +Install: pip3 install python-telegram-bot requests +Run: python3 telegram_trade_bot.py +""" +import os +import requests +from telegram import Update +from telegram.ext import Application, MessageHandler, filters, ContextTypes + +# Configuration - SET THESE! +TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN', 'YOUR_BOT_TOKEN_HERE') +N8N_WEBHOOK_URL = os.getenv('N8N_WEBHOOK_URL', 'https://your-n8n.com/webhook/manual-trade') +ALLOWED_CHAT_ID = int(os.getenv('TELEGRAM_CHAT_ID', '579304651')) + +async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE): + """Forward trade commands to n8n""" + + # Only your chat + if update.message.chat_id != ALLOWED_CHAT_ID: + return + + text = update.message.text.lower().strip() + + # Only process trade commands: buy/sell followed by symbol + if not any(text.startswith(cmd) for cmd in ['buy', 'sell', 'long', 'short']): + return + + print(f"📨 {text}") + + # Forward to n8n + try: + response = requests.post( + N8N_WEBHOOK_URL, + json={'text': text}, + timeout=10 + ) + + if response.ok: + print(f"✅ Sent to n8n") + else: + print(f"❌ Error {response.status_code}") + await update.message.reply_text(f"❌ Error: {response.status_code}") + + except Exception as e: + print(f"❌ {e}") + await update.message.reply_text(f"❌ Error: {str(e)}") + +def main(): + """Start bot""" + + if TELEGRAM_BOT_TOKEN == 'YOUR_BOT_TOKEN_HERE': + print("❌ Set TELEGRAM_BOT_TOKEN environment variable") + print("Example: export TELEGRAM_BOT_TOKEN='your_token'") + return + + if N8N_WEBHOOK_URL == 'https://your-n8n.com/webhook/manual-trade': + print("❌ Set N8N_WEBHOOK_URL environment variable") + print("Example: export N8N_WEBHOOK_URL='https://n8n.yourdomain.com/webhook/manual-trade'") + return + + print(f"🚀 Telegram Trade Bot Starting...") + print(f"📱 Chat ID: {ALLOWED_CHAT_ID}") + print(f"🔗 Webhook: {N8N_WEBHOOK_URL}") + print(f"\n✅ Send messages like:") + print(f" buy sol") + print(f" sell btc") + print(f" buy eth") + print(f" sell sol") + + app = Application.builder().token(TELEGRAM_BOT_TOKEN).build() + app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message)) + + print(f"\n🤖 Bot ready! Listening for trade commands...\n") + app.run_polling(allowed_updates=Update.ALL_TYPES) + +if __name__ == '__main__': + main() diff --git a/trade.sh b/trade.sh new file mode 100755 index 0000000..41f6931 --- /dev/null +++ b/trade.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Send manual trade command +# Usage: ./trade.sh buy sol +# ./trade.sh sell btc + +COMMAND="$1 $2" + +if [ -z "$COMMAND" ]; then + echo "Usage: $0 " + echo "Example: $0 buy sol" + exit 1 +fi + +curl -X POST http://10.0.0.48:8098/webhook/3371ad7c-0866-4161-90a4-f251de4aceb8 \ + -H "Content-Type: application/json" \ + -d "{\"body\": \"$COMMAND\"}" + +echo "" +echo "✅ Trade command sent: $COMMAND" diff --git a/webapp-trade.html b/webapp-trade.html new file mode 100644 index 0000000..35a3caa --- /dev/null +++ b/webapp-trade.html @@ -0,0 +1,120 @@ + + + + + + Quick Trade + + + +

📊 Quick Trade

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + +