239 lines
10 KiB
PL/PgSQL
239 lines
10 KiB
PL/PgSQL
/*
|
|
# Full Schema Reference — Bytelyst Trading Platform
|
|
|
|
Last updated: 2026-02-07
|
|
|
|
This file documents ALL 7 tables used by the Trading Dashboard and Bot Service.
|
|
Run individual CREATE TABLE statements or use migration 004_full_schema_sync.sql
|
|
in the bot-service/schema/ folder to apply all changes.
|
|
|
|
Tables:
|
|
1. users — User accounts (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 per-profile rule config
|
|
6. bot_config — Global config key-value store (dashboard-editable)
|
|
7. dynamic_config — Runtime config overrides (bot startup)
|
|
*/
|
|
|
|
|
|
-- ════════════════════════════════════════════════════════════
|
|
-- 1. USERS TABLE (Created by auth trigger — reference only)
|
|
-- ════════════════════════════════════════════════════════════
|
|
-- CREATE TABLE IF NOT EXISTS users (
|
|
-- user_id uuid PRIMARY KEY REFERENCES auth.users,
|
|
-- first_name text,
|
|
-- last_name text,
|
|
-- email text,
|
|
-- "ALPACA_API_KEY" text,
|
|
-- "ALPACA_SECRET_KEY" text,
|
|
-- "REAL_ALPACA_API_KEY" text,
|
|
-- "REAL_ALPACA_SECRET_KEY" text,
|
|
-- trade_enable boolean DEFAULT false,
|
|
-- role text DEFAULT 'user',
|
|
-- drop_threshold_for_buy numeric,
|
|
-- gain_threshold_for_sell numeric,
|
|
-- market_poll_interval_in_seconds integer
|
|
-- );
|
|
|
|
-- Auth trigger: auto-create user row on signup
|
|
CREATE OR REPLACE FUNCTION public.handle_new_user()
|
|
RETURNS trigger AS $$
|
|
BEGIN
|
|
INSERT INTO public.users (user_id, email, role, trade_enable)
|
|
VALUES (new.id, new.email, 'user', false);
|
|
RETURN new;
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
|
|
CREATE TRIGGER on_auth_user_created
|
|
AFTER INSERT ON auth.users
|
|
FOR EACH ROW EXECUTE PROCEDURE public.handle_new_user();
|
|
|
|
|
|
-- ════════════════════════════════════════════════════════════
|
|
-- 2. ENTRIES TABLE (Watchlist & Manual Positions)
|
|
-- ════════════════════════════════════════════════════════════
|
|
CREATE TABLE IF NOT EXISTS entries (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
stock_instance_id uuid DEFAULT gen_random_uuid(),
|
|
user_id uuid REFERENCES auth.users NOT NULL DEFAULT auth.uid(),
|
|
|
|
-- Core
|
|
symbol text NOT NULL,
|
|
label text,
|
|
notes text,
|
|
|
|
-- Config
|
|
active boolean DEFAULT true,
|
|
is_real_trade boolean DEFAULT false,
|
|
is_crypto boolean DEFAULT false,
|
|
status text DEFAULT 'active', -- 'active', 'sellCompleted', 'closed'
|
|
|
|
-- Trading Data
|
|
quantity numeric,
|
|
filled_quantity numeric,
|
|
entry_price numeric,
|
|
buy_price numeric,
|
|
sell_price numeric,
|
|
buy_time timestamptz,
|
|
sell_time timestamptz,
|
|
|
|
-- Automation
|
|
drop_threshold_for_buy numeric,
|
|
gain_threshold_for_sell numeric,
|
|
|
|
created_at timestamptz DEFAULT now(),
|
|
updated_at timestamptz DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE entries ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Users can manage own entries" ON entries
|
|
USING (auth.uid() = user_id)
|
|
WITH CHECK (auth.uid() = user_id);
|
|
|
|
|
|
-- ════════════════════════════════════════════════════════════
|
|
-- 3. TRADE_HISTORY TABLE (Completed Trade Ledger)
|
|
-- ════════════════════════════════════════════════════════════
|
|
CREATE TABLE IF NOT EXISTS trade_history (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id uuid REFERENCES auth.users NOT NULL,
|
|
profile_id uuid REFERENCES trade_profiles(id) ON DELETE SET NULL,
|
|
|
|
-- Trade Data
|
|
symbol text NOT NULL,
|
|
side text NOT NULL, -- 'BUY' or 'SELL'
|
|
entry_price numeric,
|
|
exit_price numeric,
|
|
size numeric,
|
|
pnl numeric, -- Realized P&L ($)
|
|
pnl_percent numeric, -- Realized P&L (%)
|
|
stop_loss numeric, -- SL price at entry
|
|
take_profit numeric, -- TP price at entry
|
|
|
|
-- Context
|
|
reason text, -- 'Signal Flip', 'Stop Loss', 'Manual', etc.
|
|
rules_metadata jsonb, -- Snapshot of rule statuses at trade time
|
|
timestamp bigint, -- Unix ms from bot execution
|
|
|
|
created_at timestamptz DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE trade_history ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Users can view own trade history" ON trade_history
|
|
FOR SELECT USING (auth.uid() = user_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_trade_history_profile_id ON trade_history(profile_id);
|
|
CREATE INDEX IF NOT EXISTS idx_trade_history_user_symbol ON trade_history(user_id, symbol);
|
|
|
|
|
|
-- ════════════════════════════════════════════════════════════
|
|
-- 4. ORDERS TABLE (Active/Pending Orders)
|
|
-- ════════════════════════════════════════════════════════════
|
|
CREATE TABLE IF NOT EXISTS orders (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id uuid REFERENCES auth.users NOT NULL,
|
|
profile_id uuid REFERENCES trade_profiles(id) ON DELETE SET NULL,
|
|
|
|
-- Order Identification
|
|
order_id text, -- Exchange order ID
|
|
symbol text NOT NULL,
|
|
|
|
-- Order Details
|
|
type text NOT NULL, -- 'Market', 'Limit', 'Stop'
|
|
side text NOT NULL, -- 'BUY' or 'SELL'
|
|
qty numeric NOT NULL,
|
|
price numeric,
|
|
stop_loss numeric, -- SL price at order time
|
|
take_profit numeric, -- TP price at order time
|
|
|
|
-- Status
|
|
status text DEFAULT 'pending', -- 'pending', 'filled', 'cancelled', 'rejected'
|
|
|
|
-- Timestamps
|
|
timestamp bigint, -- Unix ms when order was placed
|
|
filled_at timestamptz,
|
|
|
|
created_at timestamptz DEFAULT now(),
|
|
updated_at timestamptz DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Users can view own orders" ON orders
|
|
FOR SELECT USING (auth.uid() = user_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_orders_user_status ON orders(user_id, status);
|
|
CREATE INDEX IF NOT EXISTS idx_orders_symbol ON orders(symbol);
|
|
CREATE INDEX IF NOT EXISTS idx_orders_profile_id ON orders(profile_id);
|
|
|
|
|
|
-- ════════════════════════════════════════════════════════════
|
|
-- 5. TRADE_PROFILES TABLE (Strategy Profiles)
|
|
-- ════════════════════════════════════════════════════════════
|
|
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": {} },
|
|
{ "ruleId": "SessionRule", "enabled": true, "params": {} },
|
|
{ "ruleId": "ZoneRule", "enabled": true, "params": {} },
|
|
{ "ruleId": "MomentumRule", "enabled": true, "params": {} },
|
|
{ "ruleId": "EntryTriggerRule", "enabled": true, "params": {} },
|
|
{ "ruleId": "RiskManagementRule", "enabled": true, "params": {} },
|
|
{ "ruleId": "AIAnalysisRule", "enabled": false, "params": {} }
|
|
],
|
|
"riskLimits": {
|
|
"maxDailyLossUsd": 50,
|
|
"maxConsecutiveLosses": 2,
|
|
"maxOpenTrades": 3
|
|
},
|
|
"execution": {
|
|
"orderType": "market",
|
|
"cooldownMinutes": 30
|
|
}
|
|
}'::jsonb,
|
|
created_at timestamptz DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE trade_profiles ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Users can manage own profiles" ON trade_profiles
|
|
USING (auth.uid() = user_id)
|
|
WITH CHECK (auth.uid() = user_id);
|
|
|
|
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);
|
|
|
|
|
|
-- ════════════════════════════════════════════════════════════
|
|
-- 6. BOT_CONFIG TABLE (Global Config — Dashboard Editable)
|
|
-- ════════════════════════════════════════════════════════════
|
|
CREATE TABLE IF NOT EXISTS bot_config (
|
|
key text PRIMARY KEY,
|
|
value text,
|
|
description text,
|
|
updated_at timestamptz DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE bot_config ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Authenticated users can read bot_config" ON bot_config
|
|
FOR SELECT USING (auth.role() = 'authenticated');
|
|
|
|
|
|
-- ════════════════════════════════════════════════════════════
|
|
-- 7. DYNAMIC_CONFIG TABLE (Bot Runtime Overrides)
|
|
-- ════════════════════════════════════════════════════════════
|
|
CREATE TABLE IF NOT EXISTS dynamic_config (
|
|
key text PRIMARY KEY,
|
|
value text,
|
|
updated_at timestamptz DEFAULT now()
|
|
);
|