162 lines
8.4 KiB
SQL
162 lines
8.4 KiB
SQL
-- ============================================================
|
|
-- Migration 004: Full Schema Sync
|
|
-- Date: 2026-02-07
|
|
-- Purpose: Create missing tables, add missing columns,
|
|
-- and align DB schema with application code.
|
|
-- ============================================================
|
|
|
|
-- ────────────────────────────────────────────────────────────
|
|
-- 1. TRADE_PROFILES TABLE (Missing CREATE TABLE)
|
|
-- ────────────────────────────────────────────────────────────
|
|
CREATE TABLE IF NOT EXISTS trade_profiles (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id uuid REFERENCES auth.users NOT NULL,
|
|
name text NOT NULL,
|
|
allocated_capital numeric DEFAULT 1000,
|
|
risk_per_trade_percent numeric DEFAULT 1.0,
|
|
symbols text DEFAULT 'BTC/USDT, ETH/USDT',
|
|
is_active boolean DEFAULT true,
|
|
strategy_config jsonb DEFAULT '{
|
|
"rules": [
|
|
{ "ruleId": "TrendBiasRule", "enabled": true, "params": { "timeframe": "4h", "emaFast": 50, "emaSlow": 200 } },
|
|
{ "ruleId": "SessionRule", "enabled": true, "params": { "allowedSessions": ["NY", "LDN"] } },
|
|
{ "ruleId": "ZoneRule", "enabled": true, "params": { "emaPeriod": 20, "tolerancePercent": 0.5 } },
|
|
{ "ruleId": "MomentumRule", "enabled": true, "params": { "timeframe": "1h", "rsiPeriod": 14, "rsiOverbought": 70, "rsiOversold": 30 } },
|
|
{ "ruleId": "EntryTriggerRule", "enabled": true, "params": { "triggerType": "ema_cross" } },
|
|
{ "ruleId": "RiskManagementRule", "enabled": true, "params": { "atrPeriod": 14, "riskRewardRatio": 1.5 } },
|
|
{ "ruleId": "AIAnalysisRule", "enabled": false, "params": { "minConfidence": 80 } }
|
|
],
|
|
"riskLimits": {
|
|
"maxDailyLossUsd": 50,
|
|
"maxConsecutiveLosses": 2,
|
|
"maxOpenTrades": 3
|
|
},
|
|
"execution": {
|
|
"orderType": "market",
|
|
"cooldownMinutes": 30,
|
|
"entryMode": "both"
|
|
}
|
|
}'::jsonb,
|
|
created_at timestamptz DEFAULT now()
|
|
);
|
|
|
|
COMMENT ON TABLE trade_profiles IS 'Trading strategy profiles with per-profile rule config, risk limits, and execution settings';
|
|
COMMENT ON COLUMN trade_profiles.strategy_config IS 'JSON configuration: { rules[], riskLimits{}, execution{} }';
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_trade_profiles_user_id ON trade_profiles(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_trade_profiles_is_active ON trade_profiles(is_active);
|
|
|
|
-- RLS
|
|
ALTER TABLE trade_profiles ENABLE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS "Users can manage own profiles" ON trade_profiles;
|
|
CREATE POLICY "Users can manage own profiles" ON trade_profiles
|
|
USING (auth.uid() = user_id)
|
|
WITH CHECK (auth.uid() = user_id);
|
|
|
|
|
|
-- ────────────────────────────────────────────────────────────
|
|
-- 2. ORDERS TABLE — Add missing columns
|
|
-- ────────────────────────────────────────────────────────────
|
|
|
|
-- profile_id: links order to the trade profile that triggered it
|
|
ALTER TABLE orders
|
|
ADD COLUMN IF NOT EXISTS profile_id uuid REFERENCES trade_profiles(id) ON DELETE SET NULL;
|
|
|
|
-- stop_loss & take_profit: stored by TradeExecutor.logOrderToDb()
|
|
ALTER TABLE orders
|
|
ADD COLUMN IF NOT EXISTS stop_loss numeric;
|
|
|
|
ALTER TABLE orders
|
|
ADD COLUMN IF NOT EXISTS take_profit numeric;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_orders_profile_id ON orders(profile_id);
|
|
|
|
COMMENT ON COLUMN orders.profile_id IS 'Trade profile that triggered this order (NULL = manual)';
|
|
COMMENT ON COLUMN orders.stop_loss IS 'Stop loss price set at order time';
|
|
COMMENT ON COLUMN orders.take_profit IS 'Take profit price set at order time';
|
|
|
|
|
|
-- ────────────────────────────────────────────────────────────
|
|
-- 3. TRADE_HISTORY TABLE — Add missing columns
|
|
-- ────────────────────────────────────────────────────────────
|
|
|
|
-- profile_id: links trade to the profile that triggered it
|
|
ALTER TABLE trade_history
|
|
ADD COLUMN IF NOT EXISTS profile_id uuid REFERENCES trade_profiles(id) ON DELETE SET NULL;
|
|
|
|
-- stop_loss & take_profit: for post-trade analysis
|
|
ALTER TABLE trade_history
|
|
ADD COLUMN IF NOT EXISTS stop_loss numeric;
|
|
|
|
ALTER TABLE trade_history
|
|
ADD COLUMN IF NOT EXISTS take_profit numeric;
|
|
|
|
-- rules_metadata: stores which rules passed/failed for this trade
|
|
ALTER TABLE trade_history
|
|
ADD COLUMN IF NOT EXISTS rules_metadata jsonb;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_trade_history_profile_id ON trade_history(profile_id);
|
|
|
|
COMMENT ON COLUMN trade_history.profile_id IS 'Trade profile that triggered this trade (NULL = manual)';
|
|
COMMENT ON COLUMN trade_history.stop_loss IS 'Stop loss price at trade entry';
|
|
COMMENT ON COLUMN trade_history.take_profit IS 'Take profit price at trade entry';
|
|
COMMENT ON COLUMN trade_history.rules_metadata IS 'JSON snapshot of rule statuses at trade time: { ruleName: { passed, reason } }';
|
|
|
|
|
|
-- ────────────────────────────────────────────────────────────
|
|
-- 4. BOT_CONFIG TABLE (Missing CREATE TABLE)
|
|
-- Used by: ConfigTab.tsx, GlobalConfigManager.tsx
|
|
-- ────────────────────────────────────────────────────────────
|
|
CREATE TABLE IF NOT EXISTS bot_config (
|
|
key text PRIMARY KEY,
|
|
value text,
|
|
description text,
|
|
updated_at timestamptz DEFAULT now()
|
|
);
|
|
|
|
COMMENT ON TABLE bot_config IS 'Key-value store for global bot configuration (editable from dashboard)';
|
|
|
|
-- RLS: allow authenticated users to read, admins to write
|
|
ALTER TABLE bot_config ENABLE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS "Authenticated users can read bot_config" ON bot_config;
|
|
CREATE POLICY "Authenticated users can read bot_config" ON bot_config
|
|
FOR SELECT
|
|
USING (auth.role() = 'authenticated');
|
|
|
|
DROP POLICY IF EXISTS "Admins can manage bot_config" ON bot_config;
|
|
CREATE POLICY "Admins can manage bot_config" ON bot_config
|
|
USING (
|
|
EXISTS (SELECT 1 FROM users WHERE user_id = auth.uid() AND role = 'admin')
|
|
)
|
|
WITH CHECK (
|
|
EXISTS (SELECT 1 FROM users WHERE user_id = auth.uid() AND role = 'admin')
|
|
);
|
|
|
|
|
|
-- ────────────────────────────────────────────────────────────
|
|
-- 5. DYNAMIC_CONFIG TABLE (Missing CREATE TABLE)
|
|
-- Used by: bot-service config/index.ts (loadDynamicConfig)
|
|
-- ────────────────────────────────────────────────────────────
|
|
CREATE TABLE IF NOT EXISTS dynamic_config (
|
|
key text PRIMARY KEY,
|
|
value text,
|
|
updated_at timestamptz DEFAULT now()
|
|
);
|
|
|
|
COMMENT ON TABLE dynamic_config IS 'Runtime-overridable bot settings loaded at startup (SYMBOLS, intervals, etc.)';
|
|
|
|
|
|
-- ────────────────────────────────────────────────────────────
|
|
-- 6. UPDATE schema_reference.sql sync comment
|
|
-- ────────────────────────────────────────────────────────────
|
|
-- After running this migration, all 7 tables are fully defined:
|
|
-- 1. users (auth trigger-created)
|
|
-- 2. entries (watchlist & manual positions)
|
|
-- 3. trade_history (completed trade ledger)
|
|
-- 4. orders (active/pending orders)
|
|
-- 5. trade_profiles (strategy profiles with rule config)
|
|
-- 6. bot_config (global config key-value store)
|
|
-- 7. dynamic_config (runtime config overrides)
|