broker_integration (5 tables): - broker_accounts: Cuentas MT4/MT5/API conectadas - broker_prices: Precios en tiempo real - spread_statistics: Estadisticas historicas de spread - price_adjustment_model: Modelos de ajuste de precio - trade_execution: Ejecucion de ordenes portfolio_management (6 tables): - portfolios: Portafolios de inversion - portfolio_accounts: Cuentas vinculadas a portafolios - investment_goals: Metas de inversion - rebalance_suggestions: Sugerencias de rebalanceo - portfolio_snapshots: Snapshots historicos - monte_carlo_projections: Proyecciones Monte Carlo Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
256 lines
7.8 KiB
PL/PgSQL
256 lines
7.8 KiB
PL/PgSQL
-- ============================================================================
|
|
-- SCHEMA: broker_integration
|
|
-- TABLE: broker_accounts
|
|
-- DESCRIPTION: Cuentas de broker conectadas (MT4, MT5, etc.)
|
|
-- VERSION: 1.0.0
|
|
-- CREATED: 2026-01-16
|
|
-- SPRINT: Sprint 6 - DDL Implementation Roadmap Q1-2026
|
|
-- ============================================================================
|
|
|
|
-- Crear schema
|
|
CREATE SCHEMA IF NOT EXISTS broker_integration;
|
|
|
|
COMMENT ON SCHEMA broker_integration IS
|
|
'Integracion con brokers de trading (MT4, MT5, API de brokers)';
|
|
|
|
-- Enum para tipo de broker
|
|
DO $$ BEGIN
|
|
CREATE TYPE broker_integration.broker_type AS ENUM (
|
|
'mt4',
|
|
'mt5',
|
|
'ctrader',
|
|
'fix_api',
|
|
'rest_api',
|
|
'binance',
|
|
'interactive_brokers',
|
|
'oanda',
|
|
'alpaca',
|
|
'custom'
|
|
);
|
|
EXCEPTION
|
|
WHEN duplicate_object THEN null;
|
|
END $$;
|
|
|
|
-- Enum para tipo de cuenta
|
|
DO $$ BEGIN
|
|
CREATE TYPE broker_integration.account_type AS ENUM (
|
|
'demo',
|
|
'live',
|
|
'contest'
|
|
);
|
|
EXCEPTION
|
|
WHEN duplicate_object THEN null;
|
|
END $$;
|
|
|
|
-- Enum para estado de conexion
|
|
DO $$ BEGIN
|
|
CREATE TYPE broker_integration.connection_status AS ENUM (
|
|
'connected',
|
|
'disconnected',
|
|
'connecting',
|
|
'error',
|
|
'maintenance',
|
|
'suspended',
|
|
'expired'
|
|
);
|
|
EXCEPTION
|
|
WHEN duplicate_object THEN null;
|
|
END $$;
|
|
|
|
-- Tabla de Cuentas de Broker
|
|
CREATE TABLE IF NOT EXISTS broker_integration.broker_accounts (
|
|
-- Identificadores
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
|
|
user_id UUID NOT NULL REFERENCES users.users(id) ON DELETE CASCADE,
|
|
|
|
-- Broker info
|
|
broker_type broker_integration.broker_type NOT NULL,
|
|
broker_name VARCHAR(100) NOT NULL, -- "XM", "IC Markets"
|
|
broker_server VARCHAR(255), -- Server name/address
|
|
|
|
-- Cuenta
|
|
account_type broker_integration.account_type NOT NULL DEFAULT 'demo',
|
|
account_number VARCHAR(50) NOT NULL,
|
|
account_name VARCHAR(100),
|
|
|
|
-- Conexion
|
|
connection_status broker_integration.connection_status NOT NULL DEFAULT 'disconnected',
|
|
connection_provider VARCHAR(50), -- "metaapi", "direct"
|
|
provider_account_id VARCHAR(100), -- ID en el proveedor
|
|
|
|
-- Credenciales (encriptadas)
|
|
login_encrypted TEXT,
|
|
password_encrypted TEXT,
|
|
investor_password_encrypted TEXT,
|
|
api_token_encrypted TEXT,
|
|
additional_credentials JSONB DEFAULT '{}'::JSONB,
|
|
|
|
-- Configuracion
|
|
leverage INTEGER,
|
|
currency VARCHAR(10) NOT NULL DEFAULT 'USD',
|
|
timezone VARCHAR(50) DEFAULT 'UTC',
|
|
|
|
-- Balance y equity
|
|
balance DECIMAL(15, 2),
|
|
equity DECIMAL(15, 2),
|
|
margin DECIMAL(15, 2),
|
|
free_margin DECIMAL(15, 2),
|
|
margin_level DECIMAL(10, 2),
|
|
|
|
-- Configuracion de trading
|
|
enable_trading BOOLEAN NOT NULL DEFAULT FALSE,
|
|
max_positions INTEGER,
|
|
max_lot_size DECIMAL(10, 2),
|
|
min_lot_size DECIMAL(10, 4) DEFAULT 0.01,
|
|
lot_step DECIMAL(10, 4) DEFAULT 0.01,
|
|
|
|
-- Permisos
|
|
allow_copy_trading BOOLEAN NOT NULL DEFAULT FALSE,
|
|
allow_signals BOOLEAN NOT NULL DEFAULT TRUE,
|
|
allow_auto_trading BOOLEAN NOT NULL DEFAULT FALSE,
|
|
|
|
-- Restricciones
|
|
allowed_symbols VARCHAR(20)[], -- NULL = todos
|
|
blocked_symbols VARCHAR(20)[],
|
|
allowed_directions VARCHAR(10)[], -- ['long', 'short']
|
|
trading_hours JSONB,
|
|
|
|
-- Estado
|
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
is_default BOOLEAN NOT NULL DEFAULT FALSE,
|
|
is_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
|
|
|
-- Ultima sincronizacion
|
|
last_sync_at TIMESTAMPTZ,
|
|
last_sync_error TEXT,
|
|
sync_interval_seconds INTEGER DEFAULT 60,
|
|
|
|
-- Estadisticas
|
|
total_trades INTEGER NOT NULL DEFAULT 0,
|
|
open_positions INTEGER NOT NULL DEFAULT 0,
|
|
total_profit DECIMAL(15, 2) NOT NULL DEFAULT 0,
|
|
today_profit DECIMAL(15, 2) NOT NULL DEFAULT 0,
|
|
|
|
-- Metadata
|
|
metadata JSONB DEFAULT '{}'::JSONB,
|
|
notes TEXT,
|
|
|
|
-- Timestamps
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
connected_at TIMESTAMPTZ,
|
|
disconnected_at TIMESTAMPTZ,
|
|
verified_at TIMESTAMPTZ,
|
|
|
|
-- Constraints
|
|
CONSTRAINT broker_accounts_unique UNIQUE (tenant_id, broker_type, account_number)
|
|
);
|
|
|
|
COMMENT ON TABLE broker_integration.broker_accounts IS
|
|
'Cuentas de broker conectadas para trading real o demo';
|
|
|
|
COMMENT ON COLUMN broker_integration.broker_accounts.enable_trading IS
|
|
'Si TRUE, permite ejecutar ordenes reales en esta cuenta';
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_broker_accounts_tenant
|
|
ON broker_integration.broker_accounts(tenant_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_broker_accounts_user
|
|
ON broker_integration.broker_accounts(user_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_broker_accounts_type
|
|
ON broker_integration.broker_accounts(broker_type);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_broker_accounts_status
|
|
ON broker_integration.broker_accounts(connection_status);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_broker_accounts_active
|
|
ON broker_integration.broker_accounts(user_id, is_active, connection_status)
|
|
WHERE is_active = TRUE;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_broker_accounts_default
|
|
ON broker_integration.broker_accounts(user_id, is_default)
|
|
WHERE is_default = TRUE;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_broker_accounts_sync
|
|
ON broker_integration.broker_accounts(last_sync_at)
|
|
WHERE is_active = TRUE AND connection_status = 'connected';
|
|
|
|
-- Funcion de timestamp
|
|
CREATE OR REPLACE FUNCTION broker_integration.update_broker_timestamp()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at := NOW();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Trigger para updated_at
|
|
DROP TRIGGER IF EXISTS broker_account_updated_at ON broker_integration.broker_accounts;
|
|
CREATE TRIGGER broker_account_updated_at
|
|
BEFORE UPDATE ON broker_integration.broker_accounts
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION broker_integration.update_broker_timestamp();
|
|
|
|
-- Trigger para asegurar solo una cuenta default
|
|
CREATE OR REPLACE FUNCTION broker_integration.ensure_single_default_broker()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
IF NEW.is_default = TRUE THEN
|
|
UPDATE broker_integration.broker_accounts
|
|
SET is_default = FALSE
|
|
WHERE user_id = NEW.user_id
|
|
AND id != NEW.id
|
|
AND is_default = TRUE;
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP TRIGGER IF EXISTS broker_account_single_default ON broker_integration.broker_accounts;
|
|
CREATE TRIGGER broker_account_single_default
|
|
BEFORE INSERT OR UPDATE OF is_default ON broker_integration.broker_accounts
|
|
FOR EACH ROW
|
|
WHEN (NEW.is_default = TRUE)
|
|
EXECUTE FUNCTION broker_integration.ensure_single_default_broker();
|
|
|
|
-- Vista de cuentas activas
|
|
CREATE OR REPLACE VIEW broker_integration.v_active_accounts AS
|
|
SELECT
|
|
id,
|
|
user_id,
|
|
broker_type,
|
|
broker_name,
|
|
account_type,
|
|
account_number,
|
|
connection_status,
|
|
balance,
|
|
equity,
|
|
leverage,
|
|
currency,
|
|
open_positions,
|
|
is_default,
|
|
last_sync_at
|
|
FROM broker_integration.broker_accounts
|
|
WHERE is_active = TRUE
|
|
ORDER BY is_default DESC, broker_name;
|
|
|
|
-- RLS Policies
|
|
ALTER TABLE broker_integration.broker_accounts ENABLE ROW LEVEL SECURITY;
|
|
|
|
CREATE POLICY broker_accounts_tenant ON broker_integration.broker_accounts
|
|
FOR ALL
|
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
|
|
|
CREATE POLICY broker_accounts_user ON broker_integration.broker_accounts
|
|
FOR ALL
|
|
USING (user_id = current_setting('app.current_user_id', true)::UUID);
|
|
|
|
-- Grants
|
|
GRANT USAGE ON SCHEMA broker_integration TO trading_app;
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON broker_integration.broker_accounts TO trading_app;
|
|
GRANT SELECT ON broker_integration.broker_accounts TO trading_readonly;
|
|
GRANT SELECT ON broker_integration.v_active_accounts TO trading_app;
|