DDL schemas for Trading Platform: - User management - Authentication - Payments - Education - ML predictions - Trading data Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
427 lines
15 KiB
PL/PgSQL
427 lines
15 KiB
PL/PgSQL
-- ============================================================================
|
|
-- OrbiQuant IA - Esquema INVESTMENT
|
|
-- ============================================================================
|
|
-- Archivo: 04_investment_schema.sql
|
|
-- Descripción: Cuentas de inversión, productos y gestión de portafolios
|
|
-- Fecha: 2025-12-05
|
|
-- ============================================================================
|
|
|
|
SET search_path TO investment;
|
|
|
|
-- ============================================================================
|
|
-- TIPOS ENUMERADOS
|
|
-- ============================================================================
|
|
|
|
CREATE TYPE product_type_enum AS ENUM (
|
|
'fixed_return', -- Rendimiento fijo objetivo (ej: 5% mensual)
|
|
'variable_return', -- Rendimiento variable con reparto de utilidades
|
|
'long_term_portfolio' -- Cartera de largo plazo (acciones, ETFs)
|
|
);
|
|
|
|
CREATE TYPE account_status_enum AS ENUM (
|
|
'pending_kyc', -- Esperando verificación KYC
|
|
'pending_deposit', -- Esperando depósito inicial
|
|
'active', -- Cuenta activa operando
|
|
'paused', -- Pausada por usuario o admin
|
|
'suspended', -- Suspendida por compliance
|
|
'closed' -- Cerrada
|
|
);
|
|
|
|
CREATE TYPE fee_type_enum AS ENUM (
|
|
'management', -- Comisión de administración
|
|
'performance', -- Comisión de rendimiento
|
|
'deposit', -- Comisión de depósito
|
|
'withdrawal', -- Comisión de retiro
|
|
'subscription' -- Comisión de suscripción
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- TABLA: products
|
|
-- Descripción: Productos de inversión disponibles
|
|
-- ============================================================================
|
|
CREATE TABLE IF NOT EXISTS products (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
|
|
-- Identificación
|
|
name VARCHAR(100) NOT NULL,
|
|
slug VARCHAR(100) NOT NULL UNIQUE,
|
|
description TEXT,
|
|
short_description VARCHAR(500),
|
|
|
|
-- Tipo y riesgo
|
|
product_type product_type_enum NOT NULL,
|
|
risk_profile public.risk_profile_enum NOT NULL,
|
|
|
|
-- Objetivos
|
|
target_monthly_return DECIMAL(5,2), -- % objetivo mensual
|
|
max_drawdown DECIMAL(5,2), -- % máximo drawdown permitido
|
|
guaranteed_return BOOLEAN DEFAULT FALSE, -- SIEMPRE FALSE para cumplimiento
|
|
|
|
-- Comisiones
|
|
management_fee_percent DECIMAL(5,2) DEFAULT 0, -- % anual sobre AUM
|
|
performance_fee_percent DECIMAL(5,2) DEFAULT 0, -- % sobre ganancias
|
|
profit_share_platform DECIMAL(5,2), -- % de utilidades para plataforma (ej: 50)
|
|
profit_share_client DECIMAL(5,2), -- % de utilidades para cliente (ej: 50)
|
|
|
|
-- Límites
|
|
min_investment DECIMAL(15,2) DEFAULT 100,
|
|
max_investment DECIMAL(15,2),
|
|
min_investment_period_days INT DEFAULT 30,
|
|
|
|
-- Restricciones
|
|
requires_kyc_level INT DEFAULT 1,
|
|
allowed_risk_profiles public.risk_profile_enum[],
|
|
|
|
-- Bot/Agente asociado
|
|
default_bot_id UUID REFERENCES trading.bots(id),
|
|
|
|
-- Estado
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
is_visible BOOLEAN DEFAULT TRUE,
|
|
|
|
-- Metadata
|
|
terms_url TEXT,
|
|
risk_disclosure_url TEXT,
|
|
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_products_slug ON products(slug);
|
|
CREATE INDEX idx_products_type ON products(product_type);
|
|
CREATE INDEX idx_products_risk ON products(risk_profile);
|
|
|
|
-- ============================================================================
|
|
-- TABLA: accounts
|
|
-- Descripción: Cuentas de inversión de usuarios
|
|
-- ============================================================================
|
|
CREATE TABLE IF NOT EXISTS accounts (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
|
|
-- Referencias
|
|
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE RESTRICT,
|
|
product_id UUID NOT NULL REFERENCES products(id),
|
|
bot_id UUID REFERENCES trading.bots(id),
|
|
|
|
-- Identificación
|
|
account_number VARCHAR(20) NOT NULL UNIQUE, -- OQ-INV-XXXXXX
|
|
name VARCHAR(100),
|
|
|
|
-- Moneda
|
|
currency CHAR(3) DEFAULT 'USD',
|
|
|
|
-- Balances
|
|
initial_deposit DECIMAL(15,2) NOT NULL,
|
|
current_balance DECIMAL(15,2) NOT NULL,
|
|
available_balance DECIMAL(15,2) NOT NULL, -- Balance disponible para retiro
|
|
reserved_balance DECIMAL(15,2) DEFAULT 0, -- En operaciones abiertas
|
|
|
|
-- Rendimiento acumulado
|
|
total_profit DECIMAL(15,2) DEFAULT 0,
|
|
total_fees_paid DECIMAL(15,2) DEFAULT 0,
|
|
total_deposits DECIMAL(15,2) DEFAULT 0,
|
|
total_withdrawals DECIMAL(15,2) DEFAULT 0,
|
|
|
|
-- Métricas de rendimiento
|
|
total_return_percent DECIMAL(8,4) DEFAULT 0,
|
|
monthly_return_percent DECIMAL(8,4) DEFAULT 0,
|
|
max_drawdown_percent DECIMAL(5,2) DEFAULT 0,
|
|
sharpe_ratio DECIMAL(5,2),
|
|
|
|
-- Estado
|
|
status account_status_enum DEFAULT 'pending_deposit',
|
|
activated_at TIMESTAMPTZ,
|
|
paused_at TIMESTAMPTZ,
|
|
closed_at TIMESTAMPTZ,
|
|
|
|
-- Configuración del usuario
|
|
auto_compound BOOLEAN DEFAULT TRUE, -- Reinvertir ganancias
|
|
max_drawdown_override DECIMAL(5,2), -- Override del drawdown máximo
|
|
pause_on_drawdown BOOLEAN DEFAULT TRUE, -- Pausar si alcanza DD máximo
|
|
|
|
-- Aceptación de términos
|
|
terms_accepted_at TIMESTAMPTZ,
|
|
risk_disclosure_accepted_at TIMESTAMPTZ,
|
|
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_accounts_user ON accounts(user_id);
|
|
CREATE INDEX idx_accounts_product ON accounts(product_id);
|
|
CREATE INDEX idx_accounts_status ON accounts(status);
|
|
CREATE INDEX idx_accounts_number ON accounts(account_number);
|
|
|
|
-- ============================================================================
|
|
-- TABLA: account_transactions
|
|
-- Descripción: Movimientos en cuentas de inversión
|
|
-- ============================================================================
|
|
CREATE TYPE account_transaction_type AS ENUM (
|
|
'deposit',
|
|
'withdrawal',
|
|
'profit',
|
|
'loss',
|
|
'fee',
|
|
'adjustment',
|
|
'transfer_in',
|
|
'transfer_out'
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS account_transactions (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
account_id UUID NOT NULL REFERENCES accounts(id) ON DELETE RESTRICT,
|
|
|
|
-- Tipo y monto
|
|
transaction_type account_transaction_type NOT NULL,
|
|
amount DECIMAL(15,2) NOT NULL, -- Positivo o negativo según tipo
|
|
currency CHAR(3) DEFAULT 'USD',
|
|
|
|
-- Balances
|
|
balance_before DECIMAL(15,2) NOT NULL,
|
|
balance_after DECIMAL(15,2) NOT NULL,
|
|
|
|
-- Referencia externa
|
|
reference_type VARCHAR(50), -- 'wallet_transaction', 'position', 'fee_charge'
|
|
reference_id UUID,
|
|
|
|
-- Descripción
|
|
description TEXT,
|
|
|
|
-- Estado
|
|
status VARCHAR(20) DEFAULT 'completed', -- 'pending', 'completed', 'cancelled'
|
|
processed_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_account_tx_account ON account_transactions(account_id);
|
|
CREATE INDEX idx_account_tx_type ON account_transactions(transaction_type);
|
|
CREATE INDEX idx_account_tx_created ON account_transactions(created_at DESC);
|
|
|
|
-- ============================================================================
|
|
-- TABLA: performance_snapshots
|
|
-- Descripción: Snapshots periódicos de rendimiento
|
|
-- ============================================================================
|
|
CREATE TABLE IF NOT EXISTS performance_snapshots (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
account_id UUID NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
|
|
|
|
-- Período
|
|
snapshot_date DATE NOT NULL,
|
|
period_type VARCHAR(20) NOT NULL, -- 'daily', 'weekly', 'monthly'
|
|
|
|
-- Valores
|
|
opening_balance DECIMAL(15,2) NOT NULL,
|
|
closing_balance DECIMAL(15,2) NOT NULL,
|
|
deposits DECIMAL(15,2) DEFAULT 0,
|
|
withdrawals DECIMAL(15,2) DEFAULT 0,
|
|
profit_loss DECIMAL(15,2) NOT NULL,
|
|
fees DECIMAL(15,2) DEFAULT 0,
|
|
|
|
-- Métricas
|
|
return_percent DECIMAL(8,4),
|
|
drawdown_percent DECIMAL(5,2),
|
|
|
|
-- Trading stats
|
|
total_trades INT DEFAULT 0,
|
|
winning_trades INT DEFAULT 0,
|
|
positions_opened INT DEFAULT 0,
|
|
positions_closed INT DEFAULT 0,
|
|
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
UNIQUE(account_id, snapshot_date, period_type)
|
|
);
|
|
|
|
CREATE INDEX idx_perf_snapshots_account ON performance_snapshots(account_id);
|
|
CREATE INDEX idx_perf_snapshots_date ON performance_snapshots(snapshot_date DESC);
|
|
|
|
-- ============================================================================
|
|
-- TABLA: profit_distributions
|
|
-- Descripción: Distribución de utilidades (para cuentas con profit sharing)
|
|
-- ============================================================================
|
|
CREATE TABLE IF NOT EXISTS profit_distributions (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
account_id UUID NOT NULL REFERENCES accounts(id) ON DELETE RESTRICT,
|
|
|
|
-- Período
|
|
period_start DATE NOT NULL,
|
|
period_end DATE NOT NULL,
|
|
|
|
-- Cálculo
|
|
gross_profit DECIMAL(15,2) NOT NULL,
|
|
management_fee DECIMAL(15,2) DEFAULT 0,
|
|
net_profit DECIMAL(15,2) NOT NULL,
|
|
|
|
-- Distribución
|
|
platform_share_percent DECIMAL(5,2) NOT NULL,
|
|
client_share_percent DECIMAL(5,2) NOT NULL,
|
|
platform_amount DECIMAL(15,2) NOT NULL,
|
|
client_amount DECIMAL(15,2) NOT NULL,
|
|
|
|
-- Estado
|
|
status VARCHAR(20) DEFAULT 'pending', -- 'pending', 'approved', 'distributed', 'cancelled'
|
|
distributed_at TIMESTAMPTZ,
|
|
approved_by UUID REFERENCES auth.users(id),
|
|
|
|
-- Referencia de pago
|
|
payment_reference VARCHAR(100),
|
|
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_profit_dist_account ON profit_distributions(account_id);
|
|
CREATE INDEX idx_profit_dist_period ON profit_distributions(period_end DESC);
|
|
CREATE INDEX idx_profit_dist_status ON profit_distributions(status);
|
|
|
|
-- ============================================================================
|
|
-- TABLA: deposit_requests
|
|
-- Descripción: Solicitudes de depósito a cuentas de inversión
|
|
-- ============================================================================
|
|
CREATE TABLE IF NOT EXISTS deposit_requests (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
account_id UUID NOT NULL REFERENCES accounts(id) ON DELETE RESTRICT,
|
|
user_id UUID NOT NULL REFERENCES auth.users(id),
|
|
|
|
amount DECIMAL(15,2) NOT NULL,
|
|
currency CHAR(3) DEFAULT 'USD',
|
|
|
|
-- Origen
|
|
source_type VARCHAR(50) NOT NULL, -- 'wallet', 'external'
|
|
source_wallet_id UUID, -- Referencia a financial.wallets
|
|
|
|
-- Estado
|
|
status VARCHAR(20) DEFAULT 'pending', -- 'pending', 'approved', 'completed', 'rejected'
|
|
processed_at TIMESTAMPTZ,
|
|
processed_by UUID REFERENCES auth.users(id),
|
|
rejection_reason TEXT,
|
|
|
|
-- Transacción resultante
|
|
transaction_id UUID REFERENCES account_transactions(id),
|
|
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_deposit_requests_account ON deposit_requests(account_id);
|
|
CREATE INDEX idx_deposit_requests_user ON deposit_requests(user_id);
|
|
CREATE INDEX idx_deposit_requests_status ON deposit_requests(status);
|
|
|
|
-- ============================================================================
|
|
-- TABLA: withdrawal_requests
|
|
-- Descripción: Solicitudes de retiro de cuentas de inversión
|
|
-- ============================================================================
|
|
CREATE TABLE IF NOT EXISTS withdrawal_requests (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
account_id UUID NOT NULL REFERENCES accounts(id) ON DELETE RESTRICT,
|
|
user_id UUID NOT NULL REFERENCES auth.users(id),
|
|
|
|
amount DECIMAL(15,2) NOT NULL,
|
|
currency CHAR(3) DEFAULT 'USD',
|
|
|
|
-- Destino
|
|
destination_type VARCHAR(50) NOT NULL, -- 'wallet', 'bank_transfer'
|
|
destination_wallet_id UUID,
|
|
|
|
-- Estado
|
|
status VARCHAR(20) DEFAULT 'pending', -- 'pending', 'processing', 'completed', 'rejected'
|
|
processed_at TIMESTAMPTZ,
|
|
processed_by UUID REFERENCES auth.users(id),
|
|
rejection_reason TEXT,
|
|
|
|
-- Comisiones
|
|
fee_amount DECIMAL(10,2) DEFAULT 0,
|
|
net_amount DECIMAL(15,2),
|
|
|
|
-- Transacción resultante
|
|
transaction_id UUID REFERENCES account_transactions(id),
|
|
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_withdrawal_requests_account ON withdrawal_requests(account_id);
|
|
CREATE INDEX idx_withdrawal_requests_user ON withdrawal_requests(user_id);
|
|
CREATE INDEX idx_withdrawal_requests_status ON withdrawal_requests(status);
|
|
|
|
-- ============================================================================
|
|
-- TABLA: bot_assignments
|
|
-- Descripción: Asignación de bots a cuentas de inversión
|
|
-- ============================================================================
|
|
CREATE TABLE IF NOT EXISTS bot_assignments (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
account_id UUID NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
|
|
bot_id UUID NOT NULL REFERENCES trading.bots(id),
|
|
|
|
-- Estado
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
assigned_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
deactivated_at TIMESTAMPTZ,
|
|
|
|
-- Razón del cambio
|
|
assignment_reason TEXT,
|
|
deactivation_reason TEXT,
|
|
|
|
-- Usuario que asignó
|
|
assigned_by UUID REFERENCES auth.users(id), -- NULL = automático
|
|
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_bot_assignments_account ON bot_assignments(account_id);
|
|
CREATE INDEX idx_bot_assignments_bot ON bot_assignments(bot_id);
|
|
CREATE INDEX idx_bot_assignments_active ON bot_assignments(is_active) WHERE is_active = TRUE;
|
|
|
|
-- ============================================================================
|
|
-- TRIGGERS
|
|
-- ============================================================================
|
|
|
|
CREATE TRIGGER update_products_updated_at
|
|
BEFORE UPDATE ON products
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION public.update_updated_at_column();
|
|
|
|
CREATE TRIGGER update_accounts_updated_at
|
|
BEFORE UPDATE ON accounts
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION public.update_updated_at_column();
|
|
|
|
CREATE TRIGGER update_deposit_requests_updated_at
|
|
BEFORE UPDATE ON deposit_requests
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION public.update_updated_at_column();
|
|
|
|
CREATE TRIGGER update_withdrawal_requests_updated_at
|
|
BEFORE UPDATE ON withdrawal_requests
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION public.update_updated_at_column();
|
|
|
|
CREATE TRIGGER update_profit_distributions_updated_at
|
|
BEFORE UPDATE ON profit_distributions
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION public.update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- FUNCIÓN: Generar número de cuenta
|
|
-- ============================================================================
|
|
CREATE OR REPLACE FUNCTION generate_account_number()
|
|
RETURNS TRIGGER AS $$
|
|
DECLARE
|
|
seq_num INT;
|
|
BEGIN
|
|
SELECT COALESCE(MAX(CAST(SUBSTRING(account_number FROM 8) AS INT)), 0) + 1
|
|
INTO seq_num
|
|
FROM investment.accounts;
|
|
|
|
NEW.account_number := 'OQ-INV-' || LPAD(seq_num::TEXT, 6, '0');
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER set_account_number
|
|
BEFORE INSERT ON accounts
|
|
FOR EACH ROW
|
|
WHEN (NEW.account_number IS NULL)
|
|
EXECUTE FUNCTION generate_account_number();
|