Files
XauBot/docker/init-db/01-schema.sql
T
GifariKemal 7af9183af3 feat: Smart AI Trading Bot for XAUUSD with ML and SMC
- XGBoost ML model with 37 features for market direction prediction
- Smart Money Concepts (SMC): Order Blocks, FVG, BOS, CHoCH
- HMM market regime detection (trending/ranging/volatile)
- ATR-based stop loss with 1.5 ATR minimum distance
- Broker-level SL protection with fallback
- Time-based exit (max 6 hours per trade)
- Session-aware trading optimized for London/NY overlap
- Auto-retraining based on market conditions
- Telegram notifications and web dashboard
- Backtest results: 63.9% win rate, 2.64 profit factor, 4.83 Sharpe

Backtest period: Jan 2025 - Feb 2026, 654 trades, $4,189 net P/L

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 09:01:35 +07:00

460 lines
13 KiB
PL/PgSQL

-- ============================================================
-- Trading Bot Database Schema
-- ============================================================
-- Version: 1.0.0
-- Created: 2026-02-05
-- Description: PostgreSQL schema for AI Trading Bot data persistence
-- ============================================================
-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- ============================================================
-- TRADES TABLE - Main trade history
-- ============================================================
CREATE TABLE IF NOT EXISTS trades (
id SERIAL PRIMARY KEY,
ticket BIGINT UNIQUE NOT NULL,
symbol VARCHAR(20) NOT NULL DEFAULT 'XAUUSD',
direction VARCHAR(4) NOT NULL CHECK (direction IN ('BUY', 'SELL')),
-- Prices
entry_price DECIMAL(12,5) NOT NULL,
exit_price DECIMAL(12,5),
stop_loss DECIMAL(12,5) DEFAULT 0,
take_profit DECIMAL(12,5) DEFAULT 0,
-- Size & Result
lot_size DECIMAL(8,4) NOT NULL,
profit_usd DECIMAL(12,2),
profit_pips DECIMAL(10,2),
-- Timing
opened_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
closed_at TIMESTAMPTZ,
duration_seconds INT,
-- Market Context at Entry
entry_regime VARCHAR(30),
entry_volatility VARCHAR(20),
entry_session VARCHAR(30),
entry_spread DECIMAL(8,2),
entry_atr DECIMAL(10,5),
-- SMC Signals
smc_signal VARCHAR(10),
smc_confidence DECIMAL(5,4),
smc_reason TEXT,
smc_fvg_detected BOOLEAN DEFAULT FALSE,
smc_ob_detected BOOLEAN DEFAULT FALSE,
smc_bos_detected BOOLEAN DEFAULT FALSE,
smc_choch_detected BOOLEAN DEFAULT FALSE,
-- ML Signals
ml_signal VARCHAR(10),
ml_confidence DECIMAL(5,4),
-- Dynamic Analysis
market_quality VARCHAR(20),
market_score INT,
dynamic_threshold DECIMAL(5,4),
-- Exit Details
exit_reason VARCHAR(50),
exit_regime VARCHAR(30),
exit_ml_signal VARCHAR(10),
exit_ml_confidence DECIMAL(5,4),
-- Balance Tracking
balance_before DECIMAL(12,2),
balance_after DECIMAL(12,2),
equity_at_entry DECIMAL(12,2),
-- Features (JSONB for flexibility)
features_entry JSONB DEFAULT '{}',
features_exit JSONB DEFAULT '{}',
-- Meta
bot_version VARCHAR(20) DEFAULT '2.1',
trade_mode VARCHAR(30) DEFAULT 'SMC-ONLY',
-- Timestamps
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================
-- TRAINING_RUNS TABLE - ML model training history
-- ============================================================
CREATE TABLE IF NOT EXISTS training_runs (
id SERIAL PRIMARY KEY,
run_id UUID DEFAULT uuid_generate_v4(),
-- Timing
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
completed_at TIMESTAMPTZ,
duration_seconds INT,
-- Configuration
training_type VARCHAR(20) NOT NULL CHECK (training_type IN ('daily', 'weekend', 'manual', 'initial')),
bars_used INT,
num_boost_rounds INT,
-- Results - HMM
hmm_trained BOOLEAN DEFAULT FALSE,
hmm_n_regimes INT,
-- Results - XGBoost
xgb_trained BOOLEAN DEFAULT FALSE,
train_auc DECIMAL(6,5),
test_auc DECIMAL(6,5),
train_accuracy DECIMAL(6,5),
test_accuracy DECIMAL(6,5),
-- Model Paths
model_path VARCHAR(255),
backup_path VARCHAR(255),
-- Status
success BOOLEAN DEFAULT FALSE,
error_message TEXT,
-- Rollback
rolled_back BOOLEAN DEFAULT FALSE,
rollback_reason TEXT,
rollback_at TIMESTAMPTZ,
-- Meta
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================
-- MARKET_SNAPSHOTS TABLE - Periodic market state (time-series)
-- ============================================================
CREATE TABLE IF NOT EXISTS market_snapshots (
id SERIAL PRIMARY KEY,
snapshot_time TIMESTAMPTZ NOT NULL,
symbol VARCHAR(20) NOT NULL DEFAULT 'XAUUSD',
-- Price
price DECIMAL(12,5) NOT NULL,
-- OHLC (current candle)
open_price DECIMAL(12,5),
high_price DECIMAL(12,5),
low_price DECIMAL(12,5),
close_price DECIMAL(12,5),
-- Market State
regime VARCHAR(30),
volatility VARCHAR(20),
session VARCHAR(30),
atr DECIMAL(10,5),
spread DECIMAL(8,2),
-- Signals
ml_signal VARCHAR(10),
ml_confidence DECIMAL(5,4),
smc_signal VARCHAR(10),
smc_confidence DECIMAL(5,4),
-- Position State
open_positions INT DEFAULT 0,
floating_pnl DECIMAL(12,2) DEFAULT 0,
-- Features Snapshot
features JSONB DEFAULT '{}',
-- Meta
created_at TIMESTAMPTZ DEFAULT NOW(),
-- Composite unique constraint
UNIQUE (snapshot_time, symbol)
);
-- ============================================================
-- SIGNALS TABLE - Every signal generated
-- ============================================================
CREATE TABLE IF NOT EXISTS signals (
id SERIAL PRIMARY KEY,
signal_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
symbol VARCHAR(20) NOT NULL DEFAULT 'XAUUSD',
price DECIMAL(12,5) NOT NULL,
-- Signal Details
signal_type VARCHAR(10) CHECK (signal_type IN ('BUY', 'SELL', 'NONE', 'HOLD')),
signal_source VARCHAR(20), -- 'SMC', 'ML', 'COMBINED', 'SMC-ONLY'
combined_confidence DECIMAL(5,4),
-- SMC Analysis
smc_signal VARCHAR(10),
smc_confidence DECIMAL(5,4),
smc_fvg BOOLEAN DEFAULT FALSE,
smc_ob BOOLEAN DEFAULT FALSE,
smc_bos BOOLEAN DEFAULT FALSE,
smc_choch BOOLEAN DEFAULT FALSE,
smc_reason TEXT,
-- ML Analysis
ml_signal VARCHAR(10),
ml_confidence DECIMAL(5,4),
-- Market Context
regime VARCHAR(30),
session VARCHAR(30),
volatility VARCHAR(20),
market_score INT,
dynamic_threshold DECIMAL(5,4),
-- Execution
executed BOOLEAN DEFAULT FALSE,
execution_reason VARCHAR(100),
trade_ticket BIGINT,
-- Meta
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================
-- DAILY_SUMMARIES TABLE - Daily performance tracking
-- ============================================================
CREATE TABLE IF NOT EXISTS daily_summaries (
id SERIAL PRIMARY KEY,
summary_date DATE UNIQUE NOT NULL,
-- Trades
total_trades INT DEFAULT 0,
winning_trades INT DEFAULT 0,
losing_trades INT DEFAULT 0,
breakeven_trades INT DEFAULT 0,
-- P/L
gross_profit DECIMAL(12,2) DEFAULT 0,
gross_loss DECIMAL(12,2) DEFAULT 0,
net_profit DECIMAL(12,2) DEFAULT 0,
-- Balance
start_balance DECIMAL(12,2),
end_balance DECIMAL(12,2),
-- Metrics
win_rate DECIMAL(5,2),
profit_factor DECIMAL(8,4),
average_win DECIMAL(12,2),
average_loss DECIMAL(12,2),
largest_win DECIMAL(12,2),
largest_loss DECIMAL(12,2),
-- Sessions
trades_sydney INT DEFAULT 0,
trades_tokyo INT DEFAULT 0,
trades_london INT DEFAULT 0,
trades_ny INT DEFAULT 0,
trades_golden INT DEFAULT 0,
-- SMC Performance
fvg_trades INT DEFAULT 0,
fvg_wins INT DEFAULT 0,
ob_trades INT DEFAULT 0,
ob_wins INT DEFAULT 0,
-- Meta
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================
-- BOT_STATUS TABLE - Bot health and status tracking
-- ============================================================
CREATE TABLE IF NOT EXISTS bot_status (
id SERIAL PRIMARY KEY,
status_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- Status
is_running BOOLEAN DEFAULT TRUE,
status VARCHAR(20) DEFAULT 'active', -- 'active', 'paused', 'stopped', 'error'
-- Performance
loop_count INT DEFAULT 0,
avg_execution_ms DECIMAL(10,2),
uptime_seconds INT DEFAULT 0,
-- Account
balance DECIMAL(12,2),
equity DECIMAL(12,2),
margin_used DECIMAL(12,2),
-- Positions
open_positions INT DEFAULT 0,
floating_pnl DECIMAL(12,2),
-- Risk State
daily_pnl DECIMAL(12,2),
risk_mode VARCHAR(20), -- 'normal', 'recovery', 'protected', 'stopped'
-- Session
current_session VARCHAR(30),
is_golden_time BOOLEAN DEFAULT FALSE,
-- Error
last_error TEXT,
last_error_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================
-- INDEXES for fast queries
-- ============================================================
-- Trades indexes
CREATE INDEX IF NOT EXISTS idx_trades_opened_at ON trades(opened_at DESC);
CREATE INDEX IF NOT EXISTS idx_trades_closed_at ON trades(closed_at DESC);
CREATE INDEX IF NOT EXISTS idx_trades_symbol ON trades(symbol);
CREATE INDEX IF NOT EXISTS idx_trades_direction ON trades(direction);
CREATE INDEX IF NOT EXISTS idx_trades_profit ON trades(profit_usd);
CREATE INDEX IF NOT EXISTS idx_trades_exit_reason ON trades(exit_reason);
CREATE INDEX IF NOT EXISTS idx_trades_entry_session ON trades(entry_session);
-- Training runs indexes
CREATE INDEX IF NOT EXISTS idx_training_started_at ON training_runs(started_at DESC);
CREATE INDEX IF NOT EXISTS idx_training_type ON training_runs(training_type);
-- Snapshots indexes
CREATE INDEX IF NOT EXISTS idx_snapshots_time ON market_snapshots(snapshot_time DESC);
CREATE INDEX IF NOT EXISTS idx_snapshots_symbol_time ON market_snapshots(symbol, snapshot_time DESC);
-- Signals indexes
CREATE INDEX IF NOT EXISTS idx_signals_time ON signals(signal_time DESC);
CREATE INDEX IF NOT EXISTS idx_signals_executed ON signals(executed);
CREATE INDEX IF NOT EXISTS idx_signals_type ON signals(signal_type);
-- Daily summaries index
CREATE INDEX IF NOT EXISTS idx_daily_date ON daily_summaries(summary_date DESC);
-- Bot status index
CREATE INDEX IF NOT EXISTS idx_bot_status_time ON bot_status(status_time DESC);
-- ============================================================
-- FUNCTIONS for automatic updates
-- ============================================================
-- Function to update updated_at timestamp
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
-- Trigger for trades table
DROP TRIGGER IF EXISTS update_trades_updated_at ON trades;
CREATE TRIGGER update_trades_updated_at
BEFORE UPDATE ON trades
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Trigger for daily_summaries table
DROP TRIGGER IF EXISTS update_daily_summaries_updated_at ON daily_summaries;
CREATE TRIGGER update_daily_summaries_updated_at
BEFORE UPDATE ON daily_summaries
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- ============================================================
-- VIEWS for easy querying
-- ============================================================
-- Recent trades view
CREATE OR REPLACE VIEW v_recent_trades AS
SELECT
ticket,
direction,
entry_price,
exit_price,
lot_size,
profit_usd,
profit_pips,
duration_seconds,
entry_session,
smc_reason,
ml_confidence,
exit_reason,
opened_at,
closed_at
FROM trades
WHERE closed_at IS NOT NULL
ORDER BY closed_at DESC
LIMIT 100;
-- Daily performance view
CREATE OR REPLACE VIEW v_daily_performance AS
SELECT
DATE(closed_at) as trade_date,
COUNT(*) as total_trades,
SUM(CASE WHEN profit_usd > 0 THEN 1 ELSE 0 END) as wins,
SUM(CASE WHEN profit_usd < 0 THEN 1 ELSE 0 END) as losses,
SUM(profit_usd) as net_profit,
ROUND(AVG(profit_usd)::numeric, 2) as avg_profit,
ROUND((SUM(CASE WHEN profit_usd > 0 THEN 1 ELSE 0 END)::numeric /
NULLIF(COUNT(*), 0) * 100), 1) as win_rate
FROM trades
WHERE closed_at IS NOT NULL
GROUP BY DATE(closed_at)
ORDER BY trade_date DESC;
-- SMC performance view
CREATE OR REPLACE VIEW v_smc_performance AS
SELECT
CASE
WHEN smc_fvg_detected THEN 'FVG'
WHEN smc_ob_detected THEN 'OB'
WHEN smc_bos_detected THEN 'BOS'
ELSE 'OTHER'
END as pattern_type,
COUNT(*) as total_trades,
SUM(CASE WHEN profit_usd > 0 THEN 1 ELSE 0 END) as wins,
SUM(profit_usd) as total_profit,
ROUND(AVG(profit_usd)::numeric, 2) as avg_profit,
ROUND((SUM(CASE WHEN profit_usd > 0 THEN 1 ELSE 0 END)::numeric /
NULLIF(COUNT(*), 0) * 100), 1) as win_rate
FROM trades
WHERE closed_at IS NOT NULL
GROUP BY pattern_type
ORDER BY total_trades DESC;
-- Session performance view
CREATE OR REPLACE VIEW v_session_performance AS
SELECT
entry_session,
COUNT(*) as total_trades,
SUM(CASE WHEN profit_usd > 0 THEN 1 ELSE 0 END) as wins,
SUM(profit_usd) as total_profit,
ROUND(AVG(profit_usd)::numeric, 2) as avg_profit,
ROUND((SUM(CASE WHEN profit_usd > 0 THEN 1 ELSE 0 END)::numeric /
NULLIF(COUNT(*), 0) * 100), 1) as win_rate
FROM trades
WHERE closed_at IS NOT NULL AND entry_session IS NOT NULL
GROUP BY entry_session
ORDER BY total_trades DESC;
-- ============================================================
-- INITIAL DATA / SEED
-- ============================================================
-- Insert initial bot status
INSERT INTO bot_status (status, is_running, risk_mode)
VALUES ('initialized', false, 'normal')
ON CONFLICT DO NOTHING;
-- ============================================================
-- GRANTS (if needed for specific users)
-- ============================================================
-- GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO trading_bot;
-- GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO trading_bot;
-- ============================================================
-- Done!
-- ============================================================