# 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= 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