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
This commit is contained in:
12
.env
12
.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)
|
||||
|
||||
11
.env.telegram-bot
Normal file
11
.env.telegram-bot
Normal file
@@ -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
|
||||
262
.github/copilot-instructions.md
vendored
Normal file
262
.github/copilot-instructions.md
vendored
Normal file
@@ -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.
|
||||
11
CREATE_NEW_BOT.md
Normal file
11
CREATE_NEW_BOT.md
Normal file
@@ -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!
|
||||
12
Dockerfile.telegram-bot
Normal file
12
Dockerfile.telegram-bot
Normal file
@@ -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"]
|
||||
24
GET_BOT_TOKEN.sh
Executable file
24
GET_BOT_TOKEN.sh
Executable file
@@ -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"
|
||||
486
Money_Machine.json
Normal file
486
Money_Machine.json
Normal file
@@ -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": []
|
||||
}
|
||||
115
TELEGRAM_BOT_README.md
Normal file
115
TELEGRAM_BOT_README.md
Normal file
@@ -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!
|
||||
64
complete_telegram_setup.sh
Executable file
64
complete_telegram_setup.sh
Executable file
@@ -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
|
||||
22
docker-compose.telegram-bot.yml
Normal file
22
docker-compose.telegram-bot.yml
Normal file
@@ -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
|
||||
105
quick-trade.html
Normal file
105
quick-trade.html
Normal file
@@ -0,0 +1,105 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Quick Trade</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 500px;
|
||||
margin: 50px auto;
|
||||
padding: 20px;
|
||||
background: #1a1a1a;
|
||||
color: #fff;
|
||||
}
|
||||
button {
|
||||
width: 48%;
|
||||
padding: 30px;
|
||||
margin: 5px 1%;
|
||||
font-size: 20px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
.buy { background: #10b981; color: white; }
|
||||
.sell { background: #ef4444; color: white; }
|
||||
.row { margin: 20px 0; }
|
||||
h2 { text-align: center; color: #10b981; }
|
||||
#status {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
display: none;
|
||||
text-align: center;
|
||||
}
|
||||
.success { background: #10b981; }
|
||||
.error { background: #ef4444; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>📱 Quick Trade</h2>
|
||||
|
||||
<div class="row">
|
||||
<button class="buy" onclick="trade('buy', 'sol')">BUY SOL</button>
|
||||
<button class="sell" onclick="trade('sell', 'sol')">SELL SOL</button>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<button class="buy" onclick="trade('buy', 'btc')">BUY BTC</button>
|
||||
<button class="sell" onclick="trade('sell', 'btc')">SELL BTC</button>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<button class="buy" onclick="trade('buy', 'eth')">BUY ETH</button>
|
||||
<button class="sell" onclick="trade('sell', 'eth')">SELL ETH</button>
|
||||
</div>
|
||||
|
||||
<div id="status"></div>
|
||||
|
||||
<script>
|
||||
// SECRET TOKEN - Keep this file private! Only accessible from localhost
|
||||
const SECRET_TOKEN = 'YOUR_SECRET_HERE_' + Math.random().toString(36).substring(7);
|
||||
|
||||
// Only allow from localhost/internal network
|
||||
if (!window.location.hostname.match(/^(localhost|127\.0\.0\.1|10\.|192\.168\.|172\.)/)) {
|
||||
document.body.innerHTML = '<h2 style="color:red">Access Denied</h2>';
|
||||
}
|
||||
|
||||
async function trade(action, symbol) {
|
||||
const status = document.getElementById('status');
|
||||
status.style.display = 'block';
|
||||
status.className = '';
|
||||
status.textContent = '⏳ Sending...';
|
||||
|
||||
try {
|
||||
const response = await fetch('http://10.0.0.48:8098/webhook/3371ad7c-0866-4161-90a4-f251de4aceb8', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Secret-Token': SECRET_TOKEN
|
||||
},
|
||||
body: JSON.stringify({
|
||||
body: `${action} ${symbol}`,
|
||||
secret: SECRET_TOKEN
|
||||
})
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
status.className = 'success';
|
||||
status.textContent = `✅ ${action.toUpperCase()} ${symbol.toUpperCase()} sent!`;
|
||||
} else {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
status.className = 'error';
|
||||
status.textContent = `❌ Error: ${error.message}`;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
status.style.display = 'none';
|
||||
}, 3000);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
22
send_trade.sh
Executable file
22
send_trade.sh
Executable file
@@ -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!"
|
||||
60
setup_telegram_bot.sh
Executable file
60
setup_telegram_bot.sh
Executable file
@@ -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"
|
||||
161
telegram-listener-simple.json
Normal file
161
telegram-listener-simple.json
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
155
telegram-manual-trade-FINAL.json
Normal file
155
telegram-manual-trade-FINAL.json
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
219
telegram-n8n-listener.json
Normal file
219
telegram-n8n-listener.json
Normal file
@@ -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"
|
||||
}
|
||||
178
telegram-polling-addon.json
Normal file
178
telegram-polling-addon.json
Normal file
@@ -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": []
|
||||
}
|
||||
80
telegram-to-webhook.py
Normal file
80
telegram-to-webhook.py
Normal file
@@ -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()
|
||||
138
telegram-trigger-addon.json
Normal file
138
telegram-trigger-addon.json
Normal file
@@ -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": []
|
||||
}
|
||||
128
telegram-webhook-FINAL.json
Normal file
128
telegram-webhook-FINAL.json
Normal file
@@ -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"
|
||||
}
|
||||
96
telegram_command_bot.py
Normal file
96
telegram_command_bot.py
Normal file
@@ -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()
|
||||
79
telegram_trade_bot.py
Normal file
79
telegram_trade_bot.py
Normal file
@@ -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()
|
||||
19
trade.sh
Executable file
19
trade.sh
Executable file
@@ -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 <buy|sell> <sol|btc|eth>"
|
||||
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"
|
||||
120
webapp-trade.html
Normal file
120
webapp-trade.html
Normal file
@@ -0,0 +1,120 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||
<title>Quick Trade</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
padding: 20px;
|
||||
background: var(--tg-theme-bg-color, #1a1a1a);
|
||||
color: var(--tg-theme-text-color, #fff);
|
||||
min-height: 100vh;
|
||||
}
|
||||
h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
color: var(--tg-theme-accent-text-color, #10b981);
|
||||
}
|
||||
button {
|
||||
width: 48%;
|
||||
padding: 40px 10px;
|
||||
margin: 5px 1%;
|
||||
font-size: 18px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
transition: transform 0.1s;
|
||||
}
|
||||
button:active { transform: scale(0.95); }
|
||||
.buy { background: #10b981; color: white; }
|
||||
.sell { background: #ef4444; color: white; }
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 15px 0;
|
||||
}
|
||||
#status {
|
||||
margin-top: 30px;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
display: none;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.success { background: #10b981; color: white; }
|
||||
.error { background: #ef4444; color: white; }
|
||||
.loading { background: #3b82f6; color: white; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>📊 Quick Trade</h2>
|
||||
|
||||
<div class="row">
|
||||
<button class="buy" onclick="trade('buy', 'SOL')">🟢 BUY<br>SOL</button>
|
||||
<button class="sell" onclick="trade('sell', 'SOL')">🔴 SELL<br>SOL</button>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<button class="buy" onclick="trade('buy', 'BTC')">🟢 BUY<br>BTC</button>
|
||||
<button class="sell" onclick="trade('sell', 'BTC')">🔴 SELL<br>BTC</button>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<button class="buy" onclick="trade('buy', 'ETH')">🟢 BUY<br>ETH</button>
|
||||
<button class="sell" onclick="trade('sell', 'ETH')">🔴 SELL<br>ETH</button>
|
||||
</div>
|
||||
|
||||
<div id="status"></div>
|
||||
|
||||
<script>
|
||||
let tg = window.Telegram.WebApp;
|
||||
tg.ready();
|
||||
tg.expand();
|
||||
|
||||
async function trade(action, symbol) {
|
||||
const status = document.getElementById('status');
|
||||
status.style.display = 'block';
|
||||
status.className = 'loading';
|
||||
status.textContent = '⏳ Sending trade...';
|
||||
|
||||
// Haptic feedback
|
||||
if (tg.HapticFeedback) {
|
||||
tg.HapticFeedback.impactOccurred('medium');
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('http://10.0.0.48:8098/webhook/3371ad7c-0866-4161-90a4-f251de4aceb8', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ body: `${action} ${symbol}` })
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
status.className = 'success';
|
||||
status.textContent = `✅ ${action.toUpperCase()} ${symbol} executed!`;
|
||||
if (tg.HapticFeedback) {
|
||||
tg.HapticFeedback.notificationOccurred('success');
|
||||
}
|
||||
} else {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
status.className = 'error';
|
||||
status.textContent = `❌ Error: ${error.message}`;
|
||||
if (tg.HapticFeedback) {
|
||||
tg.HapticFeedback.notificationOccurred('error');
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
status.style.display = 'none';
|
||||
}, 3000);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user