Преглед изворни кода

Hyperliquid Manual Trading Bot - Complete professional trading solution with Telegram interface, comprehensive statistics, auto-restart, and mobile control

Carles Sentis пре 5 дана
комит
1a4449c4ab

+ 196 - 0
.gitignore

@@ -0,0 +1,196 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+#   For a library or package, you might want to ignore these files since the code is
+#   intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+#   This is especially recommended for binary packages to ensure reproducibility, and is more
+#   commonly ignored for libraries.
+#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+#   in version control.
+#   https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+#  be added to the global gitignore or merged into this project gitignore.  For a PyCharm
+#  project, it is recommended to exclude the whole .idea directory from version control.
+.idea/
+
+# Trading Bot Specific
+# Configuration files (contain sensitive keys)
+.env
+.env.local
+.env.production
+.env.development
+
+# Trading data and logs
+logs/
+*.log
+trading_stats.json
+demo_stats.json
+
+# Backup files
+*.bak
+*.backup
+*.orig
+
+# OS specific files
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+# IDE files
+.vscode/
+*.swp
+*.swo
+*~
+
+# Temporary files
+*.tmp
+*.temp 

+ 338 - 0
DEPLOYMENT_GUIDE.md

@@ -0,0 +1,338 @@
+# 🚀 Deployment Guide - How to Run Your Trading Bot
+
+This guide explains the different ways to run your Hyperliquid trading bot and best practices for each approach.
+
+## 📋 Overview
+
+You have **three different bot types**:
+
+| Bot Type | File | Purpose | Running Time |
+|----------|------|---------|--------------|
+| **Telegram Bot** | `telegram_bot.py` | Remote control interface | Continuous |
+| **Strategy Bot** | `strategy_bot.py` | Automated trading strategies | Continuous |
+| **Terminal Bot** | `simple_bot.py` | Interactive terminal interface | On-demand |
+
+## 🎯 **Different Use Cases**
+
+### **Use Case 1: Manual Trading with Remote Control**
+**Goal**: Monitor and control manually via Telegram
+```bash
+# Run only the Telegram bot
+source venv/bin/activate
+python telegram_bot.py
+```
+- ✅ Control via Telegram from anywhere
+- ✅ Manual decision making
+- ✅ Safe for beginners
+
+### **Use Case 2: Automated Trading**
+**Goal**: Fully automated trading with monitoring
+```bash
+# Terminal 1: Run strategy bot
+source venv/bin/activate
+python strategy_bot.py
+
+# Terminal 2: Run Telegram bot for monitoring
+source venv/bin/activate
+python telegram_bot.py
+```
+- ✅ Automated trading strategies
+- ✅ Remote monitoring via Telegram
+- ✅ Professional setup
+
+### **Use Case 3: Development and Testing**
+**Goal**: Test strategies and debug
+```bash
+# Use terminal bot for quick testing
+source venv/bin/activate
+python simple_bot.py
+```
+- ✅ Interactive testing
+- ✅ Quick market data checks
+- ✅ Debug configuration
+
+## 🔄 **Long-Running vs. Cron Jobs**
+
+### ❌ **DON'T Use Cron Jobs For:**
+- Telegram bot (needs to stay connected)
+- Strategy bot (needs continuous monitoring)
+- Any interactive functionality
+
+### ✅ **DO Use Long-Running Processes:**
+```bash
+# These run forever until you stop them
+python telegram_bot.py     # Listens for Telegram commands 24/7
+python strategy_bot.py     # Executes strategies every 60 seconds
+```
+
+### ✅ **Optional: Use Cron for Maintenance:**
+```bash
+# Example: Daily log rotation (optional)
+0 0 * * * /path/to/your/log_rotation_script.sh
+```
+
+## 🖥️ **Production Deployment Options**
+
+### **Option 1: Screen/Tmux Sessions**
+```bash
+# Start a screen session
+screen -S trading_bot
+
+# Run your bot
+source venv/bin/activate
+python telegram_bot.py
+
+# Detach: Ctrl+A, then D
+# Reattach: screen -r trading_bot
+```
+
+### **Option 2: Systemd Service (Linux)**
+Create `/etc/systemd/system/trading-bot.service`:
+```ini
+[Unit]
+Description=Hyperliquid Trading Bot
+After=network.target
+
+[Service]
+Type=simple
+User=your_username
+WorkingDirectory=/path/to/trader_hyperliquid
+Environment=PATH=/path/to/trader_hyperliquid/venv/bin
+ExecStart=/path/to/trader_hyperliquid/venv/bin/python telegram_bot.py
+Restart=always
+RestartSec=10
+
+[Install]
+WantedBy=multi-user.target
+```
+
+```bash
+sudo systemctl enable trading-bot
+sudo systemctl start trading-bot
+sudo systemctl status trading-bot
+```
+
+### **Option 3: Docker (Advanced)**
+```dockerfile
+FROM python:3.11-slim
+
+WORKDIR /app
+COPY requirements.txt .
+RUN pip install -r requirements.txt
+
+COPY . .
+CMD ["python", "telegram_bot.py"]
+```
+
+### **Option 4: Process Manager (PM2)**
+```bash
+npm install -g pm2
+pm2 start telegram_bot.py --interpreter python3
+pm2 startup
+pm2 save
+```
+
+## 📊 **Recommended Deployment Strategy**
+
+### **For Beginners:**
+1. **Start with manual control:**
+   ```bash
+   python telegram_bot.py
+   ```
+2. **Test strategies separately:**
+   ```bash
+   python strategy_bot.py  # Watch logs, don't let it trade yet
+   ```
+
+### **For Production:**
+1. **Run both bots in separate processes:**
+   ```bash
+   # Terminal 1 (or systemd service)
+   python telegram_bot.py
+   
+   # Terminal 2 (or systemd service)  
+   python strategy_bot.py
+   ```
+
+2. **Use process monitoring:**
+   ```bash
+   # Check if bots are running
+   ps aux | grep python
+   
+   # Check logs
+   tail -f ~/.local/share/hyperliquid-bot/logs/
+   ```
+
+## 🔧 **Bot Intervals and Timing**
+
+### **Strategy Bot Timing:**
+```python
+# In strategy_bot.py
+self.loop_interval = 60  # Run every 60 seconds
+```
+
+**Why 60 seconds?**
+- ✅ Balances responsiveness with API limits
+- ✅ Prevents overtrading
+- ✅ Allows time for proper analysis
+
+**Adjust based on strategy:**
+```python
+# Scalping: More frequent (careful of API limits)
+self.loop_interval = 30  # 30 seconds
+
+# Swing trading: Less frequent
+self.loop_interval = 300  # 5 minutes
+
+# Long-term: Much less frequent
+self.loop_interval = 3600  # 1 hour
+```
+
+### **Telegram Bot:**
+- Runs continuously
+- Responds instantly to commands
+- No interval needed
+
+## 🛡️ **Safety and Monitoring**
+
+### **1. Always Start with Testnet**
+```env
+HYPERLIQUID_TESTNET=true
+```
+
+### **2. Monitor Your Bots**
+```bash
+# Check bot status via Telegram
+/status
+
+# Check logs
+tail -f logs/trading_bot.log
+
+# Check system resources
+htop
+```
+
+### **3. Set Up Alerts**
+```python
+# Add to your strategy bot
+if large_loss_detected:
+    await send_telegram_alert("⚠️ Large loss detected!")
+```
+
+### **4. Implement Circuit Breakers**
+```python
+# In your strategy
+if daily_loss > max_daily_loss:
+    logger.error("Daily loss limit reached. Stopping trading.")
+    self.trading_enabled = False
+```
+
+## 🔄 **Updating and Maintenance**
+
+### **Safe Update Process:**
+1. **Stop bots gracefully:**
+   ```bash
+   # Ctrl+C or
+   sudo systemctl stop trading-bot
+   ```
+
+2. **Backup configuration:**
+   ```bash
+   cp .env .env.backup
+   ```
+
+3. **Update code:**
+   ```bash
+   git pull  # or download new version
+   ```
+
+4. **Test in terminal:**
+   ```bash
+   python simple_bot.py
+   ```
+
+5. **Restart production bots:**
+   ```bash
+   python telegram_bot.py
+   ```
+
+## 🔍 **Troubleshooting**
+
+### **Bot Won't Start:**
+```bash
+# Check configuration
+python -c "from config import Config; Config.validate()"
+
+# Check dependencies
+pip list | grep hyperliquid
+```
+
+### **Telegram Bot Not Responding:**
+```bash
+# Test token
+curl https://api.telegram.org/bot<YOUR_TOKEN>/getMe
+
+# Check chat ID
+python get_telegram_chat_id.py
+```
+
+### **Strategy Bot Not Trading:**
+```bash
+# Check if trading is enabled in code
+grep -n "Uncomment to enable" strategy_bot.py
+
+# Check balance and positions
+python simple_bot.py
+```
+
+## 📈 **Best Practices**
+
+### **1. Resource Management**
+- Monitor CPU and memory usage
+- Implement proper logging rotation
+- Use rate limiting for API calls
+
+### **2. Security**
+- Keep private keys secure
+- Use environment variables
+- Regularly rotate API keys
+
+### **3. Monitoring**
+- Set up health checks
+- Monitor trading performance
+- Track system metrics
+
+### **4. Testing**
+- Always test on testnet first
+- Use small amounts initially
+- Monitor for several days before scaling
+
+## 🎯 **Quick Commands Reference**
+
+```bash
+# Start manual control bot
+python telegram_bot.py
+
+# Start automated trading bot
+python strategy_bot.py
+
+# Start both (recommended for production)
+python telegram_bot.py &
+python strategy_bot.py
+
+# Test configuration
+python simple_bot.py
+
+# Get Telegram Chat ID
+python get_telegram_chat_id.py
+
+# Check if running
+ps aux | grep "python.*bot"
+
+# Stop all bots
+pkill -f "python.*bot"
+```
+
+---
+
+**Remember**: Start simple, test thoroughly, and scale gradually! 🚀 

+ 188 - 0
PROJECT_STRUCTURE.md

@@ -0,0 +1,188 @@
+# 📁 Project Structure
+
+## 🎯 **Single Command Launch**
+```bash
+python trading_bot.py  # THIS IS ALL YOU NEED TO RUN
+```
+
+## 📂 **Organized Folder Structure**
+
+```
+trader_hyperliquid/
+├── 🚀 trading_bot.py              # MAIN LAUNCHER (run this!)
+├── 📊 trading_stats.json          # Your persistent statistics
+├── 📝 .env                        # Your configuration (create from config/env.example)
+├── 📚 requirements.txt            # Dependencies
+├── 
+├── 📖 Documentation/
+│   ├── README.md                  # Complete guide
+│   ├── SETUP_GUIDE.md            # 5-minute setup
+│   ├── DEPLOYMENT_GUIDE.md       # Advanced deployment
+│   └── PROJECT_STRUCTURE.md      # This file
+│
+├── 🔧 src/                        # Core bot modules
+│   ├── __init__.py
+│   ├── config.py                  # Configuration management
+│   ├── hyperliquid_client.py      # Hyperliquid API wrapper
+│   ├── telegram_bot.py            # Telegram interface
+│   └── trading_stats.py           # Statistics engine
+│
+├── 🛠️ utils/                      # Utility scripts
+│   ├── get_telegram_chat_id.py   # Get your Chat ID
+│   ├── demo_stats.py             # See sample statistics
+│   ├── simple_bot.py             # Terminal interface
+│   ├── strategy_bot.py           # Automated strategies
+│   └── manual_trading_bot.py     # Old manual launcher
+│
+├── ⚙️ config/
+│   └── env.example               # Configuration template
+│
+├── 📋 logs/                       # Auto-created logs
+│   ├── trading_bot_YYYYMMDD.log  # Daily logs
+│   └── bot_errors.log            # Error log
+│
+└── 🐍 venv/                      # Python virtual environment
+```
+
+## 🎯 **What Each File Does**
+
+### **🚀 Main Files (What You Use)**
+
+| File | Purpose | When to Use |
+|------|---------|-------------|
+| `trading_bot.py` | **Main launcher** | **Always** - This is your bot |
+| `trading_stats.json` | Your trading data | Auto-created, never delete |
+| `.env` | Your configuration | Create from `config/env.example` |
+
+### **📖 Documentation**
+
+| File | Purpose |
+|------|---------|
+| `README.md` | Complete bot documentation |
+| `SETUP_GUIDE.md` | 5-minute quick setup |
+| `DEPLOYMENT_GUIDE.md` | Advanced deployment options |
+| `PROJECT_STRUCTURE.md` | This file - folder organization |
+
+### **🔧 Core Modules (`src/`)**
+
+| File | Purpose |
+|------|---------|
+| `config.py` | Loads and validates your `.env` settings |
+| `hyperliquid_client.py` | Handles all Hyperliquid API calls |
+| `telegram_bot.py` | Your phone interface and trading commands |
+| `trading_stats.py` | Calculates all your performance metrics |
+
+### **🛠️ Utilities (`utils/`)**
+
+| File | Purpose | When to Use |
+|------|---------|-------------|
+| `get_telegram_chat_id.py` | Find your Chat ID | **Setup only** |
+| `demo_stats.py` | See sample statistics | **Optional demo** |
+| `simple_bot.py` | Terminal interface | Testing/debugging |
+| `strategy_bot.py` | Automated strategies | If you want automation |
+
+### **📋 Auto-Created Files**
+
+| File/Folder | Purpose |
+|-------------|---------|
+| `logs/` | All bot logs and error tracking |
+| `trading_stats.json` | Your persistent trading statistics |
+| `demo_stats.json` | Sample data (can delete) |
+
+## 🚀 **How to Use This Structure**
+
+### **1. Initial Setup**
+```bash
+# 1. Get your Telegram Chat ID
+python utils/get_telegram_chat_id.py
+
+# 2. Configure the bot
+cp config/env.example .env
+nano .env  # Add your keys and Chat ID
+
+# 3. See what stats look like (optional)
+python utils/demo_stats.py
+```
+
+### **2. Daily Usage**
+```bash
+# Start your trading bot (ONLY command you need!)
+python trading_bot.py
+```
+
+### **3. Maintenance**
+```bash
+# Check logs
+tail -f logs/trading_bot_$(date +%Y%m%d).log
+
+# Validate configuration
+python -c "import sys; sys.path.insert(0, 'src'); from config import Config; Config.validate()"
+```
+
+## 🛡️ **Built-in Safety Features**
+
+### **📊 Persistent Statistics**
+- ✅ **Always saved** to `trading_stats.json`
+- ✅ **Survives restarts** - your data is never lost
+- ✅ **Automatic backups** via comprehensive logging
+
+### **🔄 Auto-Restart**
+- ✅ **Up to 10 restart attempts** if bot crashes
+- ✅ **Telegram error notifications** sent to your phone
+- ✅ **Exponential backoff** prevents spam restarts
+- ✅ **Graceful shutdown** on Ctrl+C
+
+### **📝 Comprehensive Logging**
+- ✅ **Daily log files** in `logs/` folder
+- ✅ **Error tracking** with stack traces
+- ✅ **Telegram notifications** for errors
+- ✅ **Startup/shutdown** notifications
+
+### **⚙️ Configuration Validation**
+- ✅ **Checks all required settings** before starting
+- ✅ **Clear error messages** with setup instructions
+- ✅ **Network warnings** (testnet vs mainnet)
+- ✅ **Prevents accidental real trading**
+
+## 📱 **Mobile-First Design**
+
+### **Phone Control**
+- 📱 All trading via Telegram commands
+- 📊 Complete statistics on your phone
+- 🔄 Real-time balance and P&L updates
+- 📈 Professional trading metrics
+
+### **Error Notifications**
+- 🚨 Instant error alerts to your phone
+- 🔄 Restart notifications
+- 🟢 Startup confirmations
+- 📊 Status updates
+
+## 🎯 **Key Benefits of This Structure**
+
+1. **🚀 Single Command**: `python trading_bot.py` - that's it!
+2. **📊 Persistent Data**: Your stats survive forever
+3. **🛡️ Auto-Recovery**: Bot restarts itself on errors
+4. **📱 Phone Alerts**: Get notified of any issues
+5. **📝 Complete Logs**: Full audit trail of everything
+6. **⚙️ Easy Setup**: Organized configuration and setup tools
+7. **🔧 Modular**: Clean separation of concerns
+
+## 💡 **Pro Tips**
+
+### **Keep It Simple**
+- Only use `trading_bot.py` for daily trading
+- Let the bot handle all restarts and errors
+- Check Telegram for status and error notifications
+
+### **Backup Your Data**
+- Your `.env` file (contains your keys)
+- Your `trading_stats.json` file (your performance data)
+- Archive log files periodically
+
+### **Monitor Performance**
+- Use `/stats` command in Telegram regularly
+- Check daily logs for any issues
+- Monitor error notifications
+
+**This structure gives you professional-grade trading infrastructure with simple phone control! 🚀📱** 

+ 141 - 0
QUICK_START.md

@@ -0,0 +1,141 @@
+# 🚀 Quick Start - Your Questions Answered
+
+## ✅ **Stats Persistence**: YES, Forever Saved!
+Your trading statistics are **permanently saved** to `trading_stats.json` and automatically loaded every time you restart the bot. Your complete trading history, P&L, win rates, and all performance metrics survive forever between launches.
+
+## 📁 **Organized Structure**: Clean & Simple
+```
+trader_hyperliquid/
+├── 🚀 trading_bot.py              # ONE COMMAND TO RUN EVERYTHING
+├── 📊 trading_stats.json          # Your persistent data
+├── 📝 .env                        # Your config
+├── 
+├── 🔧 src/                        # Core modules (don't touch)
+├── 🛠️ utils/                      # Setup helpers
+├── ⚙️ config/                     # Configuration template
+└── 📋 logs/                       # Auto-created logs & errors
+```
+
+## 🎯 **Single Command Launch**: Super Simple
+```bash
+python trading_bot.py    # THIS IS ALL YOU NEED!
+```
+- ✅ Launches Telegram bot automatically
+- ✅ Handles all errors and restarts
+- ✅ Sends notifications to your phone
+- ✅ Manages all logging and persistence
+
+## 🛡️ **Built-in Safeguards**: Bulletproof
+- **🔄 Auto-restart**: Up to 10 attempts if crashes
+- **📱 Error notifications**: Instant alerts to your Telegram
+- **📝 Complete logging**: All errors saved to files
+- **⚙️ Graceful shutdown**: Ctrl+C stops cleanly
+- **📊 Data protection**: Stats never lost
+
+## 🚀 **Setup in 3 Minutes**
+
+### **1. Get Telegram Chat ID**
+```bash
+python utils/get_telegram_chat_id.py
+```
+
+### **2. Configure Bot**
+```bash
+cp config/env.example .env
+nano .env  # Add your keys and Chat ID
+```
+
+### **3. Start Trading!**
+```bash
+python trading_bot.py
+```
+
+## 📱 **What Happens When You Start**
+
+1. **🔍 Validates** all your configuration
+2. **📊 Loads** your existing trading statistics (if any)
+3. **🚀 Starts** Telegram bot for phone control
+4. **📱 Sends** startup notification to your phone
+5. **🛡️ Monitors** for errors and auto-restarts if needed
+6. **📝 Logs** everything to daily log files
+
+## 🆘 **Error Handling Examples**
+
+### **If Bot Crashes:**
+- 🔄 **Auto-restarts** in 5 seconds
+- 📱 **Sends error alert** to your Telegram
+- 📝 **Logs details** to `logs/bot_errors.log`
+- ⏰ **Increases delay** for repeated failures
+
+### **If Internet Disconnects:**
+- 🔄 **Keeps trying** to reconnect
+- 📱 **Notifies you** when back online
+- 📊 **Preserves** all your trading data
+
+### **If Configuration Missing:**
+- ❌ **Stops safely** before starting
+- 💡 **Shows clear instructions** for setup
+- 📝 **Tells you exactly** what's missing
+
+## 📊 **Your Trading Data is Safe**
+
+### **Persistent Between Launches:**
+- ✅ Starting balance remembered
+- ✅ All trade history preserved
+- ✅ Performance metrics calculated
+- ✅ Risk analytics maintained
+- ✅ Win/loss streaks tracked
+
+### **Automatic Backups:**
+- 📝 Every trade logged to files
+- 📊 Statistics saved after each trade
+- 🔄 Daily log files created
+- 📱 Critical events sent to phone
+
+## 🎯 **Daily Usage**
+
+### **Start Bot:**
+```bash
+python trading_bot.py
+```
+
+### **Trade via Phone:**
+- Open Telegram → Find your bot
+- Send `/start` for quick buttons
+- Use `/buy 0.001 50000` to trade
+- Check `/stats` for performance
+
+### **Monitor:**
+- Bot sends error notifications automatically
+- Check `/stats` for trading performance
+- View logs: `tail -f logs/trading_bot_$(date +%Y%m%d).log`
+
+## 🔧 **Troubleshooting**
+
+### **"Configuration validation failed"**
+```bash
+cp config/env.example .env
+nano .env  # Add your keys
+```
+
+### **"Import error"**
+```bash
+source venv/bin/activate
+pip install -r requirements.txt
+```
+
+### **"Telegram not responding"**
+```bash
+python utils/get_telegram_chat_id.py  # Get correct Chat ID
+```
+
+## 💡 **Key Benefits**
+
+1. **🚀 One Command**: `python trading_bot.py` does everything
+2. **📊 Never Lose Data**: Statistics persist forever
+3. **🛡️ Self-Healing**: Auto-restarts on errors
+4. **📱 Phone Alerts**: Know about issues instantly
+5. **📝 Complete Audit**: Full logging of everything
+6. **⚙️ Foolproof Setup**: Clear validation and instructions
+
+**Your trading bot is now professional-grade with phone control and bulletproof reliability! 🚀📱** 

