Refactor database configuration and schema for Crypto Trading Bot Platform

- Updated `docker-compose.yml` to remove hardcoded passwords, relying on environment variables for PostgreSQL and Redis configurations.
- Modified `env.template` to reflect new password settings and ensure secure handling of sensitive information.
- Introduced a new `database/connection.py` file for improved database connection management, including connection pooling and session handling.
- Updated `database/models.py` to align with the new schema in `schema_clean.sql`, utilizing JSONB for optimized data storage.
- Enhanced `setup.md` documentation to clarify the initialization process and emphasize the importance of the `.env` file for configuration.
- Added a new `scripts/init_database.py` script for automated database initialization and verification, ensuring all tables are created as expected.
This commit is contained in:
Vasily.onl
2025-05-30 18:20:38 +08:00
parent 8121ce0430
commit 73b7e8bb9d
12 changed files with 781 additions and 142 deletions

View File

@@ -7,21 +7,11 @@ 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;
-- The database user is automatically created by Docker with the POSTGRES_USER and POSTGRES_PASSWORD
-- environment variables, so we don't need to create it here
-- Create initial comment
COMMENT ON DATABASE dashboard IS 'Crypto Trading Bot Dashboard Database';
-- Execute the main schema file
\i /docker-entrypoint-initdb.d/schema.sql
-- Execute the clean schema file (without TimescaleDB hypertables for simpler setup)
\i /docker-entrypoint-initdb.d/schema_clean.sql

View File

@@ -1,11 +1,10 @@
-- Database Schema for Crypto Trading Bot Platform
-- Following PRD specifications with optimized schema for time-series data
-- Version: 1.0
-- Database Schema for Crypto Trading Bot Platform (Clean Version)
-- Following PRD specifications - optimized for rapid development
-- Version: 1.0 (without hypertables for now)
-- Author: Generated following PRD requirements
-- Create extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "timescaledb" CASCADE;
-- Set timezone to UTC for consistency
SET timezone = 'UTC';
@@ -15,7 +14,6 @@ SET timezone = 'UTC';
-- ========================================
-- OHLCV Market Data (primary table for bot operations)
-- This is the main table that bots will use for trading decisions
CREATE TABLE market_data (
id SERIAL PRIMARY KEY,
exchange VARCHAR(50) NOT NULL DEFAULT 'okx',
@@ -32,34 +30,28 @@ CREATE TABLE market_data (
CONSTRAINT unique_market_data UNIQUE(exchange, symbol, timeframe, timestamp)
);
-- Convert to hypertable for TimescaleDB optimization
SELECT create_hypertable('market_data', 'timestamp', if_not_exists => TRUE);
-- Create optimized indexes for market data
CREATE INDEX idx_market_data_lookup ON market_data(symbol, timeframe, timestamp);
CREATE INDEX idx_market_data_recent ON market_data(timestamp DESC) WHERE timestamp > NOW() - INTERVAL '7 days';
CREATE INDEX idx_market_data_symbol ON market_data(symbol);
CREATE INDEX idx_market_data_timeframe ON market_data(timeframe);
CREATE INDEX idx_market_data_recent ON market_data(timestamp DESC);
-- Raw Trade Data (optional, for detailed backtesting only)
-- This table is partitioned by timestamp for better performance
-- Raw Trade Data (for debugging, compliance, and detailed backtesting)
CREATE TABLE raw_trades (
id SERIAL PRIMARY KEY,
exchange VARCHAR(50) NOT NULL DEFAULT 'okx',
symbol VARCHAR(20) NOT NULL,
timestamp TIMESTAMPTZ NOT NULL,
type VARCHAR(10) NOT NULL, -- trade, order, balance, tick, books
data JSONB NOT NULL, -- response from the exchange
data_type VARCHAR(20) NOT NULL, -- ticker, trade, orderbook, candle, balance
raw_data JSONB NOT NULL, -- Complete API response
created_at TIMESTAMPTZ DEFAULT NOW()
) PARTITION BY RANGE (timestamp);
);
-- Create initial partition for current month
CREATE TABLE raw_trades_current PARTITION OF raw_trades
FOR VALUES FROM (date_trunc('month', NOW())) TO (date_trunc('month', NOW()) + INTERVAL '1 month');
-- Index for raw trades
-- Create indexes for raw trades (optimized for time-series queries)
CREATE INDEX idx_raw_trades_symbol_time ON raw_trades(symbol, timestamp);
CREATE INDEX idx_raw_trades_type ON raw_trades(type);
CREATE INDEX idx_raw_trades_type ON raw_trades(data_type);
CREATE INDEX idx_raw_trades_timestamp ON raw_trades(timestamp DESC);
CREATE INDEX idx_raw_trades_recent ON raw_trades(created_at DESC);
-- ========================================
-- BOT MANAGEMENT TABLES
@@ -106,9 +98,6 @@ CREATE TABLE signals (
CONSTRAINT chk_confidence CHECK (confidence >= 0 AND confidence <= 1)
);
-- Convert signals to hypertable for TimescaleDB optimization
SELECT create_hypertable('signals', 'timestamp', if_not_exists => TRUE);
-- Indexes for signals
CREATE INDEX idx_signals_bot_time ON signals(bot_id, timestamp);
CREATE INDEX idx_signals_type ON signals(signal_type);
@@ -137,9 +126,6 @@ CREATE TABLE trades (
CONSTRAINT chk_non_negative_fees CHECK (fees >= 0)
);
-- Convert trades to hypertable for TimescaleDB optimization
SELECT create_hypertable('trades', 'timestamp', if_not_exists => TRUE);
-- Indexes for trades
CREATE INDEX idx_trades_bot_time ON trades(bot_id, timestamp);
CREATE INDEX idx_trades_side ON trades(side);
@@ -172,9 +158,6 @@ CREATE TABLE bot_performance (
CONSTRAINT chk_winning_trades_logic CHECK (winning_trades <= total_trades)
);
-- Convert bot_performance to hypertable for TimescaleDB optimization
SELECT create_hypertable('bot_performance', 'timestamp', if_not_exists => TRUE);
-- Indexes for bot performance
CREATE INDEX idx_bot_performance_bot_time ON bot_performance(bot_id, timestamp);
CREATE INDEX idx_bot_performance_timestamp ON bot_performance(timestamp);
@@ -198,24 +181,6 @@ CREATE TRIGGER trigger_update_bot_timestamp
FOR EACH ROW
EXECUTE FUNCTION update_bot_timestamp();
-- Function to create monthly partition for raw_trades
CREATE OR REPLACE FUNCTION create_monthly_partition_for_raw_trades(partition_date DATE)
RETURNS VOID AS $$
DECLARE
partition_name TEXT;
start_date DATE;
end_date DATE;
BEGIN
start_date := date_trunc('month', partition_date);
end_date := start_date + INTERVAL '1 month';
partition_name := 'raw_trades_' || to_char(start_date, 'YYYY_MM');
EXECUTE format('CREATE TABLE IF NOT EXISTS %I PARTITION OF raw_trades
FOR VALUES FROM (%L) TO (%L)',
partition_name, start_date, end_date);
END;
$$ LANGUAGE plpgsql;
-- ========================================
-- VIEWS FOR COMMON QUERIES
-- ========================================
@@ -311,13 +276,15 @@ ON CONFLICT (exchange) DO NOTHING;
-- ========================================
COMMENT ON TABLE market_data IS 'Primary OHLCV market data table optimized for bot operations and backtesting';
COMMENT ON TABLE raw_trades IS 'Optional raw trade data for detailed backtesting (partitioned by month)';
COMMENT ON TABLE raw_trades IS 'Raw API responses and trade data for debugging, compliance, and detailed analysis';
COMMENT ON TABLE bots IS 'Bot instance management with JSON configuration references';
COMMENT ON TABLE signals IS 'Trading signals generated by strategies with confidence scores';
COMMENT ON TABLE trades IS 'Virtual trade execution records with P&L tracking';
COMMENT ON TABLE bot_performance IS 'Portfolio performance snapshots for visualization';
COMMENT ON COLUMN market_data.timestamp IS 'Right-aligned timestamp (candle close time) following exchange standards';
COMMENT ON COLUMN raw_trades.data_type IS 'Type of raw data: ticker, trade, orderbook, candle, balance';
COMMENT ON COLUMN raw_trades.raw_data IS 'Complete unprocessed API response in JSONB format';
COMMENT ON COLUMN bots.config_file IS 'Path to JSON configuration file for strategy parameters';
COMMENT ON COLUMN signals.confidence IS 'Signal confidence score from 0.0000 to 1.0000';
COMMENT ON COLUMN trades.pnl IS 'Profit/Loss for this specific trade in base currency';