mirror of
https://github.com/Xe138/AI-Trader.git
synced 2026-04-04 10:07:23 -04:00
feat: transform to REST API service with SQLite persistence (v0.3.0)
Major architecture transformation from batch-only to API service with
database persistence for Windmill integration.
## REST API Implementation
- POST /simulate/trigger - Start simulation jobs
- GET /simulate/status/{job_id} - Monitor job progress
- GET /results - Query results with filters (job_id, date, model)
- GET /health - Service health checks
## Database Layer
- SQLite persistence with 6 tables (jobs, job_details, positions,
holdings, reasoning_logs, tool_usage)
- Foreign key constraints with cascade deletes
- Replaces JSONL file storage
## Backend Components
- JobManager: Job lifecycle management with concurrency control
- RuntimeConfigManager: Thread-safe isolated runtime configs
- ModelDayExecutor: Single model-day execution engine
- SimulationWorker: Date-sequential, model-parallel orchestration
## Testing
- 102 unit and integration tests (85% coverage)
- Database: 98% coverage
- Job manager: 98% coverage
- API endpoints: 81% coverage
- Pydantic models: 100% coverage
- TDD approach throughout
## Docker Deployment
- Dual-mode: API server (persistent) + batch (one-time)
- Health checks with 30s interval
- Volume persistence for database and logs
- Separate entrypoints for each mode
## Validation Tools
- scripts/validate_docker_build.sh - Build validation
- scripts/test_api_endpoints.sh - Complete API testing
- scripts/test_batch_mode.sh - Batch mode validation
- DOCKER_API.md - Deployment guide
- TESTING_GUIDE.md - Testing procedures
## Configuration
- API_PORT environment variable (default: 8080)
- Backwards compatible with existing configs
- FastAPI, uvicorn, pydantic>=2.0 dependencies
Co-Authored-By: AI Assistant <noreply@example.com>
This commit is contained in:
347
DOCKER_API.md
Normal file
347
DOCKER_API.md
Normal file
@@ -0,0 +1,347 @@
|
||||
# Docker API Server Deployment
|
||||
|
||||
This guide explains how to run AI-Trader as a persistent REST API server using Docker for Windmill.dev integration.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Environment Setup
|
||||
|
||||
```bash
|
||||
# Copy environment template
|
||||
cp .env.example .env
|
||||
|
||||
# Edit .env and add your API keys:
|
||||
# - OPENAI_API_KEY
|
||||
# - ALPHAADVANTAGE_API_KEY
|
||||
# - JINA_API_KEY
|
||||
```
|
||||
|
||||
### 2. Start API Server
|
||||
|
||||
```bash
|
||||
# Start in API mode (default)
|
||||
docker-compose up -d ai-trader-api
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f ai-trader-api
|
||||
|
||||
# Check health
|
||||
curl http://localhost:8080/health
|
||||
```
|
||||
|
||||
### 3. Test API Endpoints
|
||||
|
||||
```bash
|
||||
# Health check
|
||||
curl http://localhost:8080/health
|
||||
|
||||
# Trigger simulation
|
||||
curl -X POST http://localhost:8080/simulate/trigger \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"config_path": "/app/configs/default_config.json",
|
||||
"date_range": ["2025-01-16", "2025-01-17"],
|
||||
"models": ["gpt-4"]
|
||||
}'
|
||||
|
||||
# Check job status (replace JOB_ID)
|
||||
curl http://localhost:8080/simulate/status/JOB_ID
|
||||
|
||||
# Query results
|
||||
curl http://localhost:8080/results?date=2025-01-16
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Two Deployment Modes
|
||||
|
||||
**API Server Mode** (Windmill integration):
|
||||
- REST API on port 8080
|
||||
- Background job execution
|
||||
- Persistent SQLite database
|
||||
- Continuous uptime with health checks
|
||||
- Start with: `docker-compose up -d ai-trader-api`
|
||||
|
||||
**Batch Mode** (one-time simulation):
|
||||
- Command-line execution
|
||||
- Runs to completion then exits
|
||||
- Config file driven
|
||||
- Start with: `docker-compose --profile batch up ai-trader-batch`
|
||||
|
||||
### Port Configuration
|
||||
|
||||
| Service | Internal Port | Default Host Port | Environment Variable |
|
||||
|---------|--------------|-------------------|---------------------|
|
||||
| API Server | 8080 | 8080 | `API_PORT` |
|
||||
| Math MCP | 8000 | 8000 | `MATH_HTTP_PORT` |
|
||||
| Search MCP | 8001 | 8001 | `SEARCH_HTTP_PORT` |
|
||||
| Trade MCP | 8002 | 8002 | `TRADE_HTTP_PORT` |
|
||||
| Price MCP | 8003 | 8003 | `GETPRICE_HTTP_PORT` |
|
||||
| Web Dashboard | 8888 | 8888 | `WEB_HTTP_PORT` |
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### POST /simulate/trigger
|
||||
Trigger a new simulation job.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"config_path": "/app/configs/default_config.json",
|
||||
"date_range": ["2025-01-16", "2025-01-17"],
|
||||
"models": ["gpt-4", "claude-3.7-sonnet"]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"job_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"status": "pending",
|
||||
"total_model_days": 4,
|
||||
"message": "Simulation job created and started"
|
||||
}
|
||||
```
|
||||
|
||||
### GET /simulate/status/{job_id}
|
||||
Get job progress and status.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"job_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"status": "running",
|
||||
"progress": {
|
||||
"total_model_days": 4,
|
||||
"completed": 2,
|
||||
"failed": 0,
|
||||
"pending": 2
|
||||
},
|
||||
"date_range": ["2025-01-16", "2025-01-17"],
|
||||
"models": ["gpt-4", "claude-3.7-sonnet"],
|
||||
"created_at": "2025-01-16T10:00:00Z",
|
||||
"details": [
|
||||
{
|
||||
"date": "2025-01-16",
|
||||
"model": "gpt-4",
|
||||
"status": "completed",
|
||||
"started_at": "2025-01-16T10:00:05Z",
|
||||
"completed_at": "2025-01-16T10:05:23Z",
|
||||
"duration_seconds": 318.5
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### GET /results
|
||||
Query simulation results with optional filters.
|
||||
|
||||
**Parameters:**
|
||||
- `job_id` (optional): Filter by job UUID
|
||||
- `date` (optional): Filter by trading date (YYYY-MM-DD)
|
||||
- `model` (optional): Filter by model signature
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"job_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"date": "2025-01-16",
|
||||
"model": "gpt-4",
|
||||
"action_id": 1,
|
||||
"action_type": "buy",
|
||||
"symbol": "AAPL",
|
||||
"amount": 10,
|
||||
"price": 250.50,
|
||||
"cash": 7495.00,
|
||||
"portfolio_value": 10000.00,
|
||||
"daily_profit": 0.00,
|
||||
"daily_return_pct": 0.00,
|
||||
"holdings": [
|
||||
{"symbol": "AAPL", "quantity": 10},
|
||||
{"symbol": "CASH", "quantity": 7495.00}
|
||||
]
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
### GET /health
|
||||
Service health check.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"database": "connected",
|
||||
"timestamp": "2025-01-16T10:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
## Volume Mounts
|
||||
|
||||
Data persists across container restarts via volume mounts:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./data:/app/data # SQLite database, price data
|
||||
- ./logs:/app/logs # Application logs
|
||||
- ./configs:/app/configs # Configuration files
|
||||
```
|
||||
|
||||
**Key files:**
|
||||
- `/app/data/jobs.db` - SQLite database with job history and results
|
||||
- `/app/data/merged.jsonl` - Cached price data (fetched on first run)
|
||||
- `/app/logs/` - Application and MCP service logs
|
||||
|
||||
## Configuration
|
||||
|
||||
### Custom Config File
|
||||
|
||||
Place config files in `./configs/` directory:
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_type": "BaseAgent",
|
||||
"date_range": {
|
||||
"init_date": "2025-01-01",
|
||||
"end_date": "2025-01-31"
|
||||
},
|
||||
"models": [
|
||||
{
|
||||
"name": "GPT-4",
|
||||
"basemodel": "gpt-4",
|
||||
"signature": "gpt-4",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"agent_config": {
|
||||
"max_steps": 30,
|
||||
"initial_cash": 10000.0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Reference in API calls: `/app/configs/your_config.json`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check Container Status
|
||||
```bash
|
||||
docker-compose ps
|
||||
docker-compose logs ai-trader-api
|
||||
```
|
||||
|
||||
### Health Check Failing
|
||||
```bash
|
||||
# Check if services started
|
||||
docker exec ai-trader-api ps aux
|
||||
|
||||
# Test internal health
|
||||
docker exec ai-trader-api curl http://localhost:8080/health
|
||||
|
||||
# Check MCP services
|
||||
docker exec ai-trader-api curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
### Database Issues
|
||||
```bash
|
||||
# View database
|
||||
docker exec ai-trader-api sqlite3 data/jobs.db ".tables"
|
||||
|
||||
# Reset database (WARNING: deletes all data)
|
||||
rm ./data/jobs.db
|
||||
docker-compose restart ai-trader-api
|
||||
```
|
||||
|
||||
### Port Conflicts
|
||||
If ports are already in use, edit `.env`:
|
||||
```bash
|
||||
API_PORT=9080 # Change to available port
|
||||
```
|
||||
|
||||
## Windmill Integration
|
||||
|
||||
Example Windmill workflow step:
|
||||
|
||||
```python
|
||||
import httpx
|
||||
|
||||
def trigger_simulation(
|
||||
api_url: str,
|
||||
config_path: str,
|
||||
start_date: str,
|
||||
end_date: str,
|
||||
models: list[str]
|
||||
):
|
||||
"""Trigger AI trading simulation via API."""
|
||||
|
||||
response = httpx.post(
|
||||
f"{api_url}/simulate/trigger",
|
||||
json={
|
||||
"config_path": config_path,
|
||||
"date_range": [start_date, end_date],
|
||||
"models": models
|
||||
},
|
||||
timeout=30.0
|
||||
)
|
||||
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
def check_status(api_url: str, job_id: str):
|
||||
"""Check simulation job status."""
|
||||
|
||||
response = httpx.get(
|
||||
f"{api_url}/simulate/status/{job_id}",
|
||||
timeout=10.0
|
||||
)
|
||||
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
```
|
||||
|
||||
## Production Deployment
|
||||
|
||||
### Use Docker Hub Image
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
ai-trader-api:
|
||||
image: ghcr.io/xe138/ai-trader:latest
|
||||
# ... rest of config
|
||||
```
|
||||
|
||||
### Build Locally
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
ai-trader-api:
|
||||
build: .
|
||||
# ... rest of config
|
||||
```
|
||||
|
||||
### Environment Security
|
||||
- Never commit `.env` to version control
|
||||
- Use secrets management in production (Docker secrets, Kubernetes secrets, etc.)
|
||||
- Rotate API keys regularly
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Prometheus Metrics (Future)
|
||||
Metrics endpoint planned: `GET /metrics`
|
||||
|
||||
### Log Aggregation
|
||||
- Container logs: `docker-compose logs -f`
|
||||
- Application logs: `./logs/api.log`
|
||||
- MCP service logs: `./logs/mcp_*.log`
|
||||
|
||||
## Scaling Considerations
|
||||
|
||||
- Single-job concurrency enforced by database lock
|
||||
- For parallel simulations, deploy multiple instances with separate databases
|
||||
- Consider load balancer for high-availability setup
|
||||
- Database size grows with number of simulations (plan for cleanup/archival)
|
||||
Reference in New Issue
Block a user