+ 270 - 0
README.md

@@ -0,0 +1,270 @@
+# 📱 Manual Hyperliquid Trading Bot
+
+**Control your Hyperliquid account from your phone with comprehensive trading statistics**
+
+This bot provides complete manual control of your Hyperliquid account via Telegram, with professional-grade statistics tracking including P&L, win rates, Sharpe ratio, Sortino ratio, and all the metrics you'd expect from a trading platform.
+
+## 🎯 What This Bot Does
+
+- 📱 **Phone Control**: Trade from anywhere using Telegram commands
+- 📊 **Comprehensive Stats**: Track all your performance metrics from day one
+- 💰 **Balance Tracking**: Monitor starting vs current balance with real-time P&L
+- 🏆 **Performance Metrics**: Win rate, profit factor, expectancy, consecutive wins/losses
+- 📈 **Risk Analysis**: Sharpe ratio, Sortino ratio, max drawdown, VaR (95%)
+- 🔄 **Trade History**: Complete trade logging with automatic P&L calculation
+- 🛡️ **Safety First**: Order confirmations, testnet mode, comprehensive logging
+
+## 🚀 Quick Start
+
+### 1. Install Dependencies
+```bash
+# Clone or download this repository
+cd trader_hyperliquid
+
+# Create virtual environment
+python3 -m venv venv
+source venv/bin/activate  # On Windows: venv\Scripts\activate
+
+# Install dependencies
+pip install -r requirements.txt
+```
+
+### 2. Set Up Telegram Bot
+1. **Create a bot**: Message [@BotFather](https://t.me/BotFather) on Telegram
+   - Send `/newbot`
+   - Choose a name and username for your bot
+   - Save the bot token
+
+2. **Get your Chat ID**: Run the helper script
+   ```bash
+   python get_telegram_chat_id.py
+   ```
+   - Start the script and message your bot
+   - Copy the displayed Chat ID
+
+### 3. Configure Environment
+```bash
+# Copy example configuration
+cp env.example .env
+
+# Edit .env with your details
+nano .env  # or use any text editor
+```
+
+**Required settings in `.env`:**
+```env
+# Hyperliquid API
+HYPERLIQUID_PRIVATE_KEY=your_private_key_here
+HYPERLIQUID_TESTNET=true
+
+# Telegram Bot
+TELEGRAM_ENABLED=true
+TELEGRAM_BOT_TOKEN=your_bot_token_here
+TELEGRAM_CHAT_ID=your_chat_id_here
+
+# Trading Settings
+DEFAULT_TRADING_SYMBOL=BTC/USDC:USDC
+DEFAULT_TRADE_AMOUNT=0.001
+```
+
+### 4. Start Manual Trading
+```bash
+python manual_trading_bot.py
+```
+
+## 📱 Using Your Trading Bot
+
+### Quick Actions (Buttons)
+Open Telegram → Find your bot → Send `/start`
+
+You'll see quick action buttons for:
+- 💰 **Balance** - Check account balance with P&L
+- 📊 **Stats** - Complete trading statistics  
+- 📈 **Positions** - Open positions with unrealized P&L
+- 📋 **Orders** - Pending orders
+- 💵 **Price** - Current market price
+- 🔄 **Recent Trades** - Your trade history
+
+### Manual Trading Commands
+
+**Place Orders:**
+```
+/buy 0.001 50000    # Buy 0.001 BTC at $50,000
+/sell 0.001 55000   # Sell 0.001 BTC at $55,000
+```
+
+**Monitor Account:**
+```
+/balance     # Account balance + P&L summary
+/positions   # Open positions
+/orders      # Pending orders
+/trades      # Recent trade history
+```
+
+**View Statistics:**
+```
+/stats       # Complete trading statistics
+```
+
+## 📊 Trading Statistics Tracked
+
+### Balance & P&L
+- 💰 **Starting Balance**: Recorded when bot first launches
+- 💵 **Current Balance**: Real-time balance updates
+- 📈 **Total P&L**: Profit/Loss in USD and percentage
+- 📅 **Days Active**: Time since first launch
+
+### Performance Metrics  
+- 🏆 **Win Rate**: Percentage of profitable trades
+- 💎 **Profit Factor**: Total gains ÷ Total losses
+- �� **Average Win/Loss**: Mean profit/loss per trade
+- 🎯 **Expectancy**: Expected value per trade
+- 🔥 **Consecutive Wins/Losses**: Streak tracking
+
+### Risk Metrics
+- 📊 **Sharpe Ratio**: Risk-adjusted returns
+- 📉 **Sortino Ratio**: Downside risk-adjusted returns  
+- 📈 **Max Drawdown**: Largest peak-to-trough decline
+- 🌪️ **Volatility**: Annualized price volatility
+- ⚠️ **VaR (95%)**: Value at Risk (95% confidence)
+
+### Trade Analytics
+- 📝 **Total Trades**: Complete trade count
+- 🔄 **Buy/Sell Breakdown**: Order type distribution
+- 🎯 **Best/Worst Trades**: Largest wins and losses
+- 📊 **Trade History**: Complete audit trail with order IDs
+
+## 🛡️ Safety Features
+
+### Testnet First
+- Starts in testnet mode by default
+- Test all features before using real money
+- Clear warnings when switching to mainnet
+
+### Order Confirmations
+- All trades require explicit confirmation
+- Clear order details before execution
+- Easy cancellation option
+
+### Comprehensive Logging
+- All actions logged with timestamps
+- Trade history automatically saved
+- Statistics persist between bot restarts
+
+### Risk Management
+- Balance tracking for drawdown monitoring
+- Real-time P&L calculations
+- Risk metrics to assess performance
+
+## 📈 Sample Statistics Output
+
+```
+📊 Trading Statistics
+
+💰 Balance Overview
+• Initial: $1,000.00
+• Current: $1,150.00  
+• Total P&L: $150.00
+• Total Return: 15.00%
+
+📈 Trading Activity
+• Total Trades: 25
+• Buy Orders: 13
+• Sell Orders: 12
+• Days Active: 30
+
+🏆 Performance Metrics
+• Win Rate: 68.0%
+• Profit Factor: 2.15
+• Avg Win: $45.50
+• Avg Loss: $28.75
+• Expectancy: $6.25
+
+📊 Risk Metrics
+• Sharpe Ratio: 1.85
+• Sortino Ratio: 2.41
+• Max Drawdown: 8.5%
+• Volatility: 12.3%
+• VaR (95%): 3.2%
+
+🎯 Best/Worst
+• Largest Win: $125.00
+• Largest Loss: $75.00
+• Max Consecutive Wins: 5
+• Max Consecutive Losses: 2
+
+📅 Since: 2024-01-15
+```
+
+## 🔧 Files Overview
+
+| File | Purpose |
+|------|---------|
+| `manual_trading_bot.py` | **Main launcher** - Start this for manual trading |
+| `telegram_bot.py` | Telegram interface with trading commands |
+| `trading_stats.py` | Comprehensive statistics tracking |
+| `hyperliquid_client.py` | Hyperliquid API wrapper |
+| `config.py` | Configuration management |
+| `get_telegram_chat_id.py` | Helper to find your Chat ID |
+| `trading_stats.json` | Your trading statistics (auto-created) |
+
+## ⚙️ Advanced Configuration
+
+### Custom Trading Symbol
+```env
+DEFAULT_TRADING_SYMBOL=ETH/USDC:USDC
+```
+
+### Adjust Default Trade Size
+```env
+DEFAULT_TRADE_AMOUNT=0.01
+```
+
+### Logging Level
+```env
+LOG_LEVEL=INFO  # DEBUG, INFO, WARNING, ERROR
+```
+
+## 🔍 Troubleshooting
+
+### Bot Won't Start
+```bash
+# Check configuration
+python -c "from config import Config; Config.validate()"
+
+# Check Telegram setup
+python get_telegram_chat_id.py
+```
+
+### Telegram Not Responding
+1. Verify bot token with BotFather
+2. Ensure Chat ID is correct
+3. Check that bot is started in Telegram
+
+### Trading Issues
+1. Confirm sufficient balance
+2. Check order parameters
+3. Verify network connectivity
+
+## 🌐 Network Modes
+
+### Testnet (Default)
+- Safe testing environment
+- No real money at risk
+- Perfect for learning
+
+### Mainnet (Production)
+- Real money trading
+- Requires explicit confirmation
+- Use with caution
+
+## 📞 Support
+
+This bot is designed for manual trading control via phone. All features are focused on giving you complete control over your Hyperliquid account with professional-grade statistics tracking.
+
+For technical issues:
+1. Check configuration with validation commands
+2. Review log files for error details
+3. Ensure all dependencies are installed
+
+**Happy trading! 🚀📱** 

+ 189 - 0
SETUP_GUIDE.md

@@ -0,0 +1,189 @@
+# 📱 Quick Setup Guide - Manual Trading Bot
+
+## 🎯 What You're Getting
+
+**Complete manual control of your Hyperliquid account from your phone with professional trading statistics.**
+
+✅ **Phone Trading**: Buy/sell from anywhere via Telegram  
+✅ **Full Statistics**: Win rate, Sharpe ratio, Sortino, P&L, drawdown, etc.  
+✅ **Balance Tracking**: Starting balance vs current with % returns  
+✅ **Trade History**: Every trade logged with automatic P&L calculation  
+✅ **Risk Metrics**: Professional-grade performance analytics  
+✅ **Safe Default**: Starts in testnet mode  
+
+## 🚀 5-Minute Setup
+
+### Step 1: Create Telegram Bot (2 minutes)
+
+1. **Open Telegram** → Search **@BotFather**
+2. Send: `/newbot`
+3. **Name your bot**: "My Trading Bot" 
+4. **Username**: something like `mytradingbot_123_bot`
+5. **Save the token** (looks like: `123456789:ABCdefGHIjklMNOPqrs`)
+
+### Step 2: Get Your Chat ID (1 minute)
+
+```bash
+# In your terminal
+python get_telegram_chat_id.py
+```
+
+- **Message your bot** anything in Telegram
+- **Copy the Chat ID** from terminal output
+
+### Step 3: Configure Bot (2 minutes)
+
+```bash
+# Copy example config
+cp env.example .env
+
+# Edit with your info (use any text editor)
+nano .env
+```
+
+**Set these 4 things in `.env`:**
+```env
+HYPERLIQUID_PRIVATE_KEY=your_private_key_here
+TELEGRAM_BOT_TOKEN=your_token_from_botfather
+TELEGRAM_CHAT_ID=your_chat_id_from_script
+TELEGRAM_ENABLED=true
+```
+
+### Step 4: Start Trading! 
+
+```bash
+python manual_trading_bot.py
+```
+
+**That's it!** 🎉 Open Telegram and send `/start` to your bot.
+
+## 📱 What You Can Do
+
+### Instant Commands
+- `/balance` - Check balance + P&L
+- `/stats` - Complete trading statistics  
+- `/buy 0.001 50000` - Buy 0.001 BTC at $50,000
+- `/sell 0.001 55000` - Sell 0.001 BTC at $55,000
+- `/positions` - Open positions
+- `/orders` - Pending orders
+
+### Quick Buttons
+Send `/start` to see instant action buttons for one-tap:
+- 💰 Balance, 📊 Stats, 📈 Positions, 📋 Orders, 💵 Price
+
+## 📊 Statistics You Get
+
+**From the moment you first launch, the bot tracks:**
+
+```
+📊 Trading Statistics
+
+💰 Balance Overview
+• Initial: $1,000.00        ← Your starting balance
+• Current: $1,150.00        ← Real-time balance  
+• Total P&L: $150.00        ← Profit/Loss
+• Total Return: 15.00%      ← % return
+
+📈 Trading Activity  
+• Total Trades: 25          ← Complete count
+• Buy Orders: 13            ← Trade breakdown
+• Sell Orders: 12
+• Days Active: 30           ← Time since first launch
+
+🏆 Performance Metrics
+• Win Rate: 68.0%           ← % profitable trades
+• Profit Factor: 2.15       ← Gains ÷ Losses  
+• Avg Win: $45.50           ← Average profitable trade
+• Avg Loss: $28.75          ← Average losing trade
+• Expectancy: $6.25         ← Expected $ per trade
+
+📊 Risk Metrics
+• Sharpe Ratio: 1.85        ← Risk-adjusted returns
+• Sortino Ratio: 2.41       ← Downside risk metric
+• Max Drawdown: 8.5%        ← Worst decline from peak
+• Volatility: 12.3%         ← Price volatility  
+• VaR (95%): 3.2%          ← Value at Risk
+
+🎯 Best/Worst
+• Largest Win: $125.00      ← Best single trade
+• Largest Loss: $75.00      ← Worst single trade
+• Max Consecutive Wins: 5   ← Winning streaks
+• Max Consecutive Losses: 2 ← Losing streaks
+```
+
+## 🛡️ Safety Features
+
+### ✅ Testnet First
+- **Starts in testnet by default** (fake money)
+- Test everything before real trading
+- Switch to mainnet when ready
+
+### ✅ Order Confirmations  
+- **Every trade needs confirmation**
+- Clear order details shown
+- Easy cancel button
+
+### ✅ Complete Logging
+- All trades automatically recorded
+- Statistics saved between restarts
+- Full audit trail with order IDs
+
+## 🔧 Where Are Your Keys?
+
+### Hyperliquid Private Key
+**Testnet** (for learning): 
+1. Go to [Hyperliquid Testnet](https://app.hyperliquid-testnet.xyz/)
+2. Create/connect wallet → Export private key
+
+**Mainnet** (real money):
+1. Go to [Hyperliquid](https://app.hyperliquid.xyz/) 
+2. Connect wallet → Export private key
+
+⚠️ **Keep private keys secure** - never share them!
+
+## 🎮 Try the Demo
+
+See what your statistics will look like:
+```bash
+python demo_stats.py
+```
+
+This creates sample trading data so you can see all the metrics the bot tracks.
+
+## 🔍 Troubleshooting
+
+### "Configuration validation failed"
+- Check your `.env` file has all 4 required fields
+- Make sure `TELEGRAM_ENABLED=true`
+
+### "Telegram bot not responding"  
+- Verify bot token from @BotFather
+- Check Chat ID from `get_telegram_chat_id.py`
+- Make sure you messaged your bot first
+
+### "Private key not set"
+- Get private key from Hyperliquid (see above)
+- Add to `.env` file
+
+## 🎯 Quick Commands Reference
+
+```bash
+# Setup
+python get_telegram_chat_id.py    # Get Chat ID
+python demo_stats.py              # See sample statistics  
+python manual_trading_bot.py      # Start trading bot
+
+# Test configuration  
+python -c "from config import Config; Config.validate()"
+```
+
+## 📈 What Makes This Special
+
+- **No coding required** - Just use Telegram commands
+- **Professional analytics** - Same metrics as trading platforms  
+- **Phone optimized** - Trade from anywhere
+- **Comprehensive tracking** - Every stat you need
+- **Persistent data** - Statistics saved between sessions
+- **Safe by default** - Testnet mode prevents accidents
+
+**You get institutional-grade trading analytics with simple phone control! 🚀📱** 

+ 19 - 0
config/env.example

@@ -0,0 +1,19 @@
+# Hyperliquid API Configuration
+HYPERLIQUID_PRIVATE_KEY=your_private_key_here
+HYPERLIQUID_TESTNET=true
+
+# Trading Bot Configuration
+DEFAULT_TRADING_SYMBOL=BTC/USDC:USDC
+DEFAULT_TRADE_AMOUNT=0.001
+RISK_MANAGEMENT_ENABLED=true
+MAX_POSITION_SIZE=100
+STOP_LOSS_PERCENTAGE=2.0
+TAKE_PROFIT_PERCENTAGE=5.0
+
+# Telegram Bot Configuration
+TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here
+TELEGRAM_CHAT_ID=your_chat_id_here
+TELEGRAM_ENABLED=true
+
+# Logging
+LOG_LEVEL=INFO 

+ 133 - 0
demo_stats.py

@@ -0,0 +1,133 @@
+#!/usr/bin/env python3
+"""
+Trading Statistics Demo
+
+Shows sample trading statistics to demonstrate what the bot tracks.
+"""
+
+from trading_stats import TradingStats
+from datetime import datetime, timedelta
+import random
+
+def create_demo_stats():
+    """Create demo trading statistics."""
+    print("📊 Creating Demo Trading Statistics...\n")
+    
+    # Create stats instance with demo file
+    stats = TradingStats("demo_stats.json")
+    
+    # Set initial balance
+    initial_balance = 1000.0
+    stats.set_initial_balance(initial_balance)
+    
+    # Simulate some trades over 30 days
+    current_balance = initial_balance
+    base_time = datetime.now() - timedelta(days=30)
+    
+    print("🎲 Simulating 30 days of trading...")
+    
+    # Generate sample trades
+    symbols = ["BTC/USDC:USDC", "ETH/USDC:USDC"]
+    
+    for day in range(30):
+        date = base_time + timedelta(days=day)
+        
+        # 70% chance of trading each day
+        if random.random() < 0.7:
+            # 1-3 trades per day
+            num_trades = random.randint(1, 3)
+            
+            for _ in range(num_trades):
+                symbol = random.choice(symbols)
+                
+                # Simulate buy trade
+                if symbol == "BTC/USDC:USDC":
+                    price = random.uniform(45000, 55000)
+                    amount = random.uniform(0.001, 0.01)
+                else:  # ETH
+                    price = random.uniform(2800, 3200)
+                    amount = random.uniform(0.01, 0.1)
+                
+                trade_value = amount * price
+                
+                # Record buy
+                stats.data['trades'].append({
+                    'timestamp': date.isoformat(),
+                    'symbol': symbol,
+                    'side': 'buy',
+                    'amount': amount,
+                    'price': price,
+                    'value': trade_value,
+                    'order_id': f'demo_{len(stats.data["trades"])}',
+                    'type': 'manual',
+                    'pnl': 0.0
+                })
+                
+                # Sometimes sell (60% chance)
+                if random.random() < 0.6:
+                    # Sell at slightly different price
+                    sell_price = price * random.uniform(0.98, 1.05)  # -2% to +5%
+                    pnl = amount * (sell_price - price)
+                    current_balance += pnl
+                    
+                    sell_date = date + timedelta(hours=random.randint(1, 12))
+                    
+                    stats.data['trades'].append({
+                        'timestamp': sell_date.isoformat(),
+                        'symbol': symbol,
+                        'side': 'sell',
+                        'amount': amount,
+                        'price': sell_price,
+                        'value': amount * sell_price,
+                        'order_id': f'demo_{len(stats.data["trades"])}',
+                        'type': 'manual',
+                        'pnl': pnl
+                    })
+        
+        # Record daily balance
+        daily_variance = random.uniform(-20, 30)  # Daily balance change
+        current_balance += daily_variance
+        
+        stats.data['daily_balances'].append({
+            'date': date.date().isoformat(),
+            'balance': current_balance,
+            'timestamp': date.isoformat()
+        })
+    
+    # Save the demo data
+    stats._save_stats()
+    
+    return stats, current_balance
+
+def main():
+    """Main demo function."""
+    print("🎮 Trading Statistics Demo\n")
+    print("This shows what your bot will track when you start trading manually.\n")
+    
+    # Create demo data
+    stats, current_balance = create_demo_stats()
+    
+    # Display statistics
+    print("📈 Sample Trading Statistics:\n")
+    stats_message = stats.format_stats_message(current_balance)
+    
+    # Convert HTML to plain text for terminal display
+    plain_message = stats_message.replace('<b>', '').replace('</b>', '')
+    plain_message = plain_message.replace('<i>', '').replace('</i>', '')
+    
+    print(plain_message)
+    
+    print("\n" + "="*60)
+    print("🎯 What This Means:")
+    print("✅ Your bot will track ALL these metrics automatically")
+    print("📱 View anytime on your phone with /stats command")
+    print("💾 Statistics persist between bot restarts")
+    print("🔄 Every manual trade updates your performance metrics")
+    print("📊 Professional-grade analytics from day one")
+    print("="*60)
+    
+    print(f"\n📁 Demo data saved to: demo_stats.json")
+    print("🗑️  You can delete this file - it's just for demonstration")
+
+if __name__ == "__main__":
+    main() 

+ 5 - 0
requirements.txt

@@ -0,0 +1,5 @@
+hyperliquid==0.4.66
+python-telegram-bot[webhooks]==20.7
+python-dotenv==1.1.0
+pandas==2.2.3
+numpy==2.2.6 

+ 1 - 0
src/__init__.py

@@ -0,0 +1 @@
+# Trading Bot Package 

+ 64 - 0
src/config.py

@@ -0,0 +1,64 @@
+import os
+from dotenv import load_dotenv
+from typing import Optional
+
+# Load environment variables from .env file
+load_dotenv()
+
+class Config:
+    """Configuration class for the Hyperliquid trading bot."""
+    
+    # Hyperliquid API Configuration
+    HYPERLIQUID_PRIVATE_KEY: Optional[str] = os.getenv('HYPERLIQUID_PRIVATE_KEY')
+    HYPERLIQUID_TESTNET: bool = os.getenv('HYPERLIQUID_TESTNET', 'true').lower() == 'true'
+    
+    # Trading Bot Configuration
+    DEFAULT_TRADING_SYMBOL: str = os.getenv('DEFAULT_TRADING_SYMBOL', 'BTC/USDC:USDC')
+    DEFAULT_TRADE_AMOUNT: float = float(os.getenv('DEFAULT_TRADE_AMOUNT', '0.001'))
+    RISK_MANAGEMENT_ENABLED: bool = os.getenv('RISK_MANAGEMENT_ENABLED', 'true').lower() == 'true'
+    MAX_POSITION_SIZE: float = float(os.getenv('MAX_POSITION_SIZE', '100'))
+    STOP_LOSS_PERCENTAGE: float = float(os.getenv('STOP_LOSS_PERCENTAGE', '2.0'))
+    TAKE_PROFIT_PERCENTAGE: float = float(os.getenv('TAKE_PROFIT_PERCENTAGE', '5.0'))
+    
+    # Telegram Bot Configuration
+    TELEGRAM_BOT_TOKEN: Optional[str] = os.getenv('TELEGRAM_BOT_TOKEN')
+    TELEGRAM_CHAT_ID: Optional[str] = os.getenv('TELEGRAM_CHAT_ID')
+    TELEGRAM_ENABLED: bool = os.getenv('TELEGRAM_ENABLED', 'false').lower() == 'true'
+    
+    # Logging
+    LOG_LEVEL: str = os.getenv('LOG_LEVEL', 'INFO')
+    
+    @classmethod
+    def validate(cls) -> bool:
+        """Validate that required configuration is present."""
+        if not cls.HYPERLIQUID_PRIVATE_KEY:
+            print("❌ HYPERLIQUID_PRIVATE_KEY is required")
+            return False
+        
+        if cls.TELEGRAM_ENABLED and not cls.TELEGRAM_BOT_TOKEN:
+            print("❌ TELEGRAM_BOT_TOKEN is required when TELEGRAM_ENABLED=true")
+            return False
+        
+        if cls.TELEGRAM_ENABLED and not cls.TELEGRAM_CHAT_ID:
+            print("❌ TELEGRAM_CHAT_ID is required when TELEGRAM_ENABLED=true")
+            return False
+        
+        print("✅ Configuration is valid")
+        return True
+    
+    @classmethod
+    def print_config(cls):
+        """Print current configuration (hiding sensitive data)."""
+        print("🔧 Current Configuration:")
+        print(f"  HYPERLIQUID_TESTNET: {cls.HYPERLIQUID_TESTNET}")
+        print(f"  DEFAULT_TRADING_SYMBOL: {cls.DEFAULT_TRADING_SYMBOL}")
+        print(f"  DEFAULT_TRADE_AMOUNT: {cls.DEFAULT_TRADE_AMOUNT}")
+        print(f"  RISK_MANAGEMENT_ENABLED: {cls.RISK_MANAGEMENT_ENABLED}")
+        print(f"  MAX_POSITION_SIZE: {cls.MAX_POSITION_SIZE}")
+        print(f"  STOP_LOSS_PERCENTAGE: {cls.STOP_LOSS_PERCENTAGE}%")
+        print(f"  TAKE_PROFIT_PERCENTAGE: {cls.TAKE_PROFIT_PERCENTAGE}%")
+        print(f"  TELEGRAM_ENABLED: {cls.TELEGRAM_ENABLED}")
+        print(f"  LOG_LEVEL: {cls.LOG_LEVEL}")
+        print(f"  PRIVATE_KEY: {'✅ Set' if cls.HYPERLIQUID_PRIVATE_KEY else '❌ Not Set'}")
+        print(f"  TELEGRAM_BOT_TOKEN: {'✅ Set' if cls.TELEGRAM_BOT_TOKEN else '❌ Not Set'}")
+        print(f"  TELEGRAM_CHAT_ID: {'✅ Set' if cls.TELEGRAM_CHAT_ID else '❌ Not Set'}") 

+ 187 - 0
src/hyperliquid_client.py

@@ -0,0 +1,187 @@
+import asyncio
+import logging
+from typing import Optional, Dict, Any, List
+from hyperliquid import HyperliquidSync, HyperliquidAsync
+from config import Config
+
+# Set up logging
+logging.basicConfig(level=getattr(logging, Config.LOG_LEVEL))
+logger = logging.getLogger(__name__)
+
+class HyperliquidClient:
+    """Wrapper class for Hyperliquid API client with enhanced functionality."""
+    
+    def __init__(self, use_testnet: bool = True):
+        """
+        Initialize the Hyperliquid client.
+        
+        Args:
+            use_testnet: Whether to use testnet (default: True for safety)
+        """
+        self.use_testnet = use_testnet
+        self.config = {
+            'private_key': Config.HYPERLIQUID_PRIVATE_KEY,
+            'testnet': use_testnet
+        }
+        
+        # Initialize sync client
+        self.sync_client = None
+        self.async_client = None
+        
+        if Config.HYPERLIQUID_PRIVATE_KEY:
+            try:
+                self.sync_client = HyperliquidSync(self.config)
+                logger.info(f"✅ Hyperliquid client initialized (testnet: {use_testnet})")
+            except Exception as e:
+                logger.error(f"❌ Failed to initialize Hyperliquid client: {e}")
+        else:
+            logger.warning("⚠️ No private key provided - client will have limited functionality")
+    
+    def get_balance(self) -> Optional[Dict[str, Any]]:
+        """Get account balance."""
+        try:
+            if not self.sync_client:
+                logger.error("❌ Client not initialized")
+                return None
+            
+            balance = self.sync_client.fetch_balance()
+            logger.info("✅ Successfully fetched balance")
+            return balance
+        except Exception as e:
+            logger.error(f"❌ Error fetching balance: {e}")
+            return None
+    
+    def get_positions(self, symbol: Optional[str] = None) -> Optional[List[Dict[str, Any]]]:
+        """Get current positions."""
+        try:
+            if not self.sync_client:
+                logger.error("❌ Client not initialized")
+                return None
+            
+            positions = self.sync_client.fetch_positions([symbol] if symbol else None)
+            logger.info(f"✅ Successfully fetched positions for {symbol or 'all symbols'}")
+            return positions
+        except Exception as e:
+            logger.error(f"❌ Error fetching positions: {e}")
+            return None
+    
+    def get_market_data(self, symbol: str) -> Optional[Dict[str, Any]]:
+        """Get market data for a symbol."""
+        try:
+            if not self.sync_client:
+                logger.error("❌ Client not initialized")
+                return None
+            
+            ticker = self.sync_client.fetch_ticker(symbol)
+            orderbook = self.sync_client.fetch_order_book(symbol)
+            
+            market_data = {
+                'ticker': ticker,
+                'orderbook': orderbook,
+                'symbol': symbol
+            }
+            
+            logger.info(f"✅ Successfully fetched market data for {symbol}")
+            return market_data
+        except Exception as e:
+            logger.error(f"❌ Error fetching market data for {symbol}: {e}")
+            return None
+    
+    def place_limit_order(self, symbol: str, side: str, amount: float, price: float) -> Optional[Dict[str, Any]]:
+        """
+        Place a limit order.
+        
+        Args:
+            symbol: Trading symbol (e.g., 'BTC/USDC:USDC')
+            side: 'buy' or 'sell'
+            amount: Order amount
+            price: Order price
+        """
+        try:
+            if not self.sync_client:
+                logger.error("❌ Client not initialized")
+                return None
+            
+            order = self.sync_client.create_limit_order(symbol, side, amount, price)
+            logger.info(f"✅ Successfully placed {side} limit order for {amount} {symbol} at ${price}")
+            return order
+        except Exception as e:
+            logger.error(f"❌ Error placing limit order: {e}")
+            return None
+    
+    def place_market_order(self, symbol: str, side: str, amount: float) -> Optional[Dict[str, Any]]:
+        """
+        Place a market order.
+        
+        Args:
+            symbol: Trading symbol (e.g., 'BTC/USDC:USDC')
+            side: 'buy' or 'sell'
+            amount: Order amount
+        """
+        try:
+            if not self.sync_client:
+                logger.error("❌ Client not initialized")
+                return None
+            
+            order = self.sync_client.create_market_order(symbol, side, amount)
+            logger.info(f"✅ Successfully placed {side} market order for {amount} {symbol}")
+            return order
+        except Exception as e:
+            logger.error(f"❌ Error placing market order: {e}")
+            return None
+    
+    def get_open_orders(self, symbol: Optional[str] = None) -> Optional[List[Dict[str, Any]]]:
+        """Get open orders."""
+        try:
+            if not self.sync_client:
+                logger.error("❌ Client not initialized")
+                return None
+            
+            orders = self.sync_client.fetch_open_orders(symbol)
+            logger.info(f"✅ Successfully fetched open orders for {symbol or 'all symbols'}")
+            return orders
+        except Exception as e:
+            logger.error(f"❌ Error fetching open orders: {e}")
+            return None
+    
+    def cancel_order(self, order_id: str, symbol: str) -> bool:
+        """Cancel an order."""
+        try:
+            if not self.sync_client:
+                logger.error("❌ Client not initialized")
+                return False
+            
+            result = self.sync_client.cancel_order(order_id, symbol)
+            logger.info(f"✅ Successfully cancelled order {order_id}")
+            return True
+        except Exception as e:
+            logger.error(f"❌ Error cancelling order {order_id}: {e}")
+            return False
+    
+    def get_recent_trades(self, symbol: str, limit: int = 10) -> Optional[List[Dict[str, Any]]]:
+        """Get recent trades for a symbol."""
+        try:
+            if not self.sync_client:
+                logger.error("❌ Client not initialized")
+                return None
+            
+            trades = self.sync_client.fetch_trades(symbol, limit=limit)
+            logger.info(f"✅ Successfully fetched {len(trades)} recent trades for {symbol}")
+            return trades
+        except Exception as e:
+            logger.error(f"❌ Error fetching recent trades for {symbol}: {e}")
+            return None
+    
+    def get_trading_fee(self, symbol: str) -> Optional[Dict[str, Any]]:
+        """Get trading fee for a symbol."""
+        try:
+            if not self.sync_client:
+                logger.error("❌ Client not initialized")
+                return None
+            
+            fee = self.sync_client.fetch_trading_fee(symbol)
+            logger.info(f"✅ Successfully fetched trading fee for {symbol}")
+            return fee
+        except Exception as e:
+            logger.error(f"❌ Error fetching trading fee for {symbol}: {e}")
+            return None 

+ 703 - 0
src/telegram_bot.py

@@ -0,0 +1,703 @@
+#!/usr/bin/env python3
+"""
+Telegram Bot for Hyperliquid Trading
+
+This module provides a Telegram interface for manual Hyperliquid trading
+with comprehensive statistics tracking and phone-friendly controls.
+"""
+
+import logging
+import asyncio
+import re
+from datetime import datetime
+from typing import Optional, Dict, Any
+from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
+from telegram.ext import Application, CommandHandler, CallbackQueryHandler, ContextTypes, MessageHandler, filters
+from hyperliquid_client import HyperliquidClient
+from trading_stats import TradingStats
+from config import Config
+
+# Set up logging
+logging.basicConfig(
+    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
+    level=getattr(logging, Config.LOG_LEVEL)
+)
+logger = logging.getLogger(__name__)
+
+class TelegramTradingBot:
+    """Telegram bot for manual trading with comprehensive statistics."""
+    
+    def __init__(self):
+        """Initialize the Telegram trading bot."""
+        self.client = HyperliquidClient(use_testnet=Config.HYPERLIQUID_TESTNET)
+        self.stats = TradingStats()
+        self.authorized_chat_id = Config.TELEGRAM_CHAT_ID
+        self.application = None
+        
+        # Initialize stats with current balance
+        self._initialize_stats()
+        
+    def _initialize_stats(self):
+        """Initialize stats with current balance."""
+        try:
+            balance = self.client.get_balance()
+            if balance and balance.get('total'):
+                # Get USDC balance as the main balance
+                usdc_balance = float(balance['total'].get('USDC', 0))
+                self.stats.set_initial_balance(usdc_balance)
+        except Exception as e:
+            logger.error(f"Could not initialize stats: {e}")
+        
+    def is_authorized(self, chat_id: str) -> bool:
+        """Check if the chat ID is authorized to use the bot."""
+        return str(chat_id) == str(self.authorized_chat_id)
+    
+    async def send_message(self, text: str, parse_mode: str = 'HTML') -> None:
+        """Send a message to the authorized chat."""
+        if self.application and self.authorized_chat_id:
+            try:
+                await self.application.bot.send_message(
+                    chat_id=self.authorized_chat_id,
+                    text=text,
+                    parse_mode=parse_mode
+                )
+            except Exception as e:
+                logger.error(f"Failed to send message: {e}")
+    
+    async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /start command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        welcome_text = """
+🤖 <b>Hyperliquid Manual Trading Bot</b>
+
+Welcome to your personal trading assistant! Control your Hyperliquid account directly from your phone.
+
+<b>📱 Quick Actions:</b>
+Tap the buttons below for instant access to key functions.
+
+<b>💼 Account Commands:</b>
+/balance - Account balance
+/positions - Open positions
+/orders - Open orders
+/stats - Trading statistics
+
+<b>📊 Market Commands:</b>
+/market - Market data
+/price - Current price
+
+<b>🔄 Trading Commands:</b>
+/buy [amount] [price] - Buy order
+/sell [amount] [price] - Sell order
+/trades - Recent trades
+/cancel [order_id] - Cancel order
+
+<b>📈 Statistics:</b>
+/stats - Full trading statistics
+/performance - Performance metrics
+/risk - Risk analysis
+
+Type /help for detailed command information.
+        """
+        
+        keyboard = [
+            [
+                InlineKeyboardButton("💰 Balance", callback_data="balance"),
+                InlineKeyboardButton("📊 Stats", callback_data="stats")
+            ],
+            [
+                InlineKeyboardButton("📈 Positions", callback_data="positions"),
+                InlineKeyboardButton("📋 Orders", callback_data="orders")
+            ],
+            [
+                InlineKeyboardButton("💵 Price", callback_data="price"),
+                InlineKeyboardButton("📊 Market", callback_data="market")
+            ],
+            [
+                InlineKeyboardButton("🔄 Recent Trades", callback_data="trades"),
+                InlineKeyboardButton("⚙️ Help", callback_data="help")
+            ]
+        ]
+        reply_markup = InlineKeyboardMarkup(keyboard)
+        
+        await update.message.reply_text(welcome_text, parse_mode='HTML', reply_markup=reply_markup)
+    
+    async def help_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /help command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        help_text = """
+🔧 <b>Hyperliquid Trading Bot - Complete Guide</b>
+
+<b>💼 Account Management:</b>
+• /balance - Show account balance
+• /positions - Show open positions  
+• /orders - Show open orders
+
+<b>📊 Market Data:</b>
+• /market - Detailed market data
+• /price - Quick price check
+
+<b>🔄 Manual Trading:</b>
+• /buy 0.001 50000 - Buy 0.001 BTC at $50,000
+• /sell 0.001 55000 - Sell 0.001 BTC at $55,000
+• /cancel ABC123 - Cancel order with ID ABC123
+
+<b>📈 Statistics & Analytics:</b>
+• /stats - Complete trading statistics
+• /performance - Win rate, profit factor, etc.
+• /risk - Sharpe ratio, drawdown, VaR
+• /trades - Recent trade history
+
+<b>⚙️ Configuration:</b>
+• Symbol: {symbol}
+• Default Amount: {amount}
+• Network: {network}
+
+<b>🛡️ Safety Features:</b>
+• All trades logged automatically
+• Comprehensive performance tracking
+• Real-time balance monitoring
+• Risk metrics calculation
+
+<b>📱 Mobile Optimized:</b>
+• Quick action buttons
+• Instant notifications
+• Clean, readable layout
+• One-tap commands
+
+For support, contact your bot administrator.
+        """.format(
+            symbol=Config.DEFAULT_TRADING_SYMBOL,
+            amount=Config.DEFAULT_TRADE_AMOUNT,
+            network="Testnet" if Config.HYPERLIQUID_TESTNET else "Mainnet"
+        )
+        
+        await update.message.reply_text(help_text, parse_mode='HTML')
+    
+    async def stats_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /stats command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        # Get current balance for stats
+        balance = self.client.get_balance()
+        current_balance = 0
+        if balance and balance.get('total'):
+            current_balance = float(balance['total'].get('USDC', 0))
+        
+        stats_message = self.stats.format_stats_message(current_balance)
+        await update.message.reply_text(stats_message, parse_mode='HTML')
+    
+    async def buy_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /buy command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        try:
+            if len(context.args) < 2:
+                await update.message.reply_text(
+                    "❌ Usage: /buy [amount] [price]\n"
+                    f"Example: /buy {Config.DEFAULT_TRADE_AMOUNT} 50000"
+                )
+                return
+            
+            amount = float(context.args[0])
+            price = float(context.args[1])
+            symbol = Config.DEFAULT_TRADING_SYMBOL
+            
+            # Confirmation message
+            confirmation_text = f"""
+🟢 <b>Buy Order Confirmation</b>
+
+📊 <b>Order Details:</b>
+• Symbol: {symbol}
+• Side: BUY
+• Amount: {amount}
+• Price: ${price:,.2f}
+• Total Value: ${amount * price:,.2f}
+
+⚠️ <b>Are you sure you want to place this order?</b>
+
+This will attempt to buy {amount} {symbol} at ${price:,.2f} per unit.
+            """
+            
+            keyboard = [
+                [
+                    InlineKeyboardButton("✅ Confirm Buy", callback_data=f"confirm_buy_{amount}_{price}"),
+                    InlineKeyboardButton("❌ Cancel", callback_data="cancel_order")
+                ]
+            ]
+            reply_markup = InlineKeyboardMarkup(keyboard)
+            
+            await update.message.reply_text(confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
+            
+        except ValueError:
+            await update.message.reply_text("❌ Invalid amount or price. Please use numbers only.")
+        except Exception as e:
+            await update.message.reply_text(f"❌ Error processing buy command: {e}")
+    
+    async def sell_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /sell command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        try:
+            if len(context.args) < 2:
+                await update.message.reply_text(
+                    "❌ Usage: /sell [amount] [price]\n"
+                    f"Example: /sell {Config.DEFAULT_TRADE_AMOUNT} 55000"
+                )
+                return
+            
+            amount = float(context.args[0])
+            price = float(context.args[1])
+            symbol = Config.DEFAULT_TRADING_SYMBOL
+            
+            # Confirmation message
+            confirmation_text = f"""
+🔴 <b>Sell Order Confirmation</b>
+
+📊 <b>Order Details:</b>
+• Symbol: {symbol}
+• Side: SELL
+• Amount: {amount}
+• Price: ${price:,.2f}
+• Total Value: ${amount * price:,.2f}
+
+⚠️ <b>Are you sure you want to place this order?</b>
+
+This will attempt to sell {amount} {symbol} at ${price:,.2f} per unit.
+            """
+            
+            keyboard = [
+                [
+                    InlineKeyboardButton("✅ Confirm Sell", callback_data=f"confirm_sell_{amount}_{price}"),
+                    InlineKeyboardButton("❌ Cancel", callback_data="cancel_order")
+                ]
+            ]
+            reply_markup = InlineKeyboardMarkup(keyboard)
+            
+            await update.message.reply_text(confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
+            
+        except ValueError:
+            await update.message.reply_text("❌ Invalid amount or price. Please use numbers only.")
+        except Exception as e:
+            await update.message.reply_text(f"❌ Error processing sell command: {e}")
+    
+    async def trades_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /trades command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        recent_trades = self.stats.get_recent_trades(10)
+        
+        if not recent_trades:
+            await update.message.reply_text("📝 No trades recorded yet.")
+            return
+        
+        trades_text = "🔄 <b>Recent Trades</b>\n\n"
+        
+        for trade in reversed(recent_trades[-5:]):  # Show last 5 trades
+            timestamp = datetime.fromisoformat(trade['timestamp']).strftime('%m/%d %H:%M')
+            side_emoji = "🟢" if trade['side'] == 'buy' else "🔴"
+            
+            trades_text += f"{side_emoji} <b>{trade['side'].upper()}</b> {trade['amount']} {trade['symbol']}\n"
+            trades_text += f"   💰 ${trade['price']:,.2f} | 💵 ${trade['value']:,.2f}\n"
+            trades_text += f"   📅 {timestamp}\n\n"
+        
+        await update.message.reply_text(trades_text, parse_mode='HTML')
+    
+    async def balance_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /balance command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        balance = self.client.get_balance()
+        if balance:
+            balance_text = "💰 <b>Account Balance</b>\n\n"
+            total_balance = balance.get('total', {})
+            
+            if total_balance:
+                total_value = 0
+                for asset, amount in total_balance.items():
+                    if float(amount) > 0:
+                        balance_text += f"💵 <b>{asset}:</b> {amount}\n"
+                        if asset == 'USDC':
+                            total_value += float(amount)
+                
+                balance_text += f"\n💼 <b>Total Value:</b> ${total_value:,.2f}"
+                
+                # Add stats summary
+                basic_stats = self.stats.get_basic_stats()
+                if basic_stats['initial_balance'] > 0:
+                    pnl = total_value - basic_stats['initial_balance']
+                    pnl_percent = (pnl / basic_stats['initial_balance']) * 100
+                    
+                    balance_text += f"\n📊 <b>P&L:</b> ${pnl:,.2f} ({pnl_percent:+.2f}%)"
+            else:
+                balance_text += "No balance data available"
+        else:
+            balance_text = "❌ Could not fetch balance data"
+        
+        await update.message.reply_text(balance_text, parse_mode='HTML')
+    
+    async def positions_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /positions command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        positions = self.client.get_positions()
+        if positions:
+            positions_text = "📈 <b>Open Positions</b>\n\n"
+            
+            open_positions = [p for p in positions if float(p.get('contracts', 0)) != 0]
+            
+            if open_positions:
+                total_unrealized = 0
+                for position in open_positions:
+                    symbol = position.get('symbol', 'Unknown')
+                    contracts = float(position.get('contracts', 0))
+                    unrealized_pnl = float(position.get('unrealizedPnl', 0))
+                    entry_price = float(position.get('entryPx', 0))
+                    
+                    pnl_emoji = "🟢" if unrealized_pnl >= 0 else "🔴"
+                    
+                    positions_text += f"📊 <b>{symbol}</b>\n"
+                    positions_text += f"   📏 Size: {contracts} contracts\n"
+                    positions_text += f"   💰 Entry: ${entry_price:,.2f}\n"
+                    positions_text += f"   {pnl_emoji} PnL: ${unrealized_pnl:,.2f}\n\n"
+                    
+                    total_unrealized += unrealized_pnl
+                
+                positions_text += f"💼 <b>Total Unrealized P&L:</b> ${total_unrealized:,.2f}"
+            else:
+                positions_text += "No open positions"
+        else:
+            positions_text = "❌ Could not fetch positions data"
+        
+        await update.message.reply_text(positions_text, parse_mode='HTML')
+    
+    async def orders_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /orders command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        orders = self.client.get_open_orders()
+        if orders:
+            orders_text = "📋 <b>Open Orders</b>\n\n"
+            
+            if orders and len(orders) > 0:
+                for order in orders:
+                    symbol = order.get('symbol', 'Unknown')
+                    side = order.get('side', 'Unknown')
+                    amount = order.get('amount', 0)
+                    price = order.get('price', 0)
+                    order_id = order.get('id', 'Unknown')
+                    
+                    side_emoji = "🟢" if side.lower() == 'buy' else "🔴"
+                    
+                    orders_text += f"{side_emoji} <b>{symbol}</b>\n"
+                    orders_text += f"   📊 {side.upper()} {amount} @ ${price:,.2f}\n"
+                    orders_text += f"   💵 Value: ${float(amount) * float(price):,.2f}\n"
+                    orders_text += f"   🔑 ID: <code>{order_id}</code>\n\n"
+            else:
+                orders_text += "No open orders"
+        else:
+            orders_text = "❌ Could not fetch orders data"
+        
+        await update.message.reply_text(orders_text, parse_mode='HTML')
+    
+    async def market_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /market command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        symbol = Config.DEFAULT_TRADING_SYMBOL
+        market_data = self.client.get_market_data(symbol)
+        
+        if market_data:
+            ticker = market_data['ticker']
+            orderbook = market_data['orderbook']
+            
+            # Calculate 24h change
+            current_price = float(ticker.get('last', 0))
+            high_24h = float(ticker.get('high', 0))
+            low_24h = float(ticker.get('low', 0))
+            
+            market_text = f"📊 <b>Market Data - {symbol}</b>\n\n"
+            market_text += f"💵 <b>Current Price:</b> ${current_price:,.2f}\n"
+            market_text += f"📈 <b>24h High:</b> ${high_24h:,.2f}\n"
+            market_text += f"📉 <b>24h Low:</b> ${low_24h:,.2f}\n"
+            market_text += f"📊 <b>24h Volume:</b> {ticker.get('baseVolume', 'N/A')}\n\n"
+            
+            if orderbook.get('bids') and orderbook.get('asks'):
+                best_bid = float(orderbook['bids'][0][0]) if orderbook['bids'] else 0
+                best_ask = float(orderbook['asks'][0][0]) if orderbook['asks'] else 0
+                spread = best_ask - best_bid
+                spread_percent = (spread / best_ask * 100) if best_ask > 0 else 0
+                
+                market_text += f"🟢 <b>Best Bid:</b> ${best_bid:,.2f}\n"
+                market_text += f"🔴 <b>Best Ask:</b> ${best_ask:,.2f}\n"
+                market_text += f"📏 <b>Spread:</b> ${spread:.2f} ({spread_percent:.3f}%)\n"
+        else:
+            market_text = "❌ Could not fetch market data"
+        
+        await update.message.reply_text(market_text, parse_mode='HTML')
+    
+    async def price_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /price command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        symbol = Config.DEFAULT_TRADING_SYMBOL
+        market_data = self.client.get_market_data(symbol)
+        
+        if market_data:
+            price = float(market_data['ticker'].get('last', 0))
+            price_text = f"💵 <b>{symbol}</b>: ${price:,.2f}"
+            
+            # Add timestamp
+            timestamp = datetime.now().strftime('%H:%M:%S')
+            price_text += f"\n⏰ <i>Updated: {timestamp}</i>"
+        else:
+            price_text = f"❌ Could not fetch price for {symbol}"
+        
+        await update.message.reply_text(price_text, parse_mode='HTML')
+    
+    async def button_callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle inline keyboard button presses."""
+        query = update.callback_query
+        await query.answer()
+        
+        if not self.is_authorized(query.message.chat_id):
+            await query.edit_message_text("❌ Unauthorized access.")
+            return
+        
+        callback_data = query.data
+        
+        # Handle trading confirmations
+        if callback_data.startswith('confirm_buy_'):
+            parts = callback_data.split('_')
+            amount = float(parts[2])
+            price = float(parts[3])
+            await self._execute_buy_order(query, amount, price)
+            return
+            
+        elif callback_data.startswith('confirm_sell_'):
+            parts = callback_data.split('_')
+            amount = float(parts[2])
+            price = float(parts[3])
+            await self._execute_sell_order(query, amount, price)
+            return
+            
+        elif callback_data == 'cancel_order':
+            await query.edit_message_text("❌ Order cancelled.")
+            return
+        
+        # Create a fake update object for reusing command handlers
+        fake_update = Update(
+            update_id=update.update_id,
+            message=query.message,
+            callback_query=query
+        )
+        
+        # Handle regular button callbacks
+        if callback_data == "balance":
+            await self.balance_command(fake_update, context)
+        elif callback_data == "stats":
+            await self.stats_command(fake_update, context)
+        elif callback_data == "positions":
+            await self.positions_command(fake_update, context)
+        elif callback_data == "orders":
+            await self.orders_command(fake_update, context)
+        elif callback_data == "market":
+            await self.market_command(fake_update, context)
+        elif callback_data == "price":
+            await self.price_command(fake_update, context)
+        elif callback_data == "trades":
+            await self.trades_command(fake_update, context)
+        elif callback_data == "help":
+            await self.help_command(fake_update, context)
+    
+    async def _execute_buy_order(self, query, amount: float, price: float):
+        """Execute a buy order."""
+        symbol = Config.DEFAULT_TRADING_SYMBOL
+        
+        try:
+            await query.edit_message_text("⏳ Placing buy order...")
+            
+            # Place the order
+            order = self.client.place_limit_order(symbol, 'buy', amount, price)
+            
+            if order:
+                # Record the trade in stats
+                order_id = order.get('id', 'N/A')
+                self.stats.record_trade(symbol, 'buy', amount, price, order_id)
+                
+                success_message = f"""
+✅ <b>Buy Order Placed Successfully!</b>
+
+📊 <b>Order Details:</b>
+• Symbol: {symbol}
+• Side: BUY
+• Amount: {amount}
+• Price: ${price:,.2f}
+• Order ID: <code>{order_id}</code>
+• Total Value: ${amount * price:,.2f}
+
+The order has been submitted to Hyperliquid.
+                """
+                
+                await query.edit_message_text(success_message, parse_mode='HTML')
+                logger.info(f"Buy order placed: {amount} {symbol} @ ${price}")
+            else:
+                await query.edit_message_text("❌ Failed to place buy order. Please try again.")
+                
+        except Exception as e:
+            error_message = f"❌ Error placing buy order: {str(e)}"
+            await query.edit_message_text(error_message)
+            logger.error(f"Error placing buy order: {e}")
+    
+    async def _execute_sell_order(self, query, amount: float, price: float):
+        """Execute a sell order."""
+        symbol = Config.DEFAULT_TRADING_SYMBOL
+        
+        try:
+            await query.edit_message_text("⏳ Placing sell order...")
+            
+            # Place the order
+            order = self.client.place_limit_order(symbol, 'sell', amount, price)
+            
+            if order:
+                # Record the trade in stats
+                order_id = order.get('id', 'N/A')
+                self.stats.record_trade(symbol, 'sell', amount, price, order_id)
+                
+                success_message = f"""
+✅ <b>Sell Order Placed Successfully!</b>
+
+📊 <b>Order Details:</b>
+• Symbol: {symbol}
+• Side: SELL
+• Amount: {amount}
+• Price: ${price:,.2f}
+• Order ID: <code>{order_id}</code>
+• Total Value: ${amount * price:,.2f}
+
+The order has been submitted to Hyperliquid.
+                """
+                
+                await query.edit_message_text(success_message, parse_mode='HTML')
+                logger.info(f"Sell order placed: {amount} {symbol} @ ${price}")
+            else:
+                await query.edit_message_text("❌ Failed to place sell order. Please try again.")
+                
+        except Exception as e:
+            error_message = f"❌ Error placing sell order: {str(e)}"
+            await query.edit_message_text(error_message)
+            logger.error(f"Error placing sell order: {e}")
+    
+    async def unknown_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle unknown commands."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        await update.message.reply_text(
+            "❓ Unknown command. Use /help to see available commands or tap the buttons in /start."
+        )
+    
+    def setup_handlers(self):
+        """Set up command handlers for the bot."""
+        if not self.application:
+            return
+        
+        # Command handlers
+        self.application.add_handler(CommandHandler("start", self.start_command))
+        self.application.add_handler(CommandHandler("help", self.help_command))
+        self.application.add_handler(CommandHandler("balance", self.balance_command))
+        self.application.add_handler(CommandHandler("positions", self.positions_command))
+        self.application.add_handler(CommandHandler("orders", self.orders_command))
+        self.application.add_handler(CommandHandler("market", self.market_command))
+        self.application.add_handler(CommandHandler("price", self.price_command))
+        self.application.add_handler(CommandHandler("stats", self.stats_command))
+        self.application.add_handler(CommandHandler("trades", self.trades_command))
+        self.application.add_handler(CommandHandler("buy", self.buy_command))
+        self.application.add_handler(CommandHandler("sell", self.sell_command))
+        
+        # Callback query handler for inline keyboards
+        self.application.add_handler(CallbackQueryHandler(self.button_callback))
+        
+        # Handle unknown commands
+        self.application.add_handler(MessageHandler(filters.COMMAND, self.unknown_command))
+    
+    async def run(self):
+        """Run the Telegram bot."""
+        if not Config.TELEGRAM_BOT_TOKEN:
+            logger.error("❌ TELEGRAM_BOT_TOKEN not configured")
+            return
+        
+        if not Config.TELEGRAM_CHAT_ID:
+            logger.error("❌ TELEGRAM_CHAT_ID not configured")
+            return
+        
+        # Create application
+        self.application = Application.builder().token(Config.TELEGRAM_BOT_TOKEN).build()
+        
+        # Set up handlers
+        self.setup_handlers()
+        
+        logger.info("🚀 Starting Telegram trading bot...")
+        
+        # Send startup notification
+        await self.send_message(
+            "🤖 <b>Manual Trading Bot Started</b>\n\n"
+            f"✅ Connected to Hyperliquid {'Testnet' if Config.HYPERLIQUID_TESTNET else 'Mainnet'}\n"
+            f"📊 Default Symbol: {Config.DEFAULT_TRADING_SYMBOL}\n"
+            f"📱 Manual trading ready!\n"
+            f"⏰ Started at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
+            "Use /start for quick actions or /help for all commands."
+        )
+        
+        # Start the bot
+        await self.application.run_polling()
+
+
+def main():
+    """Main entry point for the Telegram bot."""
+    try:
+        # Validate configuration
+        if not Config.validate():
+            logger.error("❌ Configuration validation failed!")
+            return
+        
+        if not Config.TELEGRAM_ENABLED:
+            logger.error("❌ Telegram is not enabled in configuration")
+            return
+        
+        # Create and run the bot
+        bot = TelegramTradingBot()
+        asyncio.run(bot.run())
+        
+    except KeyboardInterrupt:
+        logger.info("👋 Bot stopped by user")
+    except Exception as e:
+        logger.error(f"❌ Unexpected error: {e}")
+
+
+if __name__ == "__main__":
+    main() 

+ 400 - 0
src/trading_stats.py

@@ -0,0 +1,400 @@
+#!/usr/bin/env python3
+"""
+Trading Statistics Tracker
+
+Tracks and calculates comprehensive trading statistics including:
+- Balance tracking
+- Trade history
+- P&L analysis
+- Win/Loss ratios
+- Risk metrics (Sharpe, Sortino)
+- Performance metrics
+"""
+
+import json
+import os
+import logging
+from datetime import datetime, timedelta
+from typing import Dict, List, Any, Optional, Tuple
+import numpy as np
+from config import Config
+
+logger = logging.getLogger(__name__)
+
+class TradingStats:
+    """Comprehensive trading statistics tracker."""
+    
+    def __init__(self, stats_file: str = "trading_stats.json"):
+        """Initialize the stats tracker."""
+        self.stats_file = stats_file
+        self.data = self._load_stats()
+        
+        # Initialize if first run
+        if not self.data:
+            self._initialize_stats()
+    
+    def _load_stats(self) -> Dict[str, Any]:
+        """Load stats from file."""
+        try:
+            if os.path.exists(self.stats_file):
+                with open(self.stats_file, 'r') as f:
+                    return json.load(f)
+        except Exception as e:
+            logger.error(f"Error loading stats: {e}")
+        return {}
+    
+    def _save_stats(self):
+        """Save stats to file."""
+        try:
+            with open(self.stats_file, 'w') as f:
+                json.dump(self.data, f, indent=2, default=str)
+        except Exception as e:
+            logger.error(f"Error saving stats: {e}")
+    
+    def _initialize_stats(self):
+        """Initialize stats structure."""
+        self.data = {
+            'start_time': datetime.now().isoformat(),
+            'initial_balance': 0.0,
+            'trades': [],
+            'daily_balances': [],
+            'last_update': datetime.now().isoformat(),
+            'manual_trades_only': True  # Flag to indicate manual trading
+        }
+        self._save_stats()
+    
+    def set_initial_balance(self, balance: float):
+        """Set the initial balance when bot starts."""
+        if self.data.get('initial_balance', 0) == 0:
+            self.data['initial_balance'] = balance
+            self.data['start_time'] = datetime.now().isoformat()
+            logger.info(f"Initial balance set to: ${balance:.2f}")
+            self._save_stats()
+    
+    def record_balance(self, balance: float):
+        """Record daily balance snapshot."""
+        today = datetime.now().date().isoformat()
+        
+        # Check if we already have today's balance
+        for entry in self.data['daily_balances']:
+            if entry['date'] == today:
+                entry['balance'] = balance
+                entry['timestamp'] = datetime.now().isoformat()
+                self._save_stats()
+                return
+        
+        # Add new daily balance
+        self.data['daily_balances'].append({
+            'date': today,
+            'balance': balance,
+            'timestamp': datetime.now().isoformat()
+        })
+        self._save_stats()
+    
+    def record_trade(self, symbol: str, side: str, amount: float, price: float, 
+                    order_id: str = None, trade_type: str = "manual"):
+        """Record a trade."""
+        trade = {
+            'timestamp': datetime.now().isoformat(),
+            'symbol': symbol,
+            'side': side.lower(),
+            'amount': amount,
+            'price': price,
+            'value': amount * price,
+            'order_id': order_id,
+            'type': trade_type,
+            'pnl': 0.0  # Will be calculated when position is closed
+        }
+        
+        self.data['trades'].append(trade)
+        self.data['last_update'] = datetime.now().isoformat()
+        self._save_stats()
+        
+        logger.info(f"Recorded trade: {side} {amount} {symbol} @ ${price:.2f}")
+    
+    def calculate_trade_pnl(self) -> List[Dict[str, Any]]:
+        """Calculate P&L for completed trades using FIFO method."""
+        trades_with_pnl = []
+        positions = {}  # Track open positions by symbol
+        
+        for trade in self.data['trades']:
+            symbol = trade['symbol']
+            side = trade['side']
+            amount = trade['amount']
+            price = trade['price']
+            
+            if symbol not in positions:
+                positions[symbol] = {'amount': 0, 'avg_price': 0, 'total_cost': 0}
+            
+            pos = positions[symbol]
+            
+            if side == 'buy':
+                # Add to position
+                pos['total_cost'] += amount * price
+                pos['amount'] += amount
+                pos['avg_price'] = pos['total_cost'] / pos['amount'] if pos['amount'] > 0 else 0
+                
+                trade_copy = trade.copy()
+                trade_copy['pnl'] = 0  # No PnL on opening
+                trades_with_pnl.append(trade_copy)
+                
+            elif side == 'sell':
+                # Reduce position and calculate PnL
+                if pos['amount'] > 0:
+                    sold_amount = min(amount, pos['amount'])
+                    pnl = sold_amount * (price - pos['avg_price'])
+                    
+                    # Update position
+                    pos['amount'] -= sold_amount
+                    if pos['amount'] > 0:
+                        pos['total_cost'] = pos['amount'] * pos['avg_price']
+                    else:
+                        pos['total_cost'] = 0
+                        pos['avg_price'] = 0
+                    
+                    trade_copy = trade.copy()
+                    trade_copy['pnl'] = pnl
+                    trade_copy['sold_amount'] = sold_amount
+                    trades_with_pnl.append(trade_copy)
+                else:
+                    # Short selling (negative PnL calculation)
+                    trade_copy = trade.copy()
+                    trade_copy['pnl'] = 0  # Would need more complex logic for shorts
+                    trades_with_pnl.append(trade_copy)
+        
+        return trades_with_pnl
+    
+    def get_basic_stats(self) -> Dict[str, Any]:
+        """Get basic trading statistics."""
+        if not self.data['trades']:
+            return {
+                'total_trades': 0,
+                'initial_balance': self.data.get('initial_balance', 0),
+                'current_balance': 0,
+                'total_pnl': 0,
+                'days_active': 0
+            }
+        
+        trades_with_pnl = self.calculate_trade_pnl()
+        total_pnl = sum(trade.get('pnl', 0) for trade in trades_with_pnl)
+        
+        # Calculate days active
+        start_date = datetime.fromisoformat(self.data['start_time'])
+        days_active = (datetime.now() - start_date).days + 1
+        
+        return {
+            'total_trades': len(self.data['trades']),
+            'buy_trades': len([t for t in self.data['trades'] if t['side'] == 'buy']),
+            'sell_trades': len([t for t in self.data['trades'] if t['side'] == 'sell']),
+            'initial_balance': self.data.get('initial_balance', 0),
+            'total_pnl': total_pnl,
+            'days_active': days_active,
+            'start_date': start_date.strftime('%Y-%m-%d'),
+            'last_trade': self.data['trades'][-1]['timestamp'] if self.data['trades'] else None
+        }
+    
+    def get_performance_stats(self) -> Dict[str, Any]:
+        """Calculate advanced performance statistics."""
+        trades_with_pnl = self.calculate_trade_pnl()
+        completed_trades = [t for t in trades_with_pnl if t.get('pnl', 0) != 0]
+        
+        if not completed_trades:
+            return {
+                'win_rate': 0,
+                'profit_factor': 0,
+                'avg_win': 0,
+                'avg_loss': 0,
+                'largest_win': 0,
+                'largest_loss': 0,
+                'consecutive_wins': 0,
+                'consecutive_losses': 0
+            }
+        
+        # Separate wins and losses
+        wins = [t['pnl'] for t in completed_trades if t['pnl'] > 0]
+        losses = [abs(t['pnl']) for t in completed_trades if t['pnl'] < 0]
+        
+        # Basic metrics
+        total_wins = len(wins)
+        total_losses = len(losses)
+        total_completed = total_wins + total_losses
+        
+        win_rate = (total_wins / total_completed * 100) if total_completed > 0 else 0
+        
+        # Profit metrics
+        total_profit = sum(wins) if wins else 0
+        total_loss = sum(losses) if losses else 0
+        profit_factor = (total_profit / total_loss) if total_loss > 0 else float('inf') if total_profit > 0 else 0
+        
+        avg_win = np.mean(wins) if wins else 0
+        avg_loss = np.mean(losses) if losses else 0
+        
+        largest_win = max(wins) if wins else 0
+        largest_loss = max(losses) if losses else 0
+        
+        # Consecutive wins/losses
+        consecutive_wins = 0
+        consecutive_losses = 0
+        current_wins = 0
+        current_losses = 0
+        
+        for trade in completed_trades:
+            if trade['pnl'] > 0:
+                current_wins += 1
+                current_losses = 0
+                consecutive_wins = max(consecutive_wins, current_wins)
+            else:
+                current_losses += 1
+                current_wins = 0
+                consecutive_losses = max(consecutive_losses, current_losses)
+        
+        return {
+            'win_rate': win_rate,
+            'profit_factor': profit_factor,
+            'avg_win': avg_win,
+            'avg_loss': avg_loss,
+            'largest_win': largest_win,
+            'largest_loss': largest_loss,
+            'consecutive_wins': consecutive_wins,
+            'consecutive_losses': consecutive_losses,
+            'total_wins': total_wins,
+            'total_losses': total_losses,
+            'expectancy': avg_win * (win_rate/100) - avg_loss * ((100-win_rate)/100)
+        }
+    
+    def get_risk_metrics(self) -> Dict[str, Any]:
+        """Calculate risk-adjusted metrics."""
+        if not self.data['daily_balances'] or len(self.data['daily_balances']) < 2:
+            return {
+                'sharpe_ratio': 0,
+                'sortino_ratio': 0,
+                'max_drawdown': 0,
+                'volatility': 0,
+                'var_95': 0
+            }
+        
+        # Calculate daily returns
+        balances = [entry['balance'] for entry in self.data['daily_balances']]
+        returns = []
+        for i in range(1, len(balances)):
+            daily_return = (balances[i] - balances[i-1]) / balances[i-1] if balances[i-1] > 0 else 0
+            returns.append(daily_return)
+        
+        if not returns:
+            return {
+                'sharpe_ratio': 0,
+                'sortino_ratio': 0,
+                'max_drawdown': 0,
+                'volatility': 0,
+                'var_95': 0
+            }
+        
+        returns = np.array(returns)
+        
+        # Risk-free rate (assume 2% annually, convert to daily)
+        risk_free_rate = 0.02 / 365
+        
+        # Sharpe Ratio
+        excess_returns = returns - risk_free_rate
+        sharpe_ratio = np.mean(excess_returns) / np.std(returns) * np.sqrt(365) if np.std(returns) > 0 else 0
+        
+        # Sortino Ratio (only downside volatility)
+        downside_returns = returns[returns < 0]
+        downside_std = np.std(downside_returns) if len(downside_returns) > 0 else 0
+        sortino_ratio = np.mean(excess_returns) / downside_std * np.sqrt(365) if downside_std > 0 else 0
+        
+        # Maximum Drawdown
+        cumulative = np.cumprod(1 + returns)
+        running_max = np.maximum.accumulate(cumulative)
+        drawdown = (cumulative - running_max) / running_max
+        max_drawdown = np.min(drawdown) * 100
+        
+        # Volatility (annualized)
+        volatility = np.std(returns) * np.sqrt(365) * 100
+        
+        # Value at Risk (95%)
+        var_95 = np.percentile(returns, 5) * 100
+        
+        return {
+            'sharpe_ratio': sharpe_ratio,
+            'sortino_ratio': sortino_ratio,
+            'max_drawdown': abs(max_drawdown),
+            'volatility': volatility,
+            'var_95': abs(var_95)
+        }
+    
+    def get_comprehensive_stats(self, current_balance: float = None) -> Dict[str, Any]:
+        """Get all statistics combined."""
+        if current_balance:
+            self.record_balance(current_balance)
+        
+        basic = self.get_basic_stats()
+        performance = self.get_performance_stats()
+        risk = self.get_risk_metrics()
+        
+        # Calculate total return
+        initial_balance = basic['initial_balance']
+        total_return = 0
+        if current_balance and initial_balance > 0:
+            total_return = ((current_balance - initial_balance) / initial_balance) * 100
+        
+        return {
+            'basic': basic,
+            'performance': performance,
+            'risk': risk,
+            'current_balance': current_balance or 0,
+            'total_return': total_return,
+            'last_updated': datetime.now().isoformat()
+        }
+    
+    def format_stats_message(self, current_balance: float = None) -> str:
+        """Format stats for Telegram display."""
+        stats = self.get_comprehensive_stats(current_balance)
+        
+        basic = stats['basic']
+        perf = stats['performance']
+        risk = stats['risk']
+        
+        message = f"""
+📊 <b>Trading Statistics</b>
+
+💰 <b>Balance Overview</b>
+• Initial: ${basic['initial_balance']:,.2f}
+• Current: ${stats['current_balance']:,.2f}
+• Total P&L: ${basic['total_pnl']:,.2f}
+• Total Return: {stats['total_return']:.2f}%
+
+📈 <b>Trading Activity</b>
+• Total Trades: {basic['total_trades']}
+• Buy Orders: {basic['buy_trades']}
+• Sell Orders: {basic['sell_trades']}
+• Days Active: {basic['days_active']}
+
+🏆 <b>Performance Metrics</b>
+• Win Rate: {perf['win_rate']:.1f}%
+• Profit Factor: {perf['profit_factor']:.2f}
+• Avg Win: ${perf['avg_win']:.2f}
+• Avg Loss: ${perf['avg_loss']:.2f}
+• Expectancy: ${perf['expectancy']:.2f}
+
+📊 <b>Risk Metrics</b>
+• Sharpe Ratio: {risk['sharpe_ratio']:.2f}
+• Sortino Ratio: {risk['sortino_ratio']:.2f}
+• Max Drawdown: {risk['max_drawdown']:.2f}%
+• Volatility: {risk['volatility']:.2f}%
+• VaR (95%): {risk['var_95']:.2f}%
+
+🎯 <b>Best/Worst</b>
+• Largest Win: ${perf['largest_win']:.2f}
+• Largest Loss: ${perf['largest_loss']:.2f}
+• Max Consecutive Wins: {perf['consecutive_wins']}
+• Max Consecutive Losses: {perf['consecutive_losses']}
+
+📅 <b>Since:</b> {basic['start_date']}
+        """
+        
+        return message.strip()
+    
+    def get_recent_trades(self, limit: int = 10) -> List[Dict[str, Any]]:
+        """Get recent trades."""
+        return self.data['trades'][-limit:] if self.data['trades'] else [] 

+ 703 - 0
telegram_bot.py

@@ -0,0 +1,703 @@
+#!/usr/bin/env python3
+"""
+Telegram Bot for Hyperliquid Trading
+
+This module provides a Telegram interface for manual Hyperliquid trading
+with comprehensive statistics tracking and phone-friendly controls.
+"""
+
+import logging
+import asyncio
+import re
+from datetime import datetime
+from typing import Optional, Dict, Any
+from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
+from telegram.ext import Application, CommandHandler, CallbackQueryHandler, ContextTypes, MessageHandler, filters
+from hyperliquid_client import HyperliquidClient
+from trading_stats import TradingStats
+from config import Config
+
+# Set up logging
+logging.basicConfig(
+    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
+    level=getattr(logging, Config.LOG_LEVEL)
+)
+logger = logging.getLogger(__name__)
+
+class TelegramTradingBot:
+    """Telegram bot for manual trading with comprehensive statistics."""
+    
+    def __init__(self):
+        """Initialize the Telegram trading bot."""
+        self.client = HyperliquidClient(use_testnet=Config.HYPERLIQUID_TESTNET)
+        self.stats = TradingStats()
+        self.authorized_chat_id = Config.TELEGRAM_CHAT_ID
+        self.application = None
+        
+        # Initialize stats with current balance
+        self._initialize_stats()
+        
+    def _initialize_stats(self):
+        """Initialize stats with current balance."""
+        try:
+            balance = self.client.get_balance()
+            if balance and balance.get('total'):
+                # Get USDC balance as the main balance
+                usdc_balance = float(balance['total'].get('USDC', 0))
+                self.stats.set_initial_balance(usdc_balance)
+        except Exception as e:
+            logger.error(f"Could not initialize stats: {e}")
+        
+    def is_authorized(self, chat_id: str) -> bool:
+        """Check if the chat ID is authorized to use the bot."""
+        return str(chat_id) == str(self.authorized_chat_id)
+    
+    async def send_message(self, text: str, parse_mode: str = 'HTML') -> None:
+        """Send a message to the authorized chat."""
+        if self.application and self.authorized_chat_id:
+            try:
+                await self.application.bot.send_message(
+                    chat_id=self.authorized_chat_id,
+                    text=text,
+                    parse_mode=parse_mode
+                )
+            except Exception as e:
+                logger.error(f"Failed to send message: {e}")
+    
+    async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /start command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        welcome_text = """
+🤖 <b>Hyperliquid Manual Trading Bot</b>
+
+Welcome to your personal trading assistant! Control your Hyperliquid account directly from your phone.
+
+<b>📱 Quick Actions:</b>
+Tap the buttons below for instant access to key functions.
+
+<b>💼 Account Commands:</b>
+/balance - Account balance
+/positions - Open positions
+/orders - Open orders
+/stats - Trading statistics
+
+<b>📊 Market Commands:</b>
+/market - Market data
+/price - Current price
+
+<b>🔄 Trading Commands:</b>
+/buy [amount] [price] - Buy order
+/sell [amount] [price] - Sell order
+/trades - Recent trades
+/cancel [order_id] - Cancel order
+
+<b>📈 Statistics:</b>
+/stats - Full trading statistics
+/performance - Performance metrics
+/risk - Risk analysis
+
+Type /help for detailed command information.
+        """
+        
+        keyboard = [
+            [
+                InlineKeyboardButton("💰 Balance", callback_data="balance"),
+                InlineKeyboardButton("📊 Stats", callback_data="stats")
+            ],
+            [
+                InlineKeyboardButton("📈 Positions", callback_data="positions"),
+                InlineKeyboardButton("📋 Orders", callback_data="orders")
+            ],
+            [
+                InlineKeyboardButton("💵 Price", callback_data="price"),
+                InlineKeyboardButton("📊 Market", callback_data="market")
+            ],
+            [
+                InlineKeyboardButton("🔄 Recent Trades", callback_data="trades"),
+                InlineKeyboardButton("⚙️ Help", callback_data="help")
+            ]
+        ]
+        reply_markup = InlineKeyboardMarkup(keyboard)
+        
+        await update.message.reply_text(welcome_text, parse_mode='HTML', reply_markup=reply_markup)
+    
+    async def help_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /help command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        help_text = """
+🔧 <b>Hyperliquid Trading Bot - Complete Guide</b>
+
+<b>💼 Account Management:</b>
+• /balance - Show account balance
+• /positions - Show open positions  
+• /orders - Show open orders
+
+<b>📊 Market Data:</b>
+• /market - Detailed market data
+• /price - Quick price check
+
+<b>🔄 Manual Trading:</b>
+• /buy 0.001 50000 - Buy 0.001 BTC at $50,000
+• /sell 0.001 55000 - Sell 0.001 BTC at $55,000
+• /cancel ABC123 - Cancel order with ID ABC123
+
+<b>📈 Statistics & Analytics:</b>
+• /stats - Complete trading statistics
+• /performance - Win rate, profit factor, etc.
+• /risk - Sharpe ratio, drawdown, VaR
+• /trades - Recent trade history
+
+<b>⚙️ Configuration:</b>
+• Symbol: {symbol}
+• Default Amount: {amount}
+• Network: {network}
+
+<b>🛡️ Safety Features:</b>
+• All trades logged automatically
+• Comprehensive performance tracking
+• Real-time balance monitoring
+• Risk metrics calculation
+
+<b>📱 Mobile Optimized:</b>
+• Quick action buttons
+• Instant notifications
+• Clean, readable layout
+• One-tap commands
+
+For support, contact your bot administrator.
+        """.format(
+            symbol=Config.DEFAULT_TRADING_SYMBOL,
+            amount=Config.DEFAULT_TRADE_AMOUNT,
+            network="Testnet" if Config.HYPERLIQUID_TESTNET else "Mainnet"
+        )
+        
+        await update.message.reply_text(help_text, parse_mode='HTML')
+    
+    async def stats_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /stats command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        # Get current balance for stats
+        balance = self.client.get_balance()
+        current_balance = 0
+        if balance and balance.get('total'):
+            current_balance = float(balance['total'].get('USDC', 0))
+        
+        stats_message = self.stats.format_stats_message(current_balance)
+        await update.message.reply_text(stats_message, parse_mode='HTML')
+    
+    async def buy_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /buy command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        try:
+            if len(context.args) < 2:
+                await update.message.reply_text(
+                    "❌ Usage: /buy [amount] [price]\n"
+                    f"Example: /buy {Config.DEFAULT_TRADE_AMOUNT} 50000"
+                )
+                return
+            
+            amount = float(context.args[0])
+            price = float(context.args[1])
+            symbol = Config.DEFAULT_TRADING_SYMBOL
+            
+            # Confirmation message
+            confirmation_text = f"""
+🟢 <b>Buy Order Confirmation</b>
+
+📊 <b>Order Details:</b>
+• Symbol: {symbol}
+• Side: BUY
+• Amount: {amount}
+• Price: ${price:,.2f}
+• Total Value: ${amount * price:,.2f}
+
+⚠️ <b>Are you sure you want to place this order?</b>
+
+This will attempt to buy {amount} {symbol} at ${price:,.2f} per unit.
+            """
+            
+            keyboard = [
+                [
+                    InlineKeyboardButton("✅ Confirm Buy", callback_data=f"confirm_buy_{amount}_{price}"),
+                    InlineKeyboardButton("❌ Cancel", callback_data="cancel_order")
+                ]
+            ]
+            reply_markup = InlineKeyboardMarkup(keyboard)
+            
+            await update.message.reply_text(confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
+            
+        except ValueError:
+            await update.message.reply_text("❌ Invalid amount or price. Please use numbers only.")
+        except Exception as e:
+            await update.message.reply_text(f"❌ Error processing buy command: {e}")
+    
+    async def sell_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /sell command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        try:
+            if len(context.args) < 2:
+                await update.message.reply_text(
+                    "❌ Usage: /sell [amount] [price]\n"
+                    f"Example: /sell {Config.DEFAULT_TRADE_AMOUNT} 55000"
+                )
+                return
+            
+            amount = float(context.args[0])
+            price = float(context.args[1])
+            symbol = Config.DEFAULT_TRADING_SYMBOL
+            
+            # Confirmation message
+            confirmation_text = f"""
+🔴 <b>Sell Order Confirmation</b>
+
+📊 <b>Order Details:</b>
+• Symbol: {symbol}
+• Side: SELL
+• Amount: {amount}
+• Price: ${price:,.2f}
+• Total Value: ${amount * price:,.2f}
+
+⚠️ <b>Are you sure you want to place this order?</b>
+
+This will attempt to sell {amount} {symbol} at ${price:,.2f} per unit.
+            """
+            
+            keyboard = [
+                [
+                    InlineKeyboardButton("✅ Confirm Sell", callback_data=f"confirm_sell_{amount}_{price}"),
+                    InlineKeyboardButton("❌ Cancel", callback_data="cancel_order")
+                ]
+            ]
+            reply_markup = InlineKeyboardMarkup(keyboard)
+            
+            await update.message.reply_text(confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
+            
+        except ValueError:
+            await update.message.reply_text("❌ Invalid amount or price. Please use numbers only.")
+        except Exception as e:
+            await update.message.reply_text(f"❌ Error processing sell command: {e}")
+    
+    async def trades_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /trades command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        recent_trades = self.stats.get_recent_trades(10)
+        
+        if not recent_trades:
+            await update.message.reply_text("📝 No trades recorded yet.")
+            return
+        
+        trades_text = "🔄 <b>Recent Trades</b>\n\n"
+        
+        for trade in reversed(recent_trades[-5:]):  # Show last 5 trades
+            timestamp = datetime.fromisoformat(trade['timestamp']).strftime('%m/%d %H:%M')
+            side_emoji = "🟢" if trade['side'] == 'buy' else "🔴"
+            
+            trades_text += f"{side_emoji} <b>{trade['side'].upper()}</b> {trade['amount']} {trade['symbol']}\n"
+            trades_text += f"   💰 ${trade['price']:,.2f} | 💵 ${trade['value']:,.2f}\n"
+            trades_text += f"   📅 {timestamp}\n\n"
+        
+        await update.message.reply_text(trades_text, parse_mode='HTML')
+    
+    async def balance_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /balance command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        balance = self.client.get_balance()
+        if balance:
+            balance_text = "💰 <b>Account Balance</b>\n\n"
+            total_balance = balance.get('total', {})
+            
+            if total_balance:
+                total_value = 0
+                for asset, amount in total_balance.items():
+                    if float(amount) > 0:
+                        balance_text += f"💵 <b>{asset}:</b> {amount}\n"
+                        if asset == 'USDC':
+                            total_value += float(amount)
+                
+                balance_text += f"\n💼 <b>Total Value:</b> ${total_value:,.2f}"
+                
+                # Add stats summary
+                basic_stats = self.stats.get_basic_stats()
+                if basic_stats['initial_balance'] > 0:
+                    pnl = total_value - basic_stats['initial_balance']
+                    pnl_percent = (pnl / basic_stats['initial_balance']) * 100
+                    
+                    balance_text += f"\n📊 <b>P&L:</b> ${pnl:,.2f} ({pnl_percent:+.2f}%)"
+            else:
+                balance_text += "No balance data available"
+        else:
+            balance_text = "❌ Could not fetch balance data"
+        
+        await update.message.reply_text(balance_text, parse_mode='HTML')
+    
+    async def positions_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /positions command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        positions = self.client.get_positions()
+        if positions:
+            positions_text = "📈 <b>Open Positions</b>\n\n"
+            
+            open_positions = [p for p in positions if float(p.get('contracts', 0)) != 0]
+            
+            if open_positions:
+                total_unrealized = 0
+                for position in open_positions:
+                    symbol = position.get('symbol', 'Unknown')
+                    contracts = float(position.get('contracts', 0))
+                    unrealized_pnl = float(position.get('unrealizedPnl', 0))
+                    entry_price = float(position.get('entryPx', 0))
+                    
+                    pnl_emoji = "🟢" if unrealized_pnl >= 0 else "🔴"
+                    
+                    positions_text += f"📊 <b>{symbol}</b>\n"
+                    positions_text += f"   📏 Size: {contracts} contracts\n"
+                    positions_text += f"   💰 Entry: ${entry_price:,.2f}\n"
+                    positions_text += f"   {pnl_emoji} PnL: ${unrealized_pnl:,.2f}\n\n"
+                    
+                    total_unrealized += unrealized_pnl
+                
+                positions_text += f"💼 <b>Total Unrealized P&L:</b> ${total_unrealized:,.2f}"
+            else:
+                positions_text += "No open positions"
+        else:
+            positions_text = "❌ Could not fetch positions data"
+        
+        await update.message.reply_text(positions_text, parse_mode='HTML')
+    
+    async def orders_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /orders command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        orders = self.client.get_open_orders()
+        if orders:
+            orders_text = "📋 <b>Open Orders</b>\n\n"
+            
+            if orders and len(orders) > 0:
+                for order in orders:
+                    symbol = order.get('symbol', 'Unknown')
+                    side = order.get('side', 'Unknown')
+                    amount = order.get('amount', 0)
+                    price = order.get('price', 0)
+                    order_id = order.get('id', 'Unknown')
+                    
+                    side_emoji = "🟢" if side.lower() == 'buy' else "🔴"
+                    
+                    orders_text += f"{side_emoji} <b>{symbol}</b>\n"
+                    orders_text += f"   📊 {side.upper()} {amount} @ ${price:,.2f}\n"
+                    orders_text += f"   💵 Value: ${float(amount) * float(price):,.2f}\n"
+                    orders_text += f"   🔑 ID: <code>{order_id}</code>\n\n"
+            else:
+                orders_text += "No open orders"
+        else:
+            orders_text = "❌ Could not fetch orders data"
+        
+        await update.message.reply_text(orders_text, parse_mode='HTML')
+    
+    async def market_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /market command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        symbol = Config.DEFAULT_TRADING_SYMBOL
+        market_data = self.client.get_market_data(symbol)
+        
+        if market_data:
+            ticker = market_data['ticker']
+            orderbook = market_data['orderbook']
+            
+            # Calculate 24h change
+            current_price = float(ticker.get('last', 0))
+            high_24h = float(ticker.get('high', 0))
+            low_24h = float(ticker.get('low', 0))
+            
+            market_text = f"📊 <b>Market Data - {symbol}</b>\n\n"
+            market_text += f"💵 <b>Current Price:</b> ${current_price:,.2f}\n"
+            market_text += f"📈 <b>24h High:</b> ${high_24h:,.2f}\n"
+            market_text += f"📉 <b>24h Low:</b> ${low_24h:,.2f}\n"
+            market_text += f"📊 <b>24h Volume:</b> {ticker.get('baseVolume', 'N/A')}\n\n"
+            
+            if orderbook.get('bids') and orderbook.get('asks'):
+                best_bid = float(orderbook['bids'][0][0]) if orderbook['bids'] else 0
+                best_ask = float(orderbook['asks'][0][0]) if orderbook['asks'] else 0
+                spread = best_ask - best_bid
+                spread_percent = (spread / best_ask * 100) if best_ask > 0 else 0
+                
+                market_text += f"🟢 <b>Best Bid:</b> ${best_bid:,.2f}\n"
+                market_text += f"🔴 <b>Best Ask:</b> ${best_ask:,.2f}\n"
+                market_text += f"📏 <b>Spread:</b> ${spread:.2f} ({spread_percent:.3f}%)\n"
+        else:
+            market_text = "❌ Could not fetch market data"
+        
+        await update.message.reply_text(market_text, parse_mode='HTML')
+    
+    async def price_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /price command."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        symbol = Config.DEFAULT_TRADING_SYMBOL
+        market_data = self.client.get_market_data(symbol)
+        
+        if market_data:
+            price = float(market_data['ticker'].get('last', 0))
+            price_text = f"💵 <b>{symbol}</b>: ${price:,.2f}"
+            
+            # Add timestamp
+            timestamp = datetime.now().strftime('%H:%M:%S')
+            price_text += f"\n⏰ <i>Updated: {timestamp}</i>"
+        else:
+            price_text = f"❌ Could not fetch price for {symbol}"
+        
+        await update.message.reply_text(price_text, parse_mode='HTML')
+    
+    async def button_callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle inline keyboard button presses."""
+        query = update.callback_query
+        await query.answer()
+        
+        if not self.is_authorized(query.message.chat_id):
+            await query.edit_message_text("❌ Unauthorized access.")
+            return
+        
+        callback_data = query.data
+        
+        # Handle trading confirmations
+        if callback_data.startswith('confirm_buy_'):
+            parts = callback_data.split('_')
+            amount = float(parts[2])
+            price = float(parts[3])
+            await self._execute_buy_order(query, amount, price)
+            return
+            
+        elif callback_data.startswith('confirm_sell_'):
+            parts = callback_data.split('_')
+            amount = float(parts[2])
+            price = float(parts[3])
+            await self._execute_sell_order(query, amount, price)
+            return
+            
+        elif callback_data == 'cancel_order':
+            await query.edit_message_text("❌ Order cancelled.")
+            return
+        
+        # Create a fake update object for reusing command handlers
+        fake_update = Update(
+            update_id=update.update_id,
+            message=query.message,
+            callback_query=query
+        )
+        
+        # Handle regular button callbacks
+        if callback_data == "balance":
+            await self.balance_command(fake_update, context)
+        elif callback_data == "stats":
+            await self.stats_command(fake_update, context)
+        elif callback_data == "positions":
+            await self.positions_command(fake_update, context)
+        elif callback_data == "orders":
+            await self.orders_command(fake_update, context)
+        elif callback_data == "market":
+            await self.market_command(fake_update, context)
+        elif callback_data == "price":
+            await self.price_command(fake_update, context)
+        elif callback_data == "trades":
+            await self.trades_command(fake_update, context)
+        elif callback_data == "help":
+            await self.help_command(fake_update, context)
+    
+    async def _execute_buy_order(self, query, amount: float, price: float):
+        """Execute a buy order."""
+        symbol = Config.DEFAULT_TRADING_SYMBOL
+        
+        try:
+            await query.edit_message_text("⏳ Placing buy order...")
+            
+            # Place the order
+            order = self.client.place_limit_order(symbol, 'buy', amount, price)
+            
+            if order:
+                # Record the trade in stats
+                order_id = order.get('id', 'N/A')
+                self.stats.record_trade(symbol, 'buy', amount, price, order_id)
+                
+                success_message = f"""
+✅ <b>Buy Order Placed Successfully!</b>
+
+📊 <b>Order Details:</b>
+• Symbol: {symbol}
+• Side: BUY
+• Amount: {amount}
+• Price: ${price:,.2f}
+• Order ID: <code>{order_id}</code>
+• Total Value: ${amount * price:,.2f}
+
+The order has been submitted to Hyperliquid.
+                """
+                
+                await query.edit_message_text(success_message, parse_mode='HTML')
+                logger.info(f"Buy order placed: {amount} {symbol} @ ${price}")
+            else:
+                await query.edit_message_text("❌ Failed to place buy order. Please try again.")
+                
+        except Exception as e:
+            error_message = f"❌ Error placing buy order: {str(e)}"
+            await query.edit_message_text(error_message)
+            logger.error(f"Error placing buy order: {e}")
+    
+    async def _execute_sell_order(self, query, amount: float, price: float):
+        """Execute a sell order."""
+        symbol = Config.DEFAULT_TRADING_SYMBOL
+        
+        try:
+            await query.edit_message_text("⏳ Placing sell order...")
+            
+            # Place the order
+            order = self.client.place_limit_order(symbol, 'sell', amount, price)
+            
+            if order:
+                # Record the trade in stats
+                order_id = order.get('id', 'N/A')
+                self.stats.record_trade(symbol, 'sell', amount, price, order_id)
+                
+                success_message = f"""
+✅ <b>Sell Order Placed Successfully!</b>
+
+📊 <b>Order Details:</b>
+• Symbol: {symbol}
+• Side: SELL
+• Amount: {amount}
+• Price: ${price:,.2f}
+• Order ID: <code>{order_id}</code>
+• Total Value: ${amount * price:,.2f}
+
+The order has been submitted to Hyperliquid.
+                """
+                
+                await query.edit_message_text(success_message, parse_mode='HTML')
+                logger.info(f"Sell order placed: {amount} {symbol} @ ${price}")
+            else:
+                await query.edit_message_text("❌ Failed to place sell order. Please try again.")
+                
+        except Exception as e:
+            error_message = f"❌ Error placing sell order: {str(e)}"
+            await query.edit_message_text(error_message)
+            logger.error(f"Error placing sell order: {e}")
+    
+    async def unknown_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle unknown commands."""
+        if not self.is_authorized(update.effective_chat.id):
+            await update.message.reply_text("❌ Unauthorized access.")
+            return
+        
+        await update.message.reply_text(
+            "❓ Unknown command. Use /help to see available commands or tap the buttons in /start."
+        )
+    
+    def setup_handlers(self):
+        """Set up command handlers for the bot."""
+        if not self.application:
+            return
+        
+        # Command handlers
+        self.application.add_handler(CommandHandler("start", self.start_command))
+        self.application.add_handler(CommandHandler("help", self.help_command))
+        self.application.add_handler(CommandHandler("balance", self.balance_command))
+        self.application.add_handler(CommandHandler("positions", self.positions_command))
+        self.application.add_handler(CommandHandler("orders", self.orders_command))
+        self.application.add_handler(CommandHandler("market", self.market_command))
+        self.application.add_handler(CommandHandler("price", self.price_command))
+        self.application.add_handler(CommandHandler("stats", self.stats_command))
+        self.application.add_handler(CommandHandler("trades", self.trades_command))
+        self.application.add_handler(CommandHandler("buy", self.buy_command))
+        self.application.add_handler(CommandHandler("sell", self.sell_command))
+        
+        # Callback query handler for inline keyboards
+        self.application.add_handler(CallbackQueryHandler(self.button_callback))
+        
+        # Handle unknown commands
+        self.application.add_handler(MessageHandler(filters.COMMAND, self.unknown_command))
+    
+    async def run(self):
+        """Run the Telegram bot."""
+        if not Config.TELEGRAM_BOT_TOKEN:
+            logger.error("❌ TELEGRAM_BOT_TOKEN not configured")
+            return
+        
+        if not Config.TELEGRAM_CHAT_ID:
+            logger.error("❌ TELEGRAM_CHAT_ID not configured")
+            return
+        
+        # Create application
+        self.application = Application.builder().token(Config.TELEGRAM_BOT_TOKEN).build()
+        
+        # Set up handlers
+        self.setup_handlers()
+        
+        logger.info("🚀 Starting Telegram trading bot...")
+        
+        # Send startup notification
+        await self.send_message(
+            "🤖 <b>Manual Trading Bot Started</b>\n\n"
+            f"✅ Connected to Hyperliquid {'Testnet' if Config.HYPERLIQUID_TESTNET else 'Mainnet'}\n"
+            f"📊 Default Symbol: {Config.DEFAULT_TRADING_SYMBOL}\n"
+            f"📱 Manual trading ready!\n"
+            f"⏰ Started at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
+            "Use /start for quick actions or /help for all commands."
+        )
+        
+        # Start the bot
+        await self.application.run_polling()
+
+
+def main():
+    """Main entry point for the Telegram bot."""
+    try:
+        # Validate configuration
+        if not Config.validate():
+            logger.error("❌ Configuration validation failed!")
+            return
+        
+        if not Config.TELEGRAM_ENABLED:
+            logger.error("❌ Telegram is not enabled in configuration")
+            return
+        
+        # Create and run the bot
+        bot = TelegramTradingBot()
+        asyncio.run(bot.run())
+        
+    except KeyboardInterrupt:
+        logger.info("👋 Bot stopped by user")
+    except Exception as e:
+        logger.error(f"❌ Unexpected error: {e}")
+
+
+if __name__ == "__main__":
+    main() 

+ 331 - 0
trading_bot.py

@@ -0,0 +1,331 @@
+#!/usr/bin/env python3
+"""
+Hyperliquid Manual Trading Bot - Main Launcher
+
+A robust launcher with error handling, auto-restart, and telegram notifications.
+This is the ONLY file you need to run - it handles everything.
+"""
+
+import sys
+import os
+import asyncio
+import logging
+import traceback
+import signal
+import time
+from datetime import datetime
+from pathlib import Path
+
+# Add src directory to Python path
+sys.path.insert(0, str(Path(__file__).parent / "src"))
+
+try:
+    from config import Config
+    from telegram_bot import TelegramTradingBot
+    from trading_stats import TradingStats
+except ImportError as e:
+    print(f"❌ Import error: {e}")
+    print("💡 Make sure you're in the correct directory and dependencies are installed")
+    sys.exit(1)
+
+# Global variables for graceful shutdown
+bot_instance = None
+is_shutting_down = False
+
+class BotManager:
+    """Manages the trading bot with error handling and auto-restart."""
+    
+    def __init__(self):
+        self.bot = None
+        self.restart_count = 0
+        self.max_restarts = 10
+        self.restart_delay = 5  # seconds
+        self.error_log_file = "logs/bot_errors.log"
+        self.setup_logging()
+        
+        # Ensure logs directory exists
+        os.makedirs("logs", exist_ok=True)
+    
+    def setup_logging(self):
+        """Set up comprehensive logging."""
+        # Create logs directory
+        os.makedirs("logs", exist_ok=True)
+        
+        # Set up file logging
+        log_file = f"logs/trading_bot_{datetime.now().strftime('%Y%m%d')}.log"
+        
+        logging.basicConfig(
+            level=getattr(logging, Config.LOG_LEVEL if hasattr(Config, 'LOG_LEVEL') else 'INFO'),
+            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
+            handlers=[
+                logging.FileHandler(log_file),
+                logging.StreamHandler(sys.stdout)
+            ]
+        )
+        
+        self.logger = logging.getLogger(__name__)
+        self.logger.info(f"Logging initialized - Log file: {log_file}")
+    
+    def print_banner(self):
+        """Print startup banner."""
+        banner = f"""
+╔══════════════════════════════════════════════════════════════╗
+║                    📱 HYPERLIQUID TRADING BOT                ║
+║                     Single Command Launcher                   ║
+╠══════════════════════════════════════════════════════════════╣
+║                                                              ║
+║  🤖 Manual phone control via Telegram                       ║
+║  📊 Comprehensive trading statistics                        ║
+║  🛡️ Auto-restart & error notifications                      ║
+║  💾 Persistent data between restarts                        ║
+║  📱 Professional mobile interface                            ║
+║                                                              ║
+╚══════════════════════════════════════════════════════════════╝
+
+🚀 Starting at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+📁 Working directory: {os.getcwd()}
+🌐 Network: {'Testnet' if Config.HYPERLIQUID_TESTNET else '🚨 MAINNET 🚨'}
+        """
+        print(banner)
+    
+    def validate_configuration(self):
+        """Validate bot configuration."""
+        self.logger.info("🔍 Validating configuration...")
+        
+        missing_config = []
+        
+        if not hasattr(Config, 'HYPERLIQUID_PRIVATE_KEY') or not Config.HYPERLIQUID_PRIVATE_KEY:
+            missing_config.append("HYPERLIQUID_PRIVATE_KEY")
+        
+        if not hasattr(Config, 'TELEGRAM_BOT_TOKEN') or not Config.TELEGRAM_BOT_TOKEN:
+            missing_config.append("TELEGRAM_BOT_TOKEN")
+        
+        if not hasattr(Config, 'TELEGRAM_CHAT_ID') or not Config.TELEGRAM_CHAT_ID:
+            missing_config.append("TELEGRAM_CHAT_ID")
+        
+        if not hasattr(Config, 'TELEGRAM_ENABLED') or not Config.TELEGRAM_ENABLED:
+            missing_config.append("TELEGRAM_ENABLED (must be true)")
+        
+        if missing_config:
+            error_msg = f"❌ Missing configuration: {', '.join(missing_config)}"
+            self.logger.error(error_msg)
+            print(f"\n{error_msg}")
+            print("\n💡 Setup steps:")
+            print("1. Copy config: cp config/env.example .env")
+            print("2. Get Telegram setup: python utils/get_telegram_chat_id.py")
+            print("3. Edit .env with your details")
+            print("4. See: SETUP_GUIDE.md for detailed instructions")
+            return False
+        
+        self.logger.info("✅ Configuration validation passed")
+        return True
+    
+    def check_stats_persistence(self):
+        """Check and report on statistics persistence."""
+        stats_file = "trading_stats.json"
+        if os.path.exists(stats_file):
+            try:
+                stats = TradingStats()
+                basic_stats = stats.get_basic_stats()
+                self.logger.info(f"📊 Existing stats found - {basic_stats['total_trades']} trades since {basic_stats.get('start_date', 'unknown')}")
+                return True
+            except Exception as e:
+                self.logger.warning(f"⚠️ Stats file exists but couldn't load: {e}")
+                return False
+        else:
+            self.logger.info("📊 No existing stats - will create new tracking from launch")
+            return False
+    
+    async def send_error_notification(self, error_message: str, error_details: str = None):
+        """Send error notification via Telegram."""
+        try:
+            if hasattr(Config, 'TELEGRAM_BOT_TOKEN') and hasattr(Config, 'TELEGRAM_CHAT_ID'):
+                from telegram import Bot
+                
+                bot = Bot(token=Config.TELEGRAM_BOT_TOKEN)
+                
+                notification = f"""
+🚨 <b>Trading Bot Error</b>
+
+⏰ <b>Time:</b> {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+❌ <b>Error:</b> {error_message}
+
+🔄 <b>Status:</b> Attempting restart...
+📊 <b>Restart Count:</b> {self.restart_count}/{self.max_restarts}
+
+{f'<b>Details:</b> <code>{error_details[:500]}...</code>' if error_details else ''}
+                """
+                
+                await bot.send_message(
+                    chat_id=Config.TELEGRAM_CHAT_ID,
+                    text=notification.strip(),
+                    parse_mode='HTML'
+                )
+                
+                self.logger.info("📱 Error notification sent via Telegram")
+                
+        except Exception as e:
+            self.logger.error(f"Failed to send error notification: {e}")
+    
+    async def send_startup_notification(self):
+        """Send startup notification via Telegram."""
+        try:
+            if self.bot and hasattr(self.bot, 'send_message'):
+                message = f"""
+🟢 <b>Trading Bot Started Successfully</b>
+
+⏰ <b>Started:</b> {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+🌐 <b>Network:</b> {'Testnet' if Config.HYPERLIQUID_TESTNET else 'Mainnet'}
+📊 <b>Symbol:</b> {Config.DEFAULT_TRADING_SYMBOL}
+💰 <b>Default Amount:</b> {Config.DEFAULT_TRADE_AMOUNT}
+🔄 <b>Restart #:</b> {self.restart_count}
+
+📱 Bot is ready for manual trading!
+Send /start for quick actions.
+                """
+                await self.bot.send_message(message.strip())
+                
+        except Exception as e:
+            self.logger.error(f"Failed to send startup notification: {e}")
+    
+    async def run_bot(self):
+        """Run the main bot with error handling."""
+        try:
+            self.logger.info("🤖 Creating TelegramTradingBot instance...")
+            self.bot = TelegramTradingBot()
+            
+            self.logger.info("📊 Checking statistics persistence...")
+            self.check_stats_persistence()
+            
+            self.logger.info("🚀 Starting Telegram bot...")
+            
+            # Send startup notification
+            await self.send_startup_notification()
+            
+            # Run the bot
+            await self.bot.run()
+            
+        except KeyboardInterrupt:
+            self.logger.info("👋 Bot stopped by user (Ctrl+C)")
+            raise  # Re-raise to handle gracefully
+            
+        except Exception as e:
+            self.logger.error(f"❌ Bot error: {e}")
+            
+            # Get detailed error info
+            error_details = traceback.format_exc()
+            self.logger.error(f"Error details:\n{error_details}")
+            
+            # Log to error file
+            with open(self.error_log_file, 'a') as f:
+                f.write(f"\n{datetime.now().isoformat()} - {e}\n{error_details}\n{'='*50}\n")
+            
+            # Send error notification
+            await self.send_error_notification(str(e), error_details)
+            
+            raise  # Re-raise for restart logic
+    
+    async def run_with_restart(self):
+        """Run bot with auto-restart capability."""
+        global is_shutting_down
+        
+        while not is_shutting_down and self.restart_count < self.max_restarts:
+            try:
+                if self.restart_count > 0:
+                    self.logger.info(f"🔄 Restarting bot (attempt {self.restart_count + 1}/{self.max_restarts})")
+                    self.logger.info(f"⏳ Waiting {self.restart_delay} seconds before restart...")
+                    await asyncio.sleep(self.restart_delay)
+                
+                await self.run_bot()
+                
+                # If we get here, bot exited normally
+                break
+                
+            except KeyboardInterrupt:
+                self.logger.info("👋 Graceful shutdown requested")
+                is_shutting_down = True
+                break
+                
+            except Exception as e:
+                self.restart_count += 1
+                self.logger.error(f"💥 Bot crashed: {e}")
+                
+                if self.restart_count >= self.max_restarts:
+                    self.logger.error(f"❌ Max restart attempts ({self.max_restarts}) reached. Giving up.")
+                    
+                    # Send final error notification
+                    await self.send_error_notification(
+                        f"Bot failed permanently after {self.max_restarts} restart attempts",
+                        f"Last error: {str(e)}"
+                    )
+                    break
+                
+                # Exponential backoff for restart delay
+                self.restart_delay = min(self.restart_delay * 1.5, 60)
+    
+    async def start(self):
+        """Main entry point."""
+        try:
+            self.print_banner()
+            
+            if not self.validate_configuration():
+                return False
+            
+            self.logger.info("🎯 All systems ready - starting trading bot...")
+            print("💡 Send /start to your Telegram bot for quick actions")
+            print("🛑 Press Ctrl+C to stop\n")
+            
+            await self.run_with_restart()
+            
+            return True
+            
+        except Exception as e:
+            self.logger.error(f"❌ Fatal error in bot manager: {e}")
+            print(f"\n💥 Fatal error: {e}")
+            return False
+
+def signal_handler(signum, frame):
+    """Handle shutdown signals gracefully."""
+    global is_shutting_down, bot_instance
+    
+    print("\n🛑 Shutdown signal received...")
+    is_shutting_down = True
+    
+    if bot_instance:
+        try:
+            asyncio.create_task(bot_instance.send_error_notification("Bot shutdown requested", "Graceful shutdown"))
+        except:
+            pass
+
+def main():
+    """Main function."""
+    global bot_instance
+    
+    # Set up signal handlers for graceful shutdown
+    signal.signal(signal.SIGINT, signal_handler)
+    signal.signal(signal.SIGTERM, signal_handler)
+    
+    try:
+        bot_manager = BotManager()
+        bot_instance = bot_manager
+        
+        # Run the bot
+        success = asyncio.run(bot_manager.start())
+        
+        if success:
+            print("\n✅ Bot session completed successfully")
+        else:
+            print("\n❌ Bot session failed")
+            sys.exit(1)
+            
+    except KeyboardInterrupt:
+        print("\n👋 Bot stopped by user")
+    except Exception as e:
+        print(f"\n💥 Unexpected error: {e}")
+        sys.exit(1)
+    finally:
+        print("📊 Your trading statistics have been saved")
+        print("🔄 Run again anytime to continue tracking!")
+
+if __name__ == "__main__":
+    main() 

+ 139 - 0
utils/demo_stats.py

@@ -0,0 +1,139 @@
+#!/usr/bin/env python3
+"""
+Trading Statistics Demo
+
+Shows sample trading statistics to demonstrate what the bot tracks.
+"""
+
+import sys
+from pathlib import Path
+from datetime import datetime, timedelta
+import random
+
+# Add src directory to Python path
+sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
+
+from trading_stats import TradingStats
+
+def create_demo_stats():
+    """Create demo trading statistics."""
+    print("📊 Creating Demo Trading Statistics...\n")
+    
+    # Create stats instance with demo file
+    stats = TradingStats("demo_stats.json")
+    
+    # Set initial balance
+    initial_balance = 1000.0
+    stats.set_initial_balance(initial_balance)
+    
+    # Simulate some trades over 30 days
+    current_balance = initial_balance
+    base_time = datetime.now() - timedelta(days=30)
+    
+    print("🎲 Simulating 30 days of trading...")
+    
+    # Generate sample trades
+    symbols = ["BTC/USDC:USDC", "ETH/USDC:USDC"]
+    
+    for day in range(30):
+        date = base_time + timedelta(days=day)
+        
+        # 70% chance of trading each day
+        if random.random() < 0.7:
+            # 1-3 trades per day
+            num_trades = random.randint(1, 3)
+            
+            for _ in range(num_trades):
+                symbol = random.choice(symbols)
+                
+                # Simulate buy trade
+                if symbol == "BTC/USDC:USDC":
+                    price = random.uniform(45000, 55000)
+                    amount = random.uniform(0.001, 0.01)
+                else:  # ETH
+                    price = random.uniform(2800, 3200)
+                    amount = random.uniform(0.01, 0.1)
+                
+                trade_value = amount * price
+                
+                # Record buy
+                stats.data['trades'].append({
+                    'timestamp': date.isoformat(),
+                    'symbol': symbol,
+                    'side': 'buy',
+                    'amount': amount,
+                    'price': price,
+                    'value': trade_value,
+                    'order_id': f'demo_{len(stats.data["trades"])}',
+                    'type': 'manual',
+                    'pnl': 0.0
+                })
+                
+                # Sometimes sell (60% chance)
+                if random.random() < 0.6:
+                    # Sell at slightly different price
+                    sell_price = price * random.uniform(0.98, 1.05)  # -2% to +5%
+                    pnl = amount * (sell_price - price)
+                    current_balance += pnl
+                    
+                    sell_date = date + timedelta(hours=random.randint(1, 12))
+                    
+                    stats.data['trades'].append({
+                        'timestamp': sell_date.isoformat(),
+                        'symbol': symbol,
+                        'side': 'sell',
+                        'amount': amount,
+                        'price': sell_price,
+                        'value': amount * sell_price,
+                        'order_id': f'demo_{len(stats.data["trades"])}',
+                        'type': 'manual',
+                        'pnl': pnl
+                    })
+        
+        # Record daily balance
+        daily_variance = random.uniform(-20, 30)  # Daily balance change
+        current_balance += daily_variance
+        
+        stats.data['daily_balances'].append({
+            'date': date.date().isoformat(),
+            'balance': current_balance,
+            'timestamp': date.isoformat()
+        })
+    
+    # Save the demo data
+    stats._save_stats()
+    
+    return stats, current_balance
+
+def main():
+    """Main demo function."""
+    print("🎮 Trading Statistics Demo\n")
+    print("This shows what your bot will track when you start trading manually.\n")
+    
+    # Create demo data
+    stats, current_balance = create_demo_stats()
+    
+    # Display statistics
+    print("📈 Sample Trading Statistics:\n")
+    stats_message = stats.format_stats_message(current_balance)
+    
+    # Convert HTML to plain text for terminal display
+    plain_message = stats_message.replace('<b>', '').replace('</b>', '')
+    plain_message = plain_message.replace('<i>', '').replace('</i>', '')
+    
+    print(plain_message)
+    
+    print("\n" + "="*60)
+    print("🎯 What This Means:")
+    print("✅ Your bot will track ALL these metrics automatically")
+    print("📱 View anytime on your phone with /stats command")
+    print("💾 Statistics persist between bot restarts")
+    print("🔄 Every manual trade updates your performance metrics")
+    print("📊 Professional-grade analytics from day one")
+    print("="*60)
+    
+    print(f"\n📁 Demo data saved to: demo_stats.json")
+    print("🗑️  You can delete this file - it's just for demonstration")
+
+if __name__ == "__main__":
+    main() 

+ 125 - 0
utils/get_telegram_chat_id.py

@@ -0,0 +1,125 @@
+#!/usr/bin/env python3
+"""
+Get Telegram Chat ID Helper
+
+This script helps you find your Telegram Chat ID for bot configuration.
+"""
+
+import sys
+import asyncio
+import logging
+from pathlib import Path
+
+# Add src directory to Python path
+sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
+
+try:
+    from telegram import Update
+    from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes
+except ImportError:
+    print("❌ python-telegram-bot not installed!")
+    print("💡 Run: pip install python-telegram-bot")
+    sys.exit(1)
+
+# Set up logging
+logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+class ChatIDBot:
+    """Simple bot to get your Chat ID."""
+    
+    def __init__(self, token: str):
+        self.token = token
+        self.application = None
+        self.found_chat_ids = set()
+    
+    async def handle_message(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle any message and show chat information."""
+        chat_id = update.effective_chat.id
+        user = update.effective_user
+        message_text = update.message.text if update.message else "No text"
+        
+        # Store found chat ID
+        self.found_chat_ids.add(chat_id)
+        
+        # Respond with chat information
+        response = f"""
+🎯 <b>Found Your Chat Information!</b>
+
+🆔 <b>Chat ID:</b> <code>{chat_id}</code>
+👤 <b>User:</b> {user.first_name} {user.last_name or ''}
+📧 <b>Username:</b> @{user.username or 'None'}
+💬 <b>Message:</b> {message_text}
+
+✅ <b>Copy this Chat ID to your .env file:</b>
+<code>TELEGRAM_CHAT_ID={chat_id}</code>
+        """
+        
+        await update.message.reply_text(response, parse_mode='HTML')
+        
+        # Print to console
+        print(f"\n🎉 SUCCESS! Found Chat ID: {chat_id}")
+        print(f"👤 User: {user.first_name} {user.last_name or ''}")
+        print(f"📧 Username: @{user.username or 'None'}")
+        print(f"\n📋 Add this to your .env file:")
+        print(f"TELEGRAM_CHAT_ID={chat_id}")
+        print(f"\n✅ You can now stop this script and start your trading bot!")
+    
+    async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+        """Handle the /start command."""
+        await self.handle_message(update, context)
+    
+    async def run(self):
+        """Run the Chat ID finder bot."""
+        self.application = Application.builder().token(self.token).build()
+        
+        # Add handlers for any message or /start command
+        self.application.add_handler(CommandHandler("start", self.start_command))
+        self.application.add_handler(MessageHandler(filters.ALL, self.handle_message))
+        
+        print("🤖 Chat ID finder bot is running...")
+        print("💬 Now go to Telegram and send ANY message to your bot")
+        print("🛑 Press Ctrl+C when done\n")
+        
+        try:
+            await self.application.run_polling()
+        except KeyboardInterrupt:
+            print(f"\n👋 Chat ID finder stopped")
+            if self.found_chat_ids:
+                print(f"📋 Found Chat IDs: {', '.join(map(str, self.found_chat_ids))}")
+            else:
+                print("❌ No Chat IDs found - make sure you messaged your bot!")
+
+def main():
+    """Main function."""
+    print("🔍 Telegram Chat ID Finder\n")
+    
+    # Get bot token
+    token = input("🤖 Enter your Telegram Bot Token: ").strip()
+    
+    if not token:
+        print("❌ No token provided!")
+        return
+    
+    if ':' not in token:
+        print("❌ Invalid token format! Should look like: 123456789:ABCdefGHIjklMNOPqrs")
+        return
+    
+    print(f"\n✅ Token looks valid!")
+    print(f"🚀 Starting Chat ID finder bot...")
+    print(f"\n📱 Instructions:")
+    print(f"1. Open Telegram")
+    print(f"2. Find your bot (search for the username you gave it)")
+    print(f"3. Send ANY message to your bot")
+    print(f"4. Come back here to see your Chat ID")
+    print(f"5. Copy the Chat ID to your .env file")
+    
+    try:
+        bot = ChatIDBot(token)
+        asyncio.run(bot.run())
+    except Exception as e:
+        print(f"❌ Error: {e}")
+        print("💡 Make sure your bot token is correct")
+
+if __name__ == "__main__":
+    main() 

+ 175 - 0
utils/manual_trading_bot.py

@@ -0,0 +1,175 @@
+#!/usr/bin/env python3
+"""
+Manual Trading Bot Launcher
+
+A focused launcher for manual Hyperliquid trading via Telegram.
+This script sets up comprehensive statistics tracking and phone-friendly controls.
+"""
+
+import logging
+import asyncio
+import sys
+from datetime import datetime
+from config import Config
+from telegram_bot import TelegramTradingBot
+
+# Set up logging
+logging.basicConfig(
+    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
+    level=getattr(logging, Config.LOG_LEVEL)
+)
+logger = logging.getLogger(__name__)
+
+def print_banner():
+    """Print a nice startup banner."""
+    banner = """
+╔══════════════════════════════════════════════════════════════╗
+║                    📱 MANUAL TRADING BOT                      ║
+║                      for Hyperliquid                          ║
+╠══════════════════════════════════════════════════════════════╣
+║                                                              ║
+║  🤖 Control your account from your phone via Telegram       ║
+║  📊 Comprehensive trading statistics tracking               ║
+║  📈 Real-time P&L monitoring                                ║
+║  🛡️ Risk metrics (Sharpe, Sortino, VaR)                     ║
+║  📱 Mobile-optimized interface                               ║
+║                                                              ║
+╚══════════════════════════════════════════════════════════════╝
+    """
+    print(banner)
+
+def validate_setup():
+    """Validate that everything is set up correctly."""
+    print("🔍 Validating configuration...")
+    
+    # Check configuration
+    if not Config.validate():
+        print("❌ Configuration validation failed!")
+        return False
+    
+    # Check Telegram setup
+    if not Config.TELEGRAM_ENABLED:
+        print("❌ Telegram is not enabled in configuration")
+        print("💡 Please set TELEGRAM_ENABLED=true in your .env file")
+        return False
+    
+    if not Config.TELEGRAM_BOT_TOKEN:
+        print("❌ TELEGRAM_BOT_TOKEN not configured")
+        print("💡 Please add your Telegram bot token to .env file")
+        return False
+    
+    if not Config.TELEGRAM_CHAT_ID:
+        print("❌ TELEGRAM_CHAT_ID not configured")
+        print("💡 Please run: python get_telegram_chat_id.py")
+        return False
+    
+    # Check Hyperliquid setup
+    if not Config.HYPERLIQUID_PRIVATE_KEY:
+        print("❌ HYPERLIQUID_PRIVATE_KEY not configured")
+        print("💡 Please add your private key to .env file")
+        return False
+    
+    print("✅ Configuration validation passed!")
+    return True
+
+def print_configuration():
+    """Print current configuration."""
+    print("\n📋 Current Configuration:")
+    print(f"🌐 Network: {'Testnet' if Config.HYPERLIQUID_TESTNET else '🚨 MAINNET 🚨'}")
+    print(f"📊 Trading Symbol: {Config.DEFAULT_TRADING_SYMBOL}")
+    print(f"💰 Default Amount: {Config.DEFAULT_TRADE_AMOUNT}")
+    print(f"💬 Telegram Bot: @{Config.TELEGRAM_BOT_TOKEN.split(':')[0] if Config.TELEGRAM_BOT_TOKEN else 'Not configured'}")
+    print(f"🔑 Chat ID: {Config.TELEGRAM_CHAT_ID}")
+    print(f"📈 Statistics: Enabled (saved to trading_stats.json)")
+    
+    if not Config.HYPERLIQUID_TESTNET:
+        print("\n⚠️  WARNING: You are running on MAINNET!")
+        print("💸 Real money will be used for trading!")
+        response = input("Are you sure you want to continue? (type 'YES' to confirm): ")
+        if response != 'YES':
+            print("❌ Cancelled by user")
+            return False
+    
+    return True
+
+def print_usage_guide():
+    """Print usage guide."""
+    print("""
+📱 How to Use Your Manual Trading Bot:
+
+1️⃣ Start Telegram and find your bot
+2️⃣ Send /start to see quick action buttons  
+3️⃣ Use these commands for manual trading:
+
+💼 ACCOUNT MONITORING:
+   • /balance - Check your account balance
+   • /positions - View open positions
+   • /orders - See pending orders
+   • /stats - Full trading statistics
+
+🔄 MANUAL TRADING:
+   • /buy 0.001 50000 - Buy 0.001 BTC at $50,000
+   • /sell 0.001 55000 - Sell 0.001 BTC at $55,000
+   • /trades - View recent trade history
+
+📊 STATISTICS TRACKED:
+   • 💰 Starting vs Current Balance
+   • 📈 Total P&L and Return %
+   • 🏆 Win Rate and Profit Factor
+   • 📊 Sharpe & Sortino Ratios
+   • 🎯 Max Drawdown and VaR
+   • 🔄 Trade Count and Expectancy
+
+🛡️ SAFETY FEATURES:
+   • All trades require confirmation
+   • Comprehensive logging
+   • Real-time balance tracking
+   • Risk metrics calculation
+   • Order confirmations
+
+⚠️  IMPORTANT:
+   • Bot starts statistics tracking from first launch
+   • All manual trades are automatically recorded
+   • Statistics persist between bot restarts
+   • Use /stats to see comprehensive performance metrics
+
+Ready to start manual trading from your phone! 🚀
+    """)
+
+async def main():
+    """Main function to start the manual trading bot."""
+    try:
+        print_banner()
+        
+        # Validate setup
+        if not validate_setup():
+            sys.exit(1)
+        
+        # Print configuration
+        if not print_configuration():
+            sys.exit(1)
+        
+        print_usage_guide()
+        
+        print("🚀 Starting Manual Trading Bot...")
+        print("📱 Your phone controls are ready!")
+        print("🔄 Statistics tracking initialized")
+        print("⏰ Started at:", datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
+        print("\n💡 Open Telegram and send /start to your bot!")
+        print("🛑 Press Ctrl+C to stop the bot\n")
+        
+        # Create and run the bot
+        bot = TelegramTradingBot()
+        await bot.run()
+        
+    except KeyboardInterrupt:
+        print("\n👋 Manual Trading Bot stopped by user")
+        print("📊 Your trading statistics have been saved")
+        print("🔄 Restart anytime to continue tracking!")
+    except Exception as e:
+        logger.error(f"❌ Unexpected error: {e}")
+        print(f"\n❌ Error: {e}")
+        print("💡 Check your configuration and try again")
+
+if __name__ == "__main__":
+    asyncio.run(main()) 

+ 192 - 0
utils/simple_bot.py

@@ -0,0 +1,192 @@
+#!/usr/bin/env python3
+"""
+Simple Hyperliquid Trading Bot
+
+This is a basic trading bot that demonstrates:
+- Connecting to Hyperliquid
+- Fetching market data
+- Checking account balance
+- Basic trading functions
+
+Run with: python simple_bot.py
+"""
+
+import time
+import json
+from typing import Dict, Any
+from hyperliquid_client import HyperliquidClient
+from config import Config
+
+
+class SimpleTradingBot:
+    """A simple trading bot for demonstration purposes."""
+    
+    def __init__(self):
+        """Initialize the trading bot."""
+        print("🤖 Initializing Simple Trading Bot...")
+        self.client = HyperliquidClient(use_testnet=Config.HYPERLIQUID_TESTNET)
+        self.symbol = Config.DEFAULT_TRADING_SYMBOL
+        self.is_running = False
+        
+    def print_banner(self):
+        """Print a welcome banner."""
+        print("=" * 60)
+        print("🚀 HYPERLIQUID TRADING BOT")
+        print("=" * 60)
+        Config.print_config()
+        print("=" * 60)
+    
+    def check_connection(self) -> bool:
+        """Check if we can connect to Hyperliquid."""
+        print("\n🔗 Testing connection to Hyperliquid...")
+        
+        # Try to fetch market data (doesn't require private key)
+        market_data = self.client.get_market_data(self.symbol)
+        if market_data:
+            ticker = market_data['ticker']
+            print(f"✅ Connection successful!")
+            print(f"📊 {self.symbol} - Price: ${ticker.get('last', 'N/A')}")
+            return True
+        else:
+            print("❌ Connection failed!")
+            return False
+    
+    def show_account_info(self):
+        """Display account information."""
+        print("\n💰 Account Information:")
+        
+        # Get balance
+        balance = self.client.get_balance()
+        if balance:
+            print("💳 Balance:")
+            for asset, amount in balance.get('total', {}).items():
+                if float(amount) > 0:
+                    print(f"  {asset}: {amount}")
+        else:
+            print("❌ Could not fetch balance")
+        
+        # Get positions
+        positions = self.client.get_positions()
+        if positions and len(positions) > 0:
+            print("📈 Open Positions:")
+            for position in positions:
+                if float(position.get('contracts', 0)) != 0:
+                    print(f"  {position.get('symbol')}: {position.get('contracts')} contracts")
+        else:
+            print("📈 No open positions")
+        
+        # Get open orders
+        orders = self.client.get_open_orders()
+        if orders and len(orders) > 0:
+            print("📋 Open Orders:")
+            for order in orders:
+                print(f"  {order.get('symbol')}: {order.get('side')} {order.get('amount')} @ ${order.get('price')}")
+        else:
+            print("📋 No open orders")
+    
+    def show_market_data(self):
+        """Display current market data."""
+        print(f"\n📊 Market Data for {self.symbol}:")
+        
+        market_data = self.client.get_market_data(self.symbol)
+        if market_data:
+            ticker = market_data['ticker']
+            orderbook = market_data['orderbook']
+            
+            print(f"💵 Price: ${ticker.get('last', 'N/A')}")
+            print(f"📈 24h High: ${ticker.get('high', 'N/A')}")
+            print(f"📉 24h Low: ${ticker.get('low', 'N/A')}")
+            print(f"📊 24h Volume: {ticker.get('baseVolume', 'N/A')}")
+            
+            if orderbook.get('bids') and orderbook.get('asks'):
+                best_bid = orderbook['bids'][0][0] if orderbook['bids'] else 'N/A'
+                best_ask = orderbook['asks'][0][0] if orderbook['asks'] else 'N/A'
+                print(f"🟢 Best Bid: ${best_bid}")
+                print(f"🔴 Best Ask: ${best_ask}")
+        else:
+            print("❌ Could not fetch market data")
+    
+    def demo_trading_functions(self):
+        """Demonstrate trading functions (without actually placing orders)."""
+        print(f"\n🎯 Trading Demo (SIMULATION ONLY):")
+        print("This would demonstrate trading functions, but we're in safe mode.")
+        print("To enable real trading:")
+        print("1. Set up your .env file with a real private key")
+        print("2. Modify this function to actually place orders")
+        print("3. Start with small amounts on testnet!")
+        
+        # Get current price for reference
+        market_data = self.client.get_market_data(self.symbol)
+        if market_data:
+            current_price = float(market_data['ticker'].get('last', 0))
+            print(f"\n📊 Current {self.symbol} price: ${current_price}")
+            
+            # Simulate order examples
+            buy_price = current_price * 0.99  # 1% below market
+            sell_price = current_price * 1.01  # 1% above market
+            amount = Config.DEFAULT_TRADE_AMOUNT
+            
+            print(f"🟢 Example BUY order: {amount} {self.symbol} @ ${buy_price:.2f}")
+            print(f"🔴 Example SELL order: {amount} {self.symbol} @ ${sell_price:.2f}")
+    
+    def interactive_menu(self):
+        """Show an interactive menu for the bot."""
+        while True:
+            print("\n" + "=" * 40)
+            print("🤖 Trading Bot Menu")
+            print("=" * 40)
+            print("1. Show Account Info")
+            print("2. Show Market Data")
+            print("3. Demo Trading Functions")
+            print("4. Exit")
+            print("=" * 40)
+            
+            choice = input("Select an option (1-4): ").strip()
+            
+            if choice == "1":
+                self.show_account_info()
+            elif choice == "2":
+                self.show_market_data()
+            elif choice == "3":
+                self.demo_trading_functions()
+            elif choice == "4":
+                print("👋 Goodbye!")
+                break
+            else:
+                print("❌ Invalid choice. Please try again.")
+    
+    def run(self):
+        """Main bot execution."""
+        self.print_banner()
+        
+        # Validate configuration
+        if not Config.validate():
+            print("\n❌ Configuration validation failed!")
+            print("Please set up your .env file based on env.example")
+            return
+        
+        # Test connection
+        if not self.check_connection():
+            print("❌ Could not connect to Hyperliquid. Please check your configuration.")
+            return
+        
+        # Show initial account info
+        self.show_account_info()
+        
+        # Start interactive menu
+        self.interactive_menu()
+
+
+def main():
+    """Main entry point."""
+    try:
+        bot = SimpleTradingBot()
+        bot.run()
+    except KeyboardInterrupt:
+        print("\n\n👋 Bot stopped by user")
+    except Exception as e:
+        print(f"\n❌ Unexpected error: {e}")
+
+
+if __name__ == "__main__":
+    main() 

+ 255 - 0
utils/strategy_bot.py

@@ -0,0 +1,255 @@
+#!/usr/bin/env python3
+"""
+Automated Trading Strategy Bot
+
+This bot runs continuously and implements automated trading strategies.
+It can run alongside the Telegram bot for monitoring and control.
+"""
+
+import asyncio
+import time
+import logging
+from datetime import datetime, timedelta
+from typing import Optional, Dict, Any
+from hyperliquid_client import HyperliquidClient
+from config import Config
+
+# Set up logging
+logging.basicConfig(
+    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
+    level=getattr(logging, Config.LOG_LEVEL)
+)
+logger = logging.getLogger(__name__)
+
+class TradingStrategy:
+    """Base class for trading strategies."""
+    
+    def __init__(self, client: HyperliquidClient):
+        self.client = client
+        self.symbol = Config.DEFAULT_TRADING_SYMBOL
+        self.trade_amount = Config.DEFAULT_TRADE_AMOUNT
+        
+    async def analyze_market(self) -> Dict[str, Any]:
+        """Analyze market conditions. Override in subclasses."""
+        market_data = self.client.get_market_data(self.symbol)
+        return {
+            'signal': 'HOLD',  # BUY, SELL, HOLD
+            'confidence': 0.0,  # 0.0 to 1.0
+            'market_data': market_data
+        }
+    
+    async def execute_strategy(self) -> bool:
+        """Execute the trading strategy. Override in subclasses."""
+        analysis = await self.analyze_market()
+        logger.info(f"Strategy analysis: {analysis['signal']} (confidence: {analysis['confidence']:.2f})")
+        return True
+
+class SimpleMovingAverageStrategy(TradingStrategy):
+    """Example: Simple Moving Average Crossover Strategy."""
+    
+    def __init__(self, client: HyperliquidClient):
+        super().__init__(client)
+        self.price_history = []
+        self.short_period = 5  # 5 minute MA
+        self.long_period = 20  # 20 minute MA
+        
+    async def analyze_market(self) -> Dict[str, Any]:
+        """Analyze using moving average crossover."""
+        market_data = self.client.get_market_data(self.symbol)
+        
+        if not market_data:
+            return {'signal': 'HOLD', 'confidence': 0.0, 'market_data': None}
+        
+        current_price = float(market_data['ticker'].get('last', 0))
+        if current_price == 0:
+            return {'signal': 'HOLD', 'confidence': 0.0, 'market_data': market_data}
+        
+        # Add current price to history
+        self.price_history.append(current_price)
+        
+        # Keep only what we need
+        max_history = max(self.short_period, self.long_period) + 5
+        if len(self.price_history) > max_history:
+            self.price_history = self.price_history[-max_history:]
+        
+        # Need enough data for analysis
+        if len(self.price_history) < self.long_period:
+            return {'signal': 'HOLD', 'confidence': 0.0, 'market_data': market_data}
+        
+        # Calculate moving averages
+        short_ma = sum(self.price_history[-self.short_period:]) / self.short_period
+        long_ma = sum(self.price_history[-self.long_period:]) / self.long_period
+        
+        # Previous MAs for crossover detection
+        if len(self.price_history) >= self.long_period + 1:
+            prev_short_ma = sum(self.price_history[-self.short_period-1:-1]) / self.short_period
+            prev_long_ma = sum(self.price_history[-self.long_period-1:-1]) / self.long_period
+            
+            # Bullish crossover: short MA crosses above long MA
+            if prev_short_ma <= prev_long_ma and short_ma > long_ma:
+                return {'signal': 'BUY', 'confidence': 0.7, 'market_data': market_data}
+            
+            # Bearish crossover: short MA crosses below long MA
+            if prev_short_ma >= prev_long_ma and short_ma < long_ma:
+                return {'signal': 'SELL', 'confidence': 0.7, 'market_data': market_data}
+        
+        return {'signal': 'HOLD', 'confidence': 0.5, 'market_data': market_data}
+    
+    async def execute_strategy(self) -> bool:
+        """Execute the moving average strategy."""
+        analysis = await self.analyze_market()
+        signal = analysis['signal']
+        confidence = analysis['confidence']
+        
+        logger.info(f"MA Strategy: {signal} (confidence: {confidence:.2f})")
+        
+        # Only trade with high confidence
+        if confidence < 0.6:
+            return True
+        
+        # Get current positions to avoid overtrading
+        positions = self.client.get_positions(self.symbol)
+        current_position = 0
+        if positions:
+            for pos in positions:
+                if pos.get('symbol') == self.symbol:
+                    current_position = float(pos.get('contracts', 0))
+                    break
+        
+        market_data = analysis['market_data']
+        current_price = float(market_data['ticker'].get('last', 0))
+        
+        if signal == 'BUY' and current_position <= 0:
+            # Place buy order slightly below market price
+            buy_price = current_price * 0.999  # 0.1% below market
+            logger.info(f"🟢 Placing BUY order: {self.trade_amount} {self.symbol} @ ${buy_price:.2f}")
+            
+            # Uncomment to enable real trading:
+            # order = self.client.place_limit_order(self.symbol, 'buy', self.trade_amount, buy_price)
+            # if order:
+            #     logger.info(f"✅ Buy order placed: {order}")
+            # else:
+            #     logger.error("❌ Failed to place buy order")
+            
+        elif signal == 'SELL' and current_position >= 0:
+            # Place sell order slightly above market price
+            sell_price = current_price * 1.001  # 0.1% above market
+            logger.info(f"🔴 Placing SELL order: {self.trade_amount} {self.symbol} @ ${sell_price:.2f}")
+            
+            # Uncomment to enable real trading:
+            # order = self.client.place_limit_order(self.symbol, 'sell', self.trade_amount, sell_price)
+            # if order:
+            #     logger.info(f"✅ Sell order placed: {order}")
+            # else:
+            #     logger.error("❌ Failed to place sell order")
+        
+        return True
+
+class StrategyBot:
+    """Main automated trading bot that runs strategies continuously."""
+    
+    def __init__(self):
+        """Initialize the strategy bot."""
+        self.client = HyperliquidClient(use_testnet=Config.HYPERLIQUID_TESTNET)
+        self.strategies = []
+        self.is_running = False
+        self.loop_interval = 60  # Run every 60 seconds
+        
+        # Add strategies
+        self.add_strategy(SimpleMovingAverageStrategy(self.client))
+    
+    def add_strategy(self, strategy: TradingStrategy):
+        """Add a trading strategy to the bot."""
+        self.strategies.append(strategy)
+        logger.info(f"Added strategy: {strategy.__class__.__name__}")
+    
+    async def run_strategies(self):
+        """Run all strategies once."""
+        for strategy in self.strategies:
+            try:
+                await strategy.execute_strategy()
+            except Exception as e:
+                logger.error(f"Error in strategy {strategy.__class__.__name__}: {e}")
+    
+    async def health_check(self):
+        """Check bot health and connection."""
+        # Test connection
+        market_data = self.client.get_market_data(Config.DEFAULT_TRADING_SYMBOL)
+        if not market_data:
+            logger.error("❌ Health check failed - cannot connect to Hyperliquid")
+            return False
+        
+        # Check balance
+        balance = self.client.get_balance()
+        if not balance:
+            logger.warning("⚠️ Could not fetch balance")
+        
+        logger.info("✅ Health check passed")
+        return True
+    
+    async def run(self):
+        """Main bot loop."""
+        logger.info("🚀 Starting Strategy Bot...")
+        logger.info(f"📊 Default Symbol: {Config.DEFAULT_TRADING_SYMBOL}")
+        logger.info(f"💰 Trade Amount: {Config.DEFAULT_TRADE_AMOUNT}")
+        logger.info(f"⏰ Loop Interval: {self.loop_interval} seconds")
+        logger.info(f"🌐 Network: {'Testnet' if Config.HYPERLIQUID_TESTNET else 'Mainnet'}")
+        
+        # Initial health check
+        if not await self.health_check():
+            logger.error("❌ Initial health check failed. Exiting.")
+            return
+        
+        self.is_running = True
+        iteration = 0
+        
+        try:
+            while self.is_running:
+                iteration += 1
+                start_time = time.time()
+                
+                logger.info(f"🔄 Strategy iteration #{iteration} started")
+                
+                # Run strategies
+                await self.run_strategies()
+                
+                # Periodic health check (every 10 iterations)
+                if iteration % 10 == 0:
+                    await self.health_check()
+                
+                # Calculate sleep time
+                execution_time = time.time() - start_time
+                sleep_time = max(0, self.loop_interval - execution_time)
+                
+                logger.info(f"✅ Iteration #{iteration} completed in {execution_time:.2f}s. Sleeping {sleep_time:.2f}s")
+                
+                if sleep_time > 0:
+                    await asyncio.sleep(sleep_time)
+                
+        except KeyboardInterrupt:
+            logger.info("👋 Strategy bot stopped by user")
+        except Exception as e:
+            logger.error(f"❌ Unexpected error in strategy bot: {e}")
+        finally:
+            self.is_running = False
+            logger.info("🛑 Strategy bot stopped")
+
+def main():
+    """Main entry point."""
+    try:
+        # Validate configuration
+        if not Config.validate():
+            logger.error("❌ Configuration validation failed!")
+            return
+        
+        # Create and run the bot
+        bot = StrategyBot()
+        asyncio.run(bot.run())
+        
+    except KeyboardInterrupt:
+        logger.info("👋 Bot stopped by user")
+    except Exception as e:
+        logger.error(f"❌ Unexpected error: {e}")
+
+if __name__ == "__main__":
+    main()