dev setup

This commit is contained in:
Ajasra 2025-05-29 23:50:41 +08:00
parent d90681b788
commit f5b8bd3c96
17 changed files with 1462 additions and 23 deletions

38
.env Normal file
View File

@ -0,0 +1,38 @@
# Database Configuration
POSTGRES_DB=dashboard
POSTGRES_USER=dashboard
POSTGRES_PASSWORD=dashboard123
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
DATABASE_URL=postgresql://dashboard:dashboard123@localhost:5432/dashboard
# Redis Configuration
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
# OKX API Configuration
OKX_API_KEY=your_okx_api_key_here
OKX_SECRET_KEY=your_okx_secret_key_here
OKX_PASSPHRASE=your_okx_passphrase_here
OKX_SANDBOX=true
# Application Configuration
DEBUG=true
ENVIRONMENT=development
LOG_LEVEL=INFO
# Dashboard Configuration
DASH_HOST=0.0.0.0
DASH_PORT=8050
DASH_DEBUG=true
# Bot Configuration
MAX_CONCURRENT_BOTS=5
BOT_UPDATE_INTERVAL=2 # seconds
DEFAULT_VIRTUAL_BALANCE=10000
# Data Configuration
MARKET_DATA_SYMBOLS=BTC-USDT,ETH-USDT,LTC-USDT
HISTORICAL_DATA_DAYS=30
CHART_UPDATE_INTERVAL=2000 # milliseconds

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.pyc

View File

@ -29,29 +29,27 @@ A simple control dashboard for managing and monitoring multiple cryptocurrency t
### Development Setup ### Development Setup
1. **Clone the repository** *Complete setup workflow*
```bash
git clone <repository-url>
cd Dashboard
```
2. **Install dependencies** ```
```bash python scripts/dev.py setup # Setup environment and dependencies
uv sync python scripts/dev.py start # Start Docker services
``` uv run python tests/test_setup.py # Verify everything works
```
3. **Start development environment** *Development workflow*
```bash ```
docker-compose up -d # Start PostgreSQL python scripts/dev.py dev-server # Start with hot reload (recommended)
``` python scripts/dev.py run # Start without hot reload
python scripts/dev.py status # Check service status
python scripts/dev.py stop # Stop services
```
4. **Run the application** *Dependency management*
```bash ```
uv run python main.py uv add "new-package>=1.0.0" # Add new dependency
``` uv sync --dev # Install all dependencies
```
5. **Access the dashboard**
Open your browser to `http://localhost:8050`
## Project Structure ## Project Structure

View File

@ -0,0 +1,17 @@
{
"bot_id": "ema_crossover_01",
"name": "EMA Crossover Strategy",
"strategy": "EMA_Crossover",
"parameters": {
"fast_period": 12,
"slow_period": 26,
"symbol": "BTC-USDT",
"risk_percentage": 0.02,
"stop_loss_percentage": 0.05,
"take_profit_percentage": 0.10
},
"virtual_balance": 10000,
"enabled": false,
"created_at": "2024-01-01T00:00:00Z",
"description": "Simple EMA crossover strategy for BTC-USDT trading"
}

126
config/settings.py Normal file
View File

@ -0,0 +1,126 @@
"""
Configuration settings for the Crypto Trading Bot Dashboard.
"""
import os
from pathlib import Path
from typing import Optional
from dotenv import load_dotenv
from pydantic import Field
from pydantic_settings import BaseSettings
# Load environment variables from .env file
env_file = Path(__file__).parent.parent / ".env"
if env_file.exists():
load_dotenv(env_file)
class DatabaseSettings(BaseSettings):
"""Database configuration settings."""
host: str = Field(default="localhost", env="POSTGRES_HOST")
port: int = Field(default=5432, env="POSTGRES_PORT")
database: str = Field(default="dashboard", env="POSTGRES_DB")
user: str = Field(default="dashboard", env="POSTGRES_USER")
password: str = Field(default="dashboard123", env="POSTGRES_PASSWORD")
url: Optional[str] = Field(default=None, env="DATABASE_URL")
@property
def connection_url(self) -> str:
"""Get the database connection URL."""
if self.url:
return self.url
return f"postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.database}"
class RedisSettings(BaseSettings):
"""Redis configuration settings."""
host: str = Field(default="localhost", env="REDIS_HOST")
port: int = Field(default=6379, env="REDIS_PORT")
password: Optional[str] = Field(default=None, env="REDIS_PASSWORD")
@property
def connection_url(self) -> str:
"""Get the Redis connection URL."""
if self.password:
return f"redis://:{self.password}@{self.host}:{self.port}"
return f"redis://{self.host}:{self.port}"
class OKXSettings(BaseSettings):
"""OKX API configuration settings."""
api_key: str = Field(default="", env="OKX_API_KEY")
secret_key: str = Field(default="", env="OKX_SECRET_KEY")
passphrase: str = Field(default="", env="OKX_PASSPHRASE")
sandbox: bool = Field(default=True, env="OKX_SANDBOX")
@property
def is_configured(self) -> bool:
"""Check if OKX API is properly configured."""
return bool(self.api_key and self.secret_key and self.passphrase)
class DashboardSettings(BaseSettings):
"""Dashboard application settings."""
host: str = Field(default="0.0.0.0", env="DASH_HOST")
port: int = Field(default=8050, env="DASH_PORT")
debug: bool = Field(default=True, env="DASH_DEBUG")
class BotSettings(BaseSettings):
"""Bot management settings."""
max_concurrent_bots: int = Field(default=5, env="MAX_CONCURRENT_BOTS")
update_interval: int = Field(default=2, env="BOT_UPDATE_INTERVAL")
default_virtual_balance: float = Field(default=10000.0, env="DEFAULT_VIRTUAL_BALANCE")
class DataSettings(BaseSettings):
"""Data configuration settings."""
market_data_symbols: str = Field(default="BTC-USDT,ETH-USDT,LTC-USDT", env="MARKET_DATA_SYMBOLS")
historical_data_days: int = Field(default=30, env="HISTORICAL_DATA_DAYS")
chart_update_interval: int = Field(default=2000, env="CHART_UPDATE_INTERVAL")
@property
def symbols_list(self) -> list[str]:
"""Get the list of trading symbols."""
return [symbol.strip() for symbol in self.market_data_symbols.split(",")]
class AppSettings(BaseSettings):
"""Application-wide settings."""
debug: bool = Field(default=True, env="DEBUG")
environment: str = Field(default="development", env="ENVIRONMENT")
log_level: str = Field(default="INFO", env="LOG_LEVEL")
# Create settings instances
database = DatabaseSettings()
redis = RedisSettings()
okx = OKXSettings()
dashboard = DashboardSettings()
bot = BotSettings()
data = DataSettings()
app = AppSettings()
def get_project_root() -> Path:
"""Get the project root directory."""
return Path(__file__).parent.parent
def get_config_dir() -> Path:
"""Get the configuration directory."""
return get_project_root() / "config"
def get_bot_configs_dir() -> Path:
"""Get the bot configurations directory."""
return get_config_dir() / "bot_configs"

24
database/init/init.sql Normal file
View File

@ -0,0 +1,24 @@
-- Initial database setup for Crypto Trading Bot Dashboard
-- This script runs when PostgreSQL container starts for the first time
-- Create extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Set timezone
SET timezone = 'UTC';
-- Create initial user with appropriate permissions (if not exists)
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'dashboard') THEN
CREATE ROLE dashboard WITH LOGIN PASSWORD 'dashboard123';
END IF;
END
$$;
-- Grant permissions
GRANT ALL PRIVILEGES ON DATABASE dashboard TO dashboard;
GRANT ALL ON SCHEMA public TO dashboard;
-- Create initial comment
COMMENT ON DATABASE dashboard IS 'Crypto Trading Bot Dashboard Database';

49
docker-compose.yml Normal file
View File

@ -0,0 +1,49 @@
services:
postgres:
image: postgres:15-alpine
container_name: dashboard_postgres
environment:
POSTGRES_DB: ${POSTGRES_DB:-dashboard}
POSTGRES_USER: ${POSTGRES_USER:-dashboard}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-dashboard123}
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
ports:
- "${POSTGRES_PORT:-5432}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./database/init:/docker-entrypoint-initdb.d
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-dashboard}"]
interval: 30s
timeout: 10s
retries: 3
networks:
- dashboard-network
redis:
image: redis:7-alpine
container_name: dashboard_redis
command: redis-server --appendonly yes --appendfsync everysec
ports:
- "${REDIS_PORT:-6379}:6379"
volumes:
- redis_data:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 10s
retries: 3
networks:
- dashboard-network
volumes:
postgres_data:
driver: local
redis_data:
driver: local
networks:
dashboard-network:
driver: bridge

View File

@ -0,0 +1,259 @@
# Dependency Management Guide
This guide explains how to manage Python dependencies in the Crypto Trading Bot Dashboard project.
## Local Development
### Adding New Dependencies
#### 1. Core Dependencies (Required for Runtime)
To add a new core dependency:
```bash
# Method 1: Add directly to pyproject.toml
# Edit pyproject.toml and add to the dependencies list:
# "new-package>=1.0.0",
# Method 2: Use UV to add and update pyproject.toml
uv add "new-package>=1.0.0"
# Sync to install
uv sync
```
#### 2. Development Dependencies (Testing, Linting, etc.)
```bash
# Add development-only dependency
uv add --dev "new-dev-package>=1.0.0"
# Or edit pyproject.toml under [project.optional-dependencies.dev]
# Then run:
uv sync --dev
```
### Installing Dependencies
```bash
# Install all dependencies
uv sync
# Install with development dependencies
uv sync --dev
# Install only production dependencies
uv sync --no-dev
```
### Updating Dependencies
```bash
# Update all dependencies to latest compatible versions
uv sync --upgrade
# Update specific package
uv sync --upgrade-package "package-name"
```
## Docker Environment
### Current Approach
The project uses a **volume-based development** approach where:
- Dependencies are installed in the local environment using UV
- Docker containers provide only infrastructure services (PostgreSQL, Redis)
- The Python application runs locally with hot reload
### Adding Dependencies for Docker-based Development
If you want to run the entire application in Docker:
#### 1. Create a Dockerfile
```dockerfile
FROM python:3.10-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \
postgresql-client \
curl \
&& rm -rf /var/lib/apt/lists/*
# Install UV
RUN pip install uv
# Copy dependency files
COPY pyproject.toml ./
COPY README.md ./
# Install dependencies
RUN uv sync --no-dev
# Copy application code
COPY . .
# Expose port
EXPOSE 8050
# Run application
CMD ["uv", "run", "python", "main.py"]
```
#### 2. Add Application Service to docker-compose.yml
```yaml
services:
app:
build: .
container_name: dashboard_app
ports:
- "8050:8050"
volumes:
- .:/app
- uv_cache:/root/.cache/uv
environment:
- DATABASE_URL=postgresql://dashboard:dashboard123@postgres:5432/dashboard
- REDIS_URL=redis://redis:6379
depends_on:
- postgres
- redis
networks:
- dashboard-network
restart: unless-stopped
volumes:
uv_cache:
```
#### 3. Development Workflow with Docker
```bash
# Build and start all services
docker-compose up --build
# Add new dependency
# 1. Edit pyproject.toml
# 2. Rebuild container
docker-compose build app
docker-compose up -d app
# Or use dev dependencies mount
# Mount local UV cache for faster rebuilds
```
## Hot Reload Development
### Method 1: Local Development (Recommended)
Run services in Docker, application locally with hot reload:
```bash
# Start infrastructure
python scripts/dev.py start
# Run app with hot reload
uv run python scripts/dev.py dev-server
```
### Method 2: Docker with Volume Mounts
If using Docker for the app, mount source code:
```yaml
volumes:
- .:/app # Mount source code
- /app/__pycache__ # Exclude cache
```
## Best Practices
### 1. Version Pinning
```toml
# Good: Specify minimum version with compatibility
"requests>=2.31.0,<3.0.0"
# Acceptable: Major version constraint
"pandas>=2.1.0"
# Avoid: Exact pinning (except for critical deps)
"somepackage==1.2.3" # Only if necessary
```
### 2. Dependency Categories
```toml
[project]
dependencies = [
# Core web framework
"dash>=2.14.0",
# Database
"sqlalchemy>=2.0.0",
"psycopg2-binary>=2.9.0",
# ... group related dependencies
]
```
### 3. Security Updates
```bash
# Check for security vulnerabilities
pip-audit
# Update specific vulnerable package
uv sync --upgrade-package "vulnerable-package"
```
## Troubleshooting
### Common Issues
1. **Dependency Conflicts**
```bash
# Clear UV cache and reinstall
uv cache clean
uv sync --refresh
```
2. **PostgreSQL Connection Issues**
```bash
# Ensure psycopg2-binary is installed
uv add "psycopg2-binary>=2.9.0"
```
3. **Docker Build Failures**
```bash
# Clean docker build cache
docker system prune --volumes
docker-compose build --no-cache
```
### Debugging Dependencies
```bash
# Show installed packages
uv pip list
# Show dependency tree
uv pip show <package-name>
# Check for conflicts
uv pip check
```
## Migration from requirements.txt
If you have an existing `requirements.txt`:
```bash
# Convert to pyproject.toml
uv add -r requirements.txt
# Or manually copy dependencies to pyproject.toml
# Then remove requirements.txt
```

282
docs/setup.md Normal file
View File

@ -0,0 +1,282 @@
# Development Environment Setup
This guide will help you set up the Crypto Trading Bot Dashboard development environment.
## Prerequisites
- Python 3.10+
- Docker Desktop (for Windows/Mac) or Docker Engine (for Linux)
- UV package manager
- Git
## Quick Start
### 1. Initial Setup
```bash
# Install dependencies (including dev tools)
uv sync --dev
# Set up environment and start services
python scripts/dev.py setup
```
### 2. Start Services
```bash
# Start PostgreSQL and Redis services
python scripts/dev.py start
```
### 3. Configure API Keys
Copy `env.template` to `.env` and update the OKX API credentials:
```bash
# Copy template (Windows)
copy env.template .env
# Copy template (Unix)
cp env.template .env
# Edit .env file with your actual OKX API credentials
# OKX_API_KEY=your_actual_api_key
# OKX_SECRET_KEY=your_actual_secret_key
# OKX_PASSPHRASE=your_actual_passphrase
```
### 4. Verify Setup
```bash
# Run setup verification tests
uv run python tests/test_setup.py
```
### 5. Start Dashboard with Hot Reload
```bash
# Start with hot reload (recommended for development)
python scripts/dev.py dev-server
# Or start without hot reload
python scripts/dev.py run
```
## Development Commands
### Using the dev.py script:
```bash
# Show available commands
python scripts/dev.py
# Set up environment and install dependencies
python scripts/dev.py setup
# Start all services (Docker)
python scripts/dev.py start
# Stop all services
python scripts/dev.py stop
# Restart services
python scripts/dev.py restart
# Check service status
python scripts/dev.py status
# Install/update dependencies
python scripts/dev.py install
# Run development server with hot reload
python scripts/dev.py dev-server
# Run application without hot reload
python scripts/dev.py run
```
### Direct Docker commands:
```bash
# Start services in background
docker-compose up -d
# View service logs
docker-compose logs -f
# Stop services
docker-compose down
# Rebuild and restart
docker-compose up -d --build
```
## Hot Reload Development
The development server includes hot reload functionality that automatically restarts the application when Python files change.
### Features:
- 🔥 **Auto-restart** on file changes
- 👀 **Watches multiple directories** (config, database, components, etc.)
- 🚀 **Fast restart** with debouncing (1-second delay)
- 🛑 **Graceful shutdown** with Ctrl+C
### Usage:
```bash
# Start hot reload server
python scripts/dev.py dev-server
# The server will watch these directories:
# - . (root)
# - config/
# - database/
# - components/
# - data/
# - strategies/
# - trader/
```
## Data Persistence
### Database Persistence
**PostgreSQL data persists** across container restarts
- Volume: `postgres_data` mounted to `/var/lib/postgresql/data`
- Data survives `docker-compose down` and `docker-compose up`
### Redis Persistence
**Redis data persists** with AOF (Append-Only File)
- Volume: `redis_data` mounted to `/data`
- AOF sync every second for durability
- Data survives container restarts
### Removing Persistent Data
```bash
# Stop services and remove volumes (CAUTION: This deletes all data)
docker-compose down -v
# Or remove specific volumes
docker volume rm dashboard_postgres_data
docker volume rm dashboard_redis_data
```
## Dependency Management
### Adding New Dependencies
```bash
# Add runtime dependency
uv add "package-name>=1.0.0"
# Add development dependency
uv add --dev "dev-package>=1.0.0"
# Install all dependencies
uv sync --dev
```
### Key Dependencies Included:
- **Web Framework**: Dash, Plotly
- **Database**: SQLAlchemy, psycopg2-binary, Alembic
- **Data Processing**: pandas, numpy
- **Configuration**: pydantic, python-dotenv
- **Development**: watchdog (hot reload), pytest, black, mypy
See `docs/dependency-management.md` for detailed dependency management guide.
## Directory Structure
```
Dashboard/
├── config/ # Configuration files
│ ├── settings.py # Application settings
│ └── bot_configs/ # Bot configuration files
├── database/ # Database related files
│ └── init/ # Database initialization scripts
├── scripts/ # Development scripts
│ ├── dev.py # Main development script
│ ├── setup.sh # Setup script (Unix)
│ ├── start.sh # Start script (Unix)
│ └── stop.sh # Stop script (Unix)
├── tests/ # Test files
│ └── test_setup.py # Setup verification tests
├── docs/ # Documentation
│ ├── setup.md # This file
│ └── dependency-management.md # Dependency guide
├── docker-compose.yml # Docker services configuration
├── env.template # Environment variables template
├── pyproject.toml # Dependencies and project config
└── main.py # Main application entry point
```
## Services
### PostgreSQL Database
- **Host**: localhost:5432
- **Database**: dashboard
- **User**: dashboard
- **Password**: dashboard123 (development only)
- **Persistence**: ✅ Data persists across restarts
### Redis Cache
- **Host**: localhost:6379
- **No password** (development only)
- **Persistence**: ✅ AOF enabled, data persists across restarts
## Environment Variables
Key environment variables (see `env.template` for full list):
- `DATABASE_URL` - PostgreSQL connection string
- `OKX_API_KEY` - OKX API key
- `OKX_SECRET_KEY` - OKX secret key
- `OKX_PASSPHRASE` - OKX passphrase
- `OKX_SANDBOX` - Use OKX sandbox (true/false)
- `DEBUG` - Enable debug mode
- `LOG_LEVEL` - Logging level (DEBUG, INFO, WARNING, ERROR)
## Troubleshooting
### Docker Issues
1. **Docker not running**: Start Docker Desktop/Engine
2. **Port conflicts**: Check if ports 5432 or 6379 are already in use
3. **Permission issues**: On Linux, add your user to the docker group
4. **Data persistence issues**: Check if volumes are properly mounted
### Database Connection Issues
1. **Connection refused**: Ensure PostgreSQL container is running
2. **Authentication failed**: Check credentials in `.env` file
3. **Database doesn't exist**: Run the setup script again
4. **Data loss**: Check if volume is mounted correctly
### Dependency Issues
1. **Import errors**: Run `uv sync --dev` to install dependencies
2. **Version conflicts**: Check `pyproject.toml` for compatibility
3. **Hot reload not working**: Ensure `watchdog` is installed
### Hot Reload Issues
1. **Changes not detected**: Check if files are in watched directories
2. **Rapid restarts**: Built-in 1-second debouncing should prevent this
3. **Process not stopping**: Use Ctrl+C to gracefully shutdown
## Performance Tips
1. **Use SSD**: Store Docker volumes on SSD for better database performance
2. **Increase Docker memory**: Allocate more RAM to Docker Desktop
3. **Hot reload**: Use `dev-server` for faster development cycles
4. **Dependency caching**: UV caches dependencies for faster installs
## Next Steps
After successful setup:
1. **Phase 1.0**: Database Infrastructure Setup
2. **Phase 2.0**: Bot Management System Development
3. **Phase 3.0**: OKX Integration and Data Pipeline
4. **Phase 4.0**: Dashboard UI and Visualization
5. **Phase 5.0**: Backtesting System Implementation
See `tasks/tasks-prd-crypto-bot-dashboard.md` for detailed task list.

38
env.template Normal file
View File

@ -0,0 +1,38 @@
# Database Configuration
POSTGRES_DB=dashboard
POSTGRES_USER=dashboard
POSTGRES_PASSWORD=dashboard123
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
DATABASE_URL=postgresql://dashboard:dashboard123@localhost:5432/dashboard
# Redis Configuration
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
# OKX API Configuration
OKX_API_KEY=your_okx_api_key_here
OKX_SECRET_KEY=your_okx_secret_key_here
OKX_PASSPHRASE=your_okx_passphrase_here
OKX_SANDBOX=true
# Application Configuration
DEBUG=true
ENVIRONMENT=development
LOG_LEVEL=INFO
# Dashboard Configuration
DASH_HOST=0.0.0.0
DASH_PORT=8050
DASH_DEBUG=true
# Bot Configuration
MAX_CONCURRENT_BOTS=5
BOT_UPDATE_INTERVAL=2 # seconds
DEFAULT_VIRTUAL_BALANCE=10000
# Data Configuration
MARKET_DATA_SYMBOLS=BTC-USDT,ETH-USDT,LTC-USDT
HISTORICAL_DATA_DAYS=30
CHART_UPDATE_INTERVAL=2000 # milliseconds

42
main.py
View File

@ -1,5 +1,45 @@
#!/usr/bin/env python3
"""
Main entry point for the Crypto Trading Bot Dashboard.
"""
import sys
from pathlib import Path
# Add project root to path
project_root = Path(__file__).parent
sys.path.insert(0, str(project_root))
def main(): def main():
print("Hello from dashboard!") """Main application entry point."""
print("🚀 Crypto Trading Bot Dashboard")
print("=" * 40)
try:
from config.settings import app, dashboard
print(f"Environment: {app.environment}")
print(f"Debug mode: {app.debug}")
if app.environment == "development":
print("\n🔧 Running in development mode")
print("To start the full application:")
print("1. Run: python scripts/dev.py setup")
print("2. Run: python scripts/dev.py start")
print("3. Update .env with your OKX API credentials")
print("4. Run: uv run python tests/test_setup.py")
# TODO: Start the Dash application when ready
# from app import create_app
# app = create_app()
# app.run(host=dashboard.host, port=dashboard.port, debug=dashboard.debug)
print(f"\n📝 Next: Implement Phase 1.0 - Database Infrastructure Setup")
except ImportError as e:
print(f"❌ Failed to import modules: {e}")
print("Run: uv sync")
sys.exit(1)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,7 +1,70 @@
[project] [project]
name = "dashboard" name = "dashboard"
version = "0.1.0" version = "0.1.0"
description = "Add your description here" description = "Crypto Trading Bot Dashboard - A control dashboard for managing and monitoring multiple cryptocurrency trading bots"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"
dependencies = [] dependencies = [
# Core web framework
"dash>=2.14.0",
"plotly>=5.17.0",
# Database
"sqlalchemy>=2.0.0",
"psycopg2-binary>=2.9.0",
"alembic>=1.12.0",
# HTTP and WebSocket clients
"requests>=2.31.0",
"websocket-client>=1.6.0",
"aiohttp>=3.8.0",
# Data processing
"pandas>=2.1.0",
"numpy>=1.24.0",
# Configuration and environment
"python-dotenv>=1.0.0",
"pydantic>=2.4.0",
"pydantic-settings>=2.1.0",
# Caching
"redis>=4.6.0",
# Utilities
"python-dateutil>=2.8.0",
"pytz>=2023.3",
# Logging
"structlog>=23.1.0",
# Development tools
"watchdog>=3.0.0", # For file watching and hot reload
"click>=8.0.0", # For CLI commands
]
[project.optional-dependencies]
dev = [
"pytest>=7.4.0",
"pytest-asyncio>=0.21.0",
"pytest-cov>=4.1.0",
"black>=23.0.0",
"isort>=5.12.0",
"flake8>=6.0.0",
"mypy>=1.5.0",
"pre-commit>=3.5.0", # For git hooks
"pytest-mock>=3.12.0", # For mocking in tests
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["config", "database", "scripts", "tests"]
[tool.black]
line-length = 88
target-version = ['py310']
[tool.isort]
profile = "black"
line_length = 88
[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true

282
scripts/dev.py Normal file
View File

@ -0,0 +1,282 @@
#!/usr/bin/env python3
"""
Development environment management script for the Crypto Trading Bot Dashboard.
"""
import subprocess
import sys
import time
import os
from pathlib import Path
def run_command(command: str, check: bool = True) -> subprocess.CompletedProcess:
"""Run a shell command and return the result."""
print(f"Running: {command}")
return subprocess.run(command, shell=True, check=check)
def check_docker():
"""Check if Docker is installed and running."""
try:
result = subprocess.run(
"docker --version", shell=True, capture_output=True, text=True
)
if result.returncode != 0:
print("❌ Docker is not installed or not in PATH")
return False
result = subprocess.run(
"docker info", shell=True, capture_output=True, text=True
)
if result.returncode != 0:
print("❌ Docker daemon is not running")
return False
print("✅ Docker is available and running")
return True
except Exception as e:
print(f"❌ Error checking Docker: {e}")
return False
def start_services():
"""Start all development services."""
print("🚀 Starting development environment...")
if not check_docker():
sys.exit(1)
# Start Docker services
run_command("docker-compose up -d")
# Wait for services to be ready
print("⏳ Waiting for services to be ready...")
time.sleep(10)
# Check service health
check_services()
def stop_services():
"""Stop all development services."""
print("🛑 Stopping development environment...")
run_command("docker-compose down")
def restart_services():
"""Restart all development services."""
print("🔄 Restarting development environment...")
stop_services()
start_services()
def check_services():
"""Check the status of all services."""
print("🔍 Checking service status...")
# Check Docker containers
result = subprocess.run(
"docker-compose ps", shell=True, capture_output=True, text=True
)
print(result.stdout)
# Check database connection
check_database()
def check_database():
"""Check if the database is accessible."""
try:
import psycopg2
from dotenv import load_dotenv
# Load environment variables
env_file = Path(".env")
if env_file.exists():
load_dotenv(env_file)
conn_params = {
"host": os.getenv("POSTGRES_HOST", "localhost"),
"port": os.getenv("POSTGRES_PORT", "5432"),
"database": os.getenv("POSTGRES_DB", "dashboard"),
"user": os.getenv("POSTGRES_USER", "dashboard"),
"password": os.getenv("POSTGRES_PASSWORD", "dashboard123"),
}
conn = psycopg2.connect(**conn_params)
conn.close()
print("✅ Database connection successful")
except ImportError:
print("⚠️ psycopg2 not installed, skipping database check")
except Exception as e:
print(f"❌ Database connection failed: {e}")
def setup_env():
"""Set up environment files."""
print("📝 Setting up environment...")
env_file = Path(".env")
template_file = Path("env.template")
if not env_file.exists() and template_file.exists():
import shutil
shutil.copy(template_file, env_file)
print(f"✅ Created .env file from template")
print(f"⚠️ Please update .env with your actual configuration")
elif env_file.exists():
print("✅ .env file already exists")
else:
print("❌ No env.template file found")
def install_deps():
"""Install project dependencies using UV."""
print("📦 Installing dependencies...")
run_command("uv sync --dev")
def run_dev_server():
"""Run the development server with hot reload."""
print("🔥 Starting development server with hot reload...")
try:
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import threading
import signal
class ChangeHandler(FileSystemEventHandler):
def __init__(self, restart_callback):
self.restart_callback = restart_callback
self.last_modified = 0
def on_modified(self, event):
if event.is_directory:
return
# Only watch Python files
if not event.src_path.endswith('.py'):
return
# Avoid rapid restarts
current_time = time.time()
if current_time - self.last_modified < 1:
return
self.last_modified = current_time
print(f"\n📝 File changed: {event.src_path}")
self.restart_callback()
# Application process
app_process = None
def start_app():
nonlocal app_process
if app_process:
app_process.terminate()
app_process.wait()
print("🚀 Starting application...")
app_process = subprocess.Popen([
sys.executable, "main.py"
])
def restart_app():
print("🔄 Restarting application...")
start_app()
# Set up file watcher
event_handler = ChangeHandler(restart_app)
observer = Observer()
# Watch main directories
watch_dirs = [".", "config", "database", "components", "data", "strategies", "trader"]
for watch_dir in watch_dirs:
if Path(watch_dir).exists():
observer.schedule(event_handler, watch_dir, recursive=True)
print(f"👀 Watching: {watch_dir}/")
# Start watching
observer.start()
# Start initial app
start_app()
def signal_handler(signum, frame):
print("\n🛑 Shutting down development server...")
observer.stop()
if app_process:
app_process.terminate()
app_process.wait()
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print("🔥 Development server running with hot reload")
print("📁 Watching for changes in Python files...")
print("Press Ctrl+C to stop")
# Keep the main thread alive
observer.join()
except ImportError:
print("❌ watchdog not installed, running without hot reload")
print("Install with: uv add watchdog")
# Fallback to regular execution
run_command("uv run python main.py")
except KeyboardInterrupt:
print("\n🛑 Development server stopped")
except Exception as e:
print(f"❌ Error running dev server: {e}")
def run_app():
"""Run the application without hot reload."""
print("🚀 Starting application...")
run_command("uv run python main.py")
def main():
"""Main entry point for the development script."""
if len(sys.argv) < 2:
print("Usage: python scripts/dev.py [command]")
print("Commands:")
print(" setup - Set up environment and install dependencies")
print(" start - Start development services (Docker)")
print(" stop - Stop development services")
print(" restart - Restart development services")
print(" status - Check service status")
print(" install - Install dependencies")
print(" dev-server - Run development server with hot reload")
print(" run - Run application without hot reload")
sys.exit(1)
command = sys.argv[1]
if command == "setup":
setup_env()
install_deps()
elif command == "start":
start_services()
elif command == "stop":
stop_services()
elif command == "restart":
restart_services()
elif command == "status":
check_services()
elif command == "install":
install_deps()
elif command == "dev-server":
run_dev_server()
elif command == "run":
run_app()
else:
print(f"Unknown command: {command}")
sys.exit(1)
if __name__ == "__main__":
main()

11
scripts/setup.sh Normal file
View File

@ -0,0 +1,11 @@
#!/bin/bash
# Initial setup for development environment
echo "Setting up Crypto Trading Bot Dashboard development environment..."
python scripts/dev.py setup
echo ""
echo "Setup complete! Next steps:"
echo "1. Update .env file with your actual OKX API credentials"
echo "2. Run 'python scripts/dev.py start' to start services"
echo "3. Run 'uv run python main.py' to start the dashboard"

5
scripts/start.sh Normal file
View File

@ -0,0 +1,5 @@
#!/bin/bash
# Start development environment
echo "Starting Crypto Trading Bot Dashboard development environment..."
python scripts/dev.py start

5
scripts/stop.sh Normal file
View File

@ -0,0 +1,5 @@
#!/bin/bash
# Stop development environment
echo "Stopping Crypto Trading Bot Dashboard development environment..."
python scripts/dev.py stop

201
tests/test_setup.py Normal file
View File

@ -0,0 +1,201 @@
"""
Test script to verify the development environment setup.
"""
import sys
import time
from pathlib import Path
# Add the project root to Python path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
try:
from config.settings import database, redis, app, okx, dashboard
print("✅ Configuration module loaded successfully")
except ImportError as e:
print(f"❌ Failed to load configuration: {e}")
sys.exit(1)
def test_database_connection():
"""Test database connection."""
print("\n🔍 Testing database connection...")
try:
import psycopg2
from psycopg2 import sql
conn_params = {
"host": database.host,
"port": database.port,
"database": database.database,
"user": database.user,
"password": database.password,
}
print(f"Connecting to: {database.host}:{database.port}/{database.database}")
conn = psycopg2.connect(**conn_params)
cursor = conn.cursor()
# Test basic query
cursor.execute("SELECT version();")
version = cursor.fetchone()[0]
print(f"✅ Database connected successfully")
print(f" PostgreSQL version: {version}")
# Test if we can create tables
cursor.execute("""
CREATE TABLE IF NOT EXISTS test_table (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
created_at TIMESTAMP DEFAULT NOW()
);
""")
cursor.execute("INSERT INTO test_table (name) VALUES ('test_setup');")
conn.commit()
cursor.execute("SELECT COUNT(*) FROM test_table;")
count = cursor.fetchone()[0]
print(f"✅ Database operations successful (test records: {count})")
# Clean up test table
cursor.execute("DROP TABLE IF EXISTS test_table;")
conn.commit()
cursor.close()
conn.close()
except ImportError:
print("❌ psycopg2 not installed, run: uv sync")
return False
except Exception as e:
print(f"❌ Database connection failed: {e}")
return False
return True
def test_redis_connection():
"""Test Redis connection."""
print("\n🔍 Testing Redis connection...")
try:
import redis as redis_module
r = redis_module.Redis(
host=redis.host,
port=redis.port,
password=redis.password,
decode_responses=True
)
# Test basic operations
r.set("test_key", "test_value")
value = r.get("test_key")
if value == "test_value":
print("✅ Redis connected successfully")
print(f" Connected to: {redis.host}:{redis.port}")
# Clean up
r.delete("test_key")
return True
else:
print("❌ Redis test failed")
return False
except ImportError:
print("❌ redis not installed, run: uv sync")
return False
except Exception as e:
print(f"❌ Redis connection failed: {e}")
return False
def test_configuration():
"""Test configuration loading."""
print("\n🔍 Testing configuration...")
print(f"Database URL: {database.connection_url}")
print(f"Redis URL: {redis.connection_url}")
print(f"Dashboard: {dashboard.host}:{dashboard.port}")
print(f"Environment: {app.environment}")
print(f"OKX configured: {okx.is_configured}")
if not okx.is_configured:
print("⚠️ OKX API not configured (update .env file)")
return True
def test_directories():
"""Test required directories exist."""
print("\n🔍 Testing directory structure...")
required_dirs = [
"config",
"config/bot_configs",
"database",
"scripts",
"tests",
]
all_exist = True
for dir_name in required_dirs:
dir_path = project_root / dir_name
if dir_path.exists():
print(f"{dir_name}/ exists")
else:
print(f"{dir_name}/ missing")
all_exist = False
return all_exist
def main():
"""Run all tests."""
print("🧪 Running setup verification tests...")
print(f"Project root: {project_root}")
tests = [
("Configuration", test_configuration),
("Directories", test_directories),
("Database", test_database_connection),
("Redis", test_redis_connection),
]
results = []
for test_name, test_func in tests:
try:
result = test_func()
results.append((test_name, result))
except Exception as e:
print(f"{test_name} test crashed: {e}")
results.append((test_name, False))
print("\n📊 Test Results:")
print("=" * 40)
all_passed = True
for test_name, passed in results:
status = "✅ PASS" if passed else "❌ FAIL"
print(f"{test_name:15} {status}")
if not passed:
all_passed = False
print("=" * 40)
if all_passed:
print("🎉 All tests passed! Environment is ready.")
return 0
else:
print("⚠️ Some tests failed. Check the setup.")
return 1
if __name__ == "__main__":
sys.exit(main())