This guide explains how to set up and manage the PostgreSQL database for the NIJA trading platform.
Create a .env file with your PostgreSQL credentials:
# PostgreSQL Connection
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=nija
POSTGRES_USER=nija_user
POSTGRES_PASSWORD=your_secure_password
# Or use a single DATABASE_URL (for cloud deployments)
DATABASE_URL=postgresql://nija_user:password@localhost:5432/nija
# Login to PostgreSQL
psql -U postgres
# Create database and user
CREATE DATABASE nija;
CREATE USER nija_user WITH PASSWORD 'your_secure_password';
GRANT ALL PRIVILEGES ON DATABASE nija TO nija_user;
# Exit psql
\q
# Initialize database schema
python init_database.py
# Or with demo user for testing
python init_database.py --demo-user
This will create all necessary tables:
users - User accountsbroker_credentials - Encrypted API credentialsuser_permissions - Trading limits and permissionstrading_instances - Bot instancespositions - Active trading positionstrades - Trade historydaily_statistics - Daily aggregated statsfrom database.db_connection import init_database, test_connection
# Initialize connection
init_database()
# Test connection
if test_connection():
print("✅ Database connected!")
When you modify database models, create a migration:
# Auto-generate migration from model changes
alembic revision --autogenerate -m "Add new field to User model"
# Run all pending migrations
alembic upgrade head
# Rollback one migration
alembic downgrade -1
# View migration history
alembic history
# View current version
alembic current
# Create empty migration
alembic revision -m "Custom migration"
# Edit the generated file in alembic/versions/
# Implement upgrade() and downgrade() functions
| Column | Type | Description |
|---|---|---|
| id | Integer | Primary key (auto-increment) |
| user_id | String(50) | Unique user identifier |
| String(255) | User email (unique) | |
| password_hash | String(255) | Hashed password (Argon2) |
| subscription_tier | String(20) | basic/pro/enterprise |
| enabled | Boolean | Account status |
| created_at | DateTime | Registration timestamp |
| updated_at | DateTime | Last update timestamp |
| Column | Type | Description |
|---|---|---|
| id | Integer | Primary key |
| user_id | String(50) | Foreign key to users |
| broker_name | String(50) | Broker name (coinbase, kraken, etc.) |
| encrypted_api_key | Text | Encrypted API key |
| encrypted_api_secret | Text | Encrypted API secret |
| encrypted_additional_params | Text | Additional broker-specific params |
| created_at | DateTime | Creation timestamp |
| updated_at | DateTime | Last update timestamp |
| Column | Type | Description |
|---|---|---|
| id | Integer | Primary key |
| user_id | String(50) | Foreign key to users |
| pair | String(20) | Trading pair (BTC-USD) |
| side | String(10) | long/short |
| size | Numeric(18,8) | Position size |
| entry_price | Numeric(18,8) | Entry price |
| current_price | Numeric(18,8) | Current market price |
| pnl | Numeric(18,8) | Profit/Loss in USD |
| pnl_percent | Numeric(8,4) | P&L percentage |
| opened_at | DateTime | Position open time |
| closed_at | DateTime | Position close time (null if open) |
| status | String(20) | open/closed |
| Column | Type | Description |
|---|---|---|
| id | Integer | Primary key |
| user_id | String(50) | Foreign key to users |
| pair | String(20) | Trading pair |
| side | String(10) | buy/sell |
| size | Numeric(18,8) | Trade size |
| entry_price | Numeric(18,8) | Entry price |
| exit_price | Numeric(18,8) | Exit price |
| pnl | Numeric(18,8) | Realized P&L |
| pnl_percent | Numeric(8,4) | P&L percentage |
| fees | Numeric(18,8) | Trading fees |
| opened_at | DateTime | Trade open time |
| closed_at | DateTime | Trade close time |
| status | String(20) | open/closed |
The database uses SQLAlchemy’s connection pooling for optimal performance:
from database.db_connection import init_database
# Initialize with custom pool settings
init_database(
pool_size=10, # Number of connections to keep in pool
max_overflow=20, # Maximum overflow connections
pool_timeout=30, # Timeout for getting connection (seconds)
pool_recycle=3600 # Recycle connections after 1 hour
)
from database.db_connection import get_pool_status
# Get current pool status
status = get_pool_status()
print(f"Pool size: {status['size']}")
print(f"Checked out: {status['checked_out']}")
print(f"Checked in: {status['checked_in']}")
print(f"Overflow: {status['overflow']}")
from database.db_connection import check_database_health
# Check database health
health = check_database_health()
if health['healthy']:
print("✅ Database is healthy")
print(f"Pool status: {health['pool']}")
else:
print(f"❌ Database unhealthy: {health['error']}")
Always use context managers for database sessions:
from database.db_connection import get_db_session
from database.models import User
# Automatic commit/rollback
with get_db_session() as session:
user = session.query(User).filter_by(email='user@example.com').first()
# Session automatically commits on success, rolls back on error
Always close database connections when done:
from database.db_connection import close_database
# At application shutdown
close_database()
Ensure queries use indexes for performance:
-- Check query plan
EXPLAIN ANALYZE SELECT * FROM trades WHERE user_id = 'user_123';
-- Should use index: ix_trades_user_id
# Backup database
pg_dump -U nija_user -d nija > backup_$(date +%Y%m%d_%H%M%S).sql
# Restore from backup
psql -U nija_user -d nija < backup_20260129_131500.sql
# Check if PostgreSQL is running
sudo systemctl status postgresql
# Start PostgreSQL
sudo systemctl start postgresql
-- Grant permissions to user
GRANT ALL PRIVILEGES ON DATABASE nija TO nija_user;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO nija_user;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO nija_user;
# Check current migration version
alembic current
# View history
alembic history
# Force to specific version (careful!)
alembic stamp head
For production, use managed PostgreSQL services:
EXPLAIN ANALYZE to optimize slow queriesVACUUM ANALYZE regularly on high-churn tablesFor issues or questions:
tail -f /var/log/postgresql/postgresql-14-main.logalembic historypsql -U nija_user -d nijaDocument Version: 1.0 Last Updated: January 29, 2026 Status: Production Ready