458 lines
13 KiB
Markdown
458 lines
13 KiB
Markdown
# AI Trading Application
|
||
|
||
AI-assisted trading application with Interactive Brokers integration, news aggregation, and configurable trading strategies.
|
||
|
||
## Features
|
||
|
||
✅ **Phase 1: Foundation**
|
||
- Go module structure
|
||
- SQLite database with migrations
|
||
- Configuration via environment variables
|
||
- Structured JSON logging
|
||
- Graceful shutdown handling
|
||
|
||
✅ **Phase 2: IB Gateway Integration**
|
||
- Interactive Brokers API client
|
||
- Connection with retry logic and exponential backoff
|
||
- Account balance tracking (every 5 minutes)
|
||
- Order placement and cancellation
|
||
- Market data subscription support
|
||
|
||
✅ **Phase 3: News Aggregation**
|
||
- RSS feed integration (CNBC, MarketWatch, Reuters)
|
||
- Keyword-based sentiment analysis
|
||
- Article deduplication by URL
|
||
- Symbol extraction from news content
|
||
- Automatic news polling (configurable interval)
|
||
|
||
✅ **Phase 4: Trading Strategies**
|
||
- Three configurable strategies: defensive, normal, aggressive
|
||
- Risk parameters per strategy (max trades, position size, stop-loss)
|
||
- Sentiment-based trade signal generation
|
||
- Comprehensive test coverage
|
||
|
||
✅ **Phase 5: Trade Execution Engine**
|
||
- Pending trade workflow with configurable timeout
|
||
- Rate limiting (hourly and parallel trade limits)
|
||
- Trade repository with full lifecycle tracking
|
||
- Stop-loss order management
|
||
- Trade executor with order placement
|
||
- User approval/rejection of pending trades
|
||
- Force immediate execution option
|
||
|
||
✅ **Phase 6: Web Dashboard**
|
||
- HTML/JavaScript frontend with real-time updates
|
||
- Server-Sent Events (SSE) for live trade notifications
|
||
- OpenID Connect authentication via Authelia (optional)
|
||
- Trade management UI (approve/reject/force)
|
||
- **Whitelist Management UI** - Add/edit/disable trading symbols with WKN/ISIN
|
||
- Real-time balance and statistics display
|
||
- Tabbed interface (Overview/Trades/Whitelist)
|
||
- Responsive design with modal forms
|
||
- Health check endpoint
|
||
|
||
✅ **Phase 8: LLM-Based Sentiment Analysis** (Optional)
|
||
- Ollama integration for contextual sentiment analysis
|
||
- Ensemble mode: weighted average of LLM + keyword scoring
|
||
- Graceful fallback to keyword analyzer on LLM timeout
|
||
- Support for Mistral, Llama2, and other Ollama models
|
||
- Configurable temperature and timeout
|
||
- Enhanced accuracy for complex financial language
|
||
|
||
## Status
|
||
|
||
**Completed:** Phases 1-6, 8 ✅
|
||
**Production Ready:** Backend complete with optional LLM sentiment enhancement
|
||
|
||
## Optional: LLM-Based Sentiment Analysis
|
||
|
||
The application can optionally use a local LLM (via **Ollama**) for more accurate sentiment analysis:
|
||
|
||
**Benefits:**
|
||
- Context-aware: understands "beats expectations despite loss" as positive
|
||
- Handles negations, sarcasm, and hedging language
|
||
- Adaptive to new financial terminology
|
||
- Provides confidence scores for position sizing
|
||
|
||
**Setup:**
|
||
```bash
|
||
# Install Ollama
|
||
curl -fsSL https://ollama.com/install.sh | sh
|
||
|
||
# Pull model (4GB)
|
||
ollama pull mistral
|
||
|
||
# Start Ollama server
|
||
ollama serve # Runs on http://localhost:11434
|
||
```
|
||
|
||
**Enable in config:**
|
||
```yaml
|
||
llm_scorer:
|
||
enabled: true
|
||
endpoint: http://localhost:11434
|
||
model_name: mistral
|
||
timeout: 30
|
||
temperature: 0.3
|
||
ensemble_weight: 0.7 # 70% LLM + 30% keyword
|
||
```
|
||
|
||
**Resource Requirements:**
|
||
- CPU-only: 2-4s per article (async processing)
|
||
- GPU (NVIDIA 4GB+): 0.5-1s per article
|
||
- Memory: 4-8GB RAM
|
||
|
||
**Fallback:** If LLM times out or Ollama is unavailable, automatically falls back to keyword-based sentiment analysis.
|
||
|
||
## Docker Deployment
|
||
|
||
### Quick Start with Docker Compose
|
||
|
||
```bash
|
||
# Prepare data directory for distroless nonroot user
|
||
mkdir -p data && chown 65532:65532 data
|
||
|
||
# Build and run
|
||
docker-compose up -d
|
||
|
||
# View logs
|
||
docker-compose logs -f aitrade
|
||
|
||
# Stop
|
||
docker-compose down
|
||
```
|
||
|
||
### Image Details
|
||
|
||
**Base Image:** Google Distroless (`gcr.io/distroless/static-debian12:nonroot`)
|
||
- **Size:** ~23 MB (with healthcheck binary)
|
||
- **No CGO:** Pure Go with `modernc.org/sqlite`
|
||
- **Embedded Migrations:** No external files needed
|
||
- **Health Check:** Built-in lightweight binary (no curl/wget)
|
||
- **Security:** Non-root user (UID 65532), minimal attack surface
|
||
- **Includes:** CA certificates, timezone data
|
||
|
||
### Using Pre-built Image from Gitea Registry
|
||
|
||
```bash
|
||
# Pull from registry
|
||
docker pull gitea.yourdomain.com/yourusername/aitrade:latest
|
||
|
||
# Run with environment variables
|
||
docker run -d \
|
||
-p 8080:8080 \
|
||
-v $(pwd)/data:/app/data \
|
||
-e TRADING_STRATEGY=normal \
|
||
-e DRY_RUN=true \
|
||
-e LLM_SCORER_ENABLED=false \
|
||
--name aitrade \
|
||
gitea.yourdomain.com/yourusername/aitrade:latest
|
||
```
|
||
|
||
### Docker with Ollama (LLM Sentiment)
|
||
|
||
```bash
|
||
# Start both services
|
||
docker-compose --profile llm up -d
|
||
|
||
# Pull Mistral model
|
||
docker exec ollama ollama pull mistral
|
||
|
||
# Enable LLM in aitrade
|
||
docker-compose exec aitrade sh -c 'export LLM_SCORER_ENABLED=true'
|
||
docker-compose restart aitrade
|
||
```
|
||
|
||
### Build Locally
|
||
|
||
```bash
|
||
# Build image
|
||
docker build -t aitrade:local .
|
||
|
||
# Run
|
||
docker run -d -p 8080:8080 -v $(pwd)/data:/app/data aitrade:local
|
||
```
|
||
|
||
### CI/CD Pipeline
|
||
|
||
The repository includes a Gitea Actions workflow (`.gitea/workflows/docker.yaml`) that automatically:
|
||
- Builds Docker image on push to main/master/develop
|
||
- Tags images with branch name, commit SHA, and semantic version
|
||
- Pushes to Gitea Container Registry
|
||
- Creates `latest` tag for default branch
|
||
|
||
**Triggered by:**
|
||
- Push to main/master/develop branches
|
||
- Git tags matching `v*` (e.g., `v1.0.0`)
|
||
- Pull requests (build only, no push)
|
||
|
||
**Required Secret:** `GITEA_TOKEN` with registry write permissions
|
||
|
||
## Quick Start
|
||
|
||
### Option 1: Native Binary
|
||
|
||
```bash
|
||
# Build
|
||
go build -o aitrade ./cmd/aitrade
|
||
|
||
# Run
|
||
./aitrade
|
||
```
|
||
|
||
### Option 2: Docker (Recommended)
|
||
|
||
```bash
|
||
# Using Docker Compose
|
||
docker-compose up -d
|
||
|
||
# Or pull from registry
|
||
docker pull gitea.yourdomain.com/username/aitrade:latest
|
||
docker run -d -p 8080:8080 -v $(pwd)/data:/app/data gitea.yourdomain.com/username/aitrade:latest
|
||
```
|
||
|
||
### Access
|
||
|
||
Open browser: `http://localhost:8080`
|
||
|
||
**Note:** IB Gateway must be running for broker integration. See full documentation in `docs/DOCKER.md`.
|
||
|
||
## Configuration
|
||
|
||
The application supports **two configuration methods**:
|
||
|
||
### Option 1: YAML Configuration (Recommended)
|
||
|
||
Create a `config.yaml` file in one of these locations:
|
||
- `./config.yaml` (current directory)
|
||
- `~/.config/aitrade/config.yaml`
|
||
- `/etc/aitrade/config.yaml`
|
||
- Custom path via `CONFIG_FILE=/path/to/config.yaml`
|
||
|
||
**Example config.yaml:**
|
||
```yaml
|
||
trading:
|
||
strategy: normal
|
||
dry_run: true
|
||
dry_run_balance: 100000.0
|
||
max_trade_value: 2000.0
|
||
watch_symbols:
|
||
- AAPL
|
||
- MSFT
|
||
- GOOGL
|
||
|
||
database:
|
||
path: ./data/aitrade.db
|
||
|
||
web:
|
||
port: "8080"
|
||
```
|
||
|
||
See `config.example.yaml` for a complete configuration file.
|
||
|
||
### Option 2: Environment Variables
|
||
|
||
If no YAML file is found, the application uses environment variables:
|
||
|
||
```bash
|
||
# Interactive Brokers
|
||
IB_GATEWAY_HOST=127.0.0.1
|
||
IB_GATEWAY_PORT=4001
|
||
IB_CLIENT_ID=1
|
||
|
||
# Trading Strategy
|
||
TRADING_STRATEGY=normal # defensive, normal, aggressive
|
||
STOP_LOSS_ENABLED=true
|
||
STOP_LOSS_PERCENT=3.0
|
||
|
||
# Auto-Trading
|
||
TRADING_ENABLED=true # Enable automatic trade generation
|
||
TRADING_INTERVAL_SECONDS=60 # How often to analyze market (60s default)
|
||
WATCH_SYMBOLS=AAPL,MSFT,GOOGL,TSLA,AMZN # Symbols to monitor
|
||
|
||
# SELL Triggers
|
||
TAKE_PROFIT_PERCENT=5.0 # Sell when profit reaches 5%
|
||
HOLD_TIME_MINUTES=30 # Minimum hold time before selling
|
||
SELL_ON_NEGATIVE_SENTIMENT=true # Sell on negative news sentiment
|
||
|
||
# Rate Limiting
|
||
MAX_TRADES_PER_HOUR=6
|
||
MAX_PARALLEL_TRADES=5
|
||
PENDING_TIME_SECONDS=300 # 5 minutes
|
||
|
||
# Trade Limits
|
||
MAX_TRADE_VALUE=2000.0 # Absolute max $ per trade (0 = unlimited)
|
||
|
||
# Dry Run Mode
|
||
DRY_RUN=true # Enable paper trading (no real money)
|
||
DRY_RUN_BALANCE=100000.0 # Starting virtual balance
|
||
|
||
# Database
|
||
DB_PATH=./data/aitrade.db
|
||
|
||
# Web
|
||
WEB_PORT=8080
|
||
|
||
# News
|
||
NEWS_POLL_INTERVAL=300 # seconds
|
||
|
||
# LLM Sentiment Scorer (Optional - requires Ollama)
|
||
LLM_SCORER_ENABLED=false # Set to true to enable
|
||
LLM_SCORER_ENDPOINT=http://localhost:11434
|
||
LLM_SCORER_MODEL=mistral
|
||
LLM_SCORER_TIMEOUT_SECONDS=30
|
||
LLM_SCORER_TEMPERATURE=0.3
|
||
LLM_SCORER_ENSEMBLE_WEIGHT=0.7 # 0.0-1.0 (1.0 = LLM only, 0.7 = 70% LLM + 30% keyword)
|
||
|
||
# OpenID Connect (Authelia) - Optional
|
||
OIDC_ENABLED=false # Set to true to enable
|
||
OIDC_ISSUER=https://auth.example.com
|
||
OIDC_CLIENT_ID=aitrade
|
||
OIDC_CLIENT_SECRET=<secret>
|
||
OIDC_REDIRECT_URL=http://localhost:8080/callback
|
||
OIDC_SCOPES=openid,profile,email
|
||
```
|
||
|
||
## API Endpoints
|
||
|
||
### Public
|
||
- `GET /health` - Health check
|
||
- `GET /callback` - OIDC callback (when auth enabled)
|
||
|
||
### Protected (requires auth if OIDC enabled)
|
||
- `GET /` - Main dashboard
|
||
- `GET /trades` - Get all trades (JSON)
|
||
- `GET /events` - SSE stream for real-time updates
|
||
- `GET /api/balance` - Get current balance
|
||
- `GET /api/news` - Get recent news
|
||
- `POST /api/trades/{id}/approve?force=bool` - Approve trade
|
||
- `POST /api/trades/{id}/reject` - Reject trade (JSON body: `{"reason": "..."}`)
|
||
|
||
## Web Dashboard Features
|
||
|
||
- 📊 **Three Tabs:** Overview / All Trades / Whitelist Management
|
||
- 💹 Real-time statistics (balance, active trades, pending trades)
|
||
- 📈 Complete trade history with reasoning and P&L
|
||
- ⏱️ Live countdown timers for pending trades
|
||
- ✅ One-click approve/reject/force actions
|
||
- 🛡️ **Whitelist Management:** Add/edit/disable symbols with WKN/ISIN identifiers
|
||
- ⚡ Only whitelisted & enabled symbols can execute trades
|
||
- 🔄 Server-Sent Events for instant updates
|
||
- 🔒 Optional OpenID Connect authentication via Authelia
|
||
- 📱 Responsive design with modal forms
|
||
|
||
## Trading Logic
|
||
|
||
### Position Sizing (Capital Allocation)
|
||
|
||
The system uses **intelligent position sizing** that considers:
|
||
|
||
1. **Strategy Base Percentage**
|
||
- Defensive: 1.5% of capital per trade
|
||
- Normal: 4.0% of capital per trade
|
||
- Aggressive: 7.5% of capital per trade
|
||
|
||
2. **Confidence-Based Scaling**
|
||
- High confidence (0.9) → Larger position
|
||
- Low confidence (0.5) → Smaller position
|
||
- Multiplier ranges:
|
||
- Defensive: 0.3x - 0.8x
|
||
- Normal: 0.5x - 1.0x
|
||
- Aggressive: 0.7x - 1.2x
|
||
|
||
3. **Parallel Trade Allocation**
|
||
- Capital is divided by `MAX_PARALLEL_TRADES`
|
||
- Each trade slot gets: `TotalCapital / MaxParallel`
|
||
- Example: $100k with 5 parallel → $20k per slot
|
||
- Prevents first trade from consuming all capital
|
||
|
||
4. **Absolute Maximum per Trade**
|
||
- `MAX_TRADE_VALUE` sets hard limit (default: 0 = unlimited)
|
||
- If calculated trade exceeds limit → quantity reduced to fit
|
||
- If price too high for even 1 share → trade rejected
|
||
- Example: MAX_TRADE_VALUE=$2000, price $3000 → rejected
|
||
|
||
**Formula:**
|
||
```
|
||
capitalPerSlot = totalCapital / maxParallelTrades
|
||
adjustedPercent = basePercent * (0.5 + confidence * 0.5)
|
||
positionValue = capitalPerSlot * (adjustedPercent / 100)
|
||
quantity = floor(positionValue / currentPrice)
|
||
```
|
||
|
||
**Example (Normal Strategy):**
|
||
- Total: $100,000
|
||
- Max Parallel: 5
|
||
- Per Slot: $20,000
|
||
- Confidence: 0.72
|
||
- Base: 4.0%
|
||
- Multiplier: 0.86x
|
||
- Adjusted: 3.44%
|
||
- Position: $20,000 × 3.44% = $688
|
||
- Price: $180
|
||
- **Quantity: 3 shares**
|
||
|
||
### SELL Triggers
|
||
|
||
Positions are automatically sold when:
|
||
|
||
1. **Take Profit**: Profit ≥ `TAKE_PROFIT_PERCENT` (default: 5%)
|
||
2. **Negative Sentiment**: Strong negative news (if `SELL_ON_NEGATIVE_SENTIMENT=true`)
|
||
3. **Stop Loss**: Loss ≥ `STOP_LOSS_PERCENT` (default: 3%)
|
||
|
||
All SELL trades require minimum hold time (`HOLD_TIME_MINUTES`) before execution.
|
||
|
||
```bash
|
||
go build -o aitrade ./cmd/aitrade
|
||
```
|
||
|
||
## Running
|
||
|
||
```bash
|
||
./aitrade
|
||
```
|
||
|
||
**Note:** IB Gateway or TWS must be running and configured to accept API connections on the specified port.
|
||
|
||
## Testing
|
||
|
||
```bash
|
||
go test ./...
|
||
```
|
||
|
||
## Architecture
|
||
|
||
```
|
||
/projects/Private/aitrade/
|
||
├── cmd/aitrade/ # Application entry point
|
||
├── pkg/
|
||
│ ├── app/
|
||
│ │ ├── client/ # IB Gateway client
|
||
│ │ ├── news/ # News aggregation
|
||
│ │ ├── strategy/ # Trading strategies
|
||
│ │ └── app.go # Main orchestrator
|
||
│ ├── config/ # Configuration
|
||
│ ├── db/ # Database layer
|
||
│ └── model/ # Data models
|
||
└── migrations/ # SQL migrations
|
||
```
|
||
|
||
## Strategy Comparison
|
||
|
||
| Strategy | Max Parallel | Max/Hour | Position Size | Stop-Loss | Sentiment Threshold |
|
||
|-------------|--------------|----------|---------------|-----------|---------------------|
|
||
| Defensive | 2 | 3 | 1.5% | 2% | >0.5 (3+ pos news) |
|
||
| Normal | 5 | 6 | 4.0% | 3% | >0.3 (2+ pos news) |
|
||
| Aggressive | 10 | 12 | 7.5% | 5% | >0.0 (1+ pos news) |
|
||
|
||
## Database Schema
|
||
|
||
- `trades` - Trade lifecycle tracking (pending → submitted → filled → completed)
|
||
- `balances` - Account balance snapshots
|
||
- `news_articles` - Aggregated news with sentiment scores
|
||
- `schema_migrations` - Migration version tracking
|
||
|
||
## License
|
||
|
||
Private project
|