dev setup
This commit is contained in:
parent
d90681b788
commit
f5b8bd3c96
38
.env
Normal file
38
.env
Normal 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
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.pyc
|
||||||
38
README.md
38
README.md
@ -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
|
||||||
|
|
||||||
|
|||||||
17
config/bot_configs/example_bot.json
Normal file
17
config/bot_configs/example_bot.json
Normal 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
126
config/settings.py
Normal 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
24
database/init/init.sql
Normal 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
49
docker-compose.yml
Normal 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
|
||||||
259
docs/dependency-management.md
Normal file
259
docs/dependency-management.md
Normal 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
282
docs/setup.md
Normal 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
38
env.template
Normal 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
42
main.py
@ -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__":
|
||||||
|
|||||||
@ -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
282
scripts/dev.py
Normal 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
11
scripts/setup.sh
Normal 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
5
scripts/start.sh
Normal 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
5
scripts/stop.sh
Normal 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
201
tests/test_setup.py
Normal 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())
|
||||||
Loading…
x
Reference in New Issue
Block a user