StockAnalysers
Loading market data...
Your portfolio & reports sync across all devices
-- Run this in your Supabase SQL Editor
-- User profiles (email linked to portfolio)
CREATE TABLE public.profiles (
user_id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
email TEXT, full_name TEXT, avatar_url TEXT,
updated_at TIMESTAMPTZ DEFAULT NOW()
);
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
CREATE POLICY "own_profile" ON public.profiles
FOR ALL TO authenticated USING (auth.uid() = user_id) WITH CHECK (auth.uid() = user_id);
-- Auto-upsert profile on every sign-in
CREATE OR REPLACE FUNCTION public.handle_user_upsert()
RETURNS TRIGGER LANGUAGE plpgsql SECURITY DEFINER AS $$
BEGIN
INSERT INTO public.profiles (user_id, email, full_name, avatar_url)
VALUES (NEW.id, NEW.email,
COALESCE(NEW.raw_user_meta_data->>'full_name', NEW.raw_user_meta_data->>'name'),
NEW.raw_user_meta_data->>'avatar_url')
ON CONFLICT (user_id) DO UPDATE SET
email=EXCLUDED.email, full_name=EXCLUDED.full_name,
avatar_url=EXCLUDED.avatar_url, updated_at=NOW();
RETURN NEW;
END; $$;
CREATE OR REPLACE TRIGGER on_auth_user_created
AFTER INSERT OR UPDATE ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_user_upsert();
-- Reports table
CREATE TABLE public.reports (
id TEXT PRIMARY KEY, user_id UUID NOT NULL DEFAULT auth.uid(),
report_ts TIMESTAMPTZ NOT NULL, tickers TEXT[] DEFAULT '{}',
title TEXT DEFAULT '', description TEXT DEFAULT '',
is_live BOOLEAN DEFAULT TRUE, snapshot JSONB DEFAULT '[]',
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX ON public.reports (user_id, report_ts DESC);
ALTER TABLE public.reports ENABLE ROW LEVEL SECURITY;
CREATE POLICY "own_reports" ON public.reports
FOR ALL TO authenticated USING (auth.uid() = user_id) WITH CHECK (auth.uid() = user_id);
-- Transactions table
CREATE TABLE public.transactions (
id TEXT PRIMARY KEY, user_id UUID NOT NULL DEFAULT auth.uid(),
ticker TEXT NOT NULL, company_name TEXT DEFAULT '',
volume NUMERIC(18,6) NOT NULL, price NUMERIC(18,4) NOT NULL,
transaction_type TEXT NOT NULL CHECK (transaction_type IN ('buy','sell')),
transaction_date DATE NOT NULL, notes TEXT DEFAULT '',
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX ON public.transactions (user_id, transaction_date DESC);
ALTER TABLE public.transactions ENABLE ROW LEVEL SECURITY;
CREATE POLICY "own_transactions" ON public.transactions
FOR ALL TO authenticated USING (auth.uid() = user_id) WITH CHECK (auth.uid() = user_id);
-- GARP Screener table (shared market data — no user_id, publicly readable)
CREATE TABLE public.garp_screener (
symbol TEXT PRIMARY KEY,
name TEXT DEFAULT '',
price NUMERIC DEFAULT 0,
pe NUMERIC DEFAULT 0,
peg NUMERIC DEFAULT 0,
eps_growth NUMERIC DEFAULT 0,
rev_growth NUMERIC DEFAULT 0,
roe NUMERIC DEFAULT 0,
gross_margin NUMERIC DEFAULT 0,
day_change_pct NUMERIC DEFAULT 0,
year_high NUMERIC DEFAULT 0,
year_low NUMERIC DEFAULT 0,
garp_score NUMERIC NOT NULL DEFAULT 0,
screened_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX ON public.garp_screener (garp_score DESC);
ALTER TABLE public.garp_screener ENABLE ROW LEVEL SECURITY;
CREATE POLICY "anyone_read" ON public.garp_screener FOR SELECT USING (true);
CREATE POLICY "authenticated_write" ON public.garp_screener
FOR ALL TO authenticated USING (true) WITH CHECK (true);
-- ── Financial Data Store — run in Supabase SQL Editor ──
-- Auto-update timestamp helper (skip if already exists)
CREATE OR REPLACE FUNCTION public.touch_updated_at()
RETURNS TRIGGER LANGUAGE plpgsql AS $$
BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$;
-- 1. Company Profiles
CREATE TABLE public.company_profiles (
symbol TEXT PRIMARY KEY,
name TEXT NOT NULL DEFAULT '',
sector TEXT DEFAULT '',
industry TEXT DEFAULT '',
exchange TEXT DEFAULT '',
country TEXT DEFAULT 'US',
currency TEXT DEFAULT 'USD',
description TEXT DEFAULT '',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TRIGGER trg_cp_updated BEFORE UPDATE ON public.company_profiles
FOR EACH ROW EXECUTE FUNCTION public.touch_updated_at();
ALTER TABLE public.company_profiles ENABLE ROW LEVEL SECURITY;
CREATE POLICY "cp_read_all" ON public.company_profiles FOR SELECT USING (true);
CREATE POLICY "cp_auth_write" ON public.company_profiles
FOR ALL TO authenticated USING (true) WITH CHECK (true);
-- 2. Latest Financial Snapshot (one row per company, upserted on refresh)
CREATE TABLE public.company_financials (
symbol TEXT PRIMARY KEY REFERENCES public.company_profiles(symbol) ON DELETE CASCADE,
-- Market data
price NUMERIC DEFAULT 0,
market_cap NUMERIC DEFAULT 0,
shares_outstanding NUMERIC DEFAULT 0,
week_52_high NUMERIC DEFAULT 0,
week_52_low NUMERIC DEFAULT 0,
beta NUMERIC DEFAULT 0,
-- Valuation multiples
pe_ratio NUMERIC DEFAULT 0,
forward_pe NUMERIC DEFAULT 0,
peg_ratio NUMERIC DEFAULT 0,
ps_ratio NUMERIC DEFAULT 0,
pb_ratio NUMERIC DEFAULT 0,
ev_ebitda NUMERIC DEFAULT 0,
fcf_yield NUMERIC DEFAULT 0,
-- Income (TTM)
revenue_ttm NUMERIC DEFAULT 0,
gross_profit_ttm NUMERIC DEFAULT 0,
ebitda_ttm NUMERIC DEFAULT 0,
net_income_ttm NUMERIC DEFAULT 0,
eps_ttm NUMERIC DEFAULT 0,
-- Growth rates (as decimals: 0.15 = 15%)
revenue_growth_yoy NUMERIC DEFAULT 0,
eps_growth_yoy NUMERIC DEFAULT 0,
eps_growth_3y_cagr NUMERIC DEFAULT 0,
-- Margins (as decimals: 0.65 = 65%)
gross_margin NUMERIC DEFAULT 0,
ebitda_margin NUMERIC DEFAULT 0,
net_margin NUMERIC DEFAULT 0,
operating_margin NUMERIC DEFAULT 0,
-- Efficiency
roe NUMERIC DEFAULT 0,
roa NUMERIC DEFAULT 0,
roic NUMERIC DEFAULT 0,
-- Balance sheet
cash NUMERIC DEFAULT 0,
total_debt NUMERIC DEFAULT 0,
debt_to_equity NUMERIC DEFAULT 0,
current_ratio NUMERIC DEFAULT 0,
quick_ratio NUMERIC DEFAULT 0,
interest_coverage NUMERIC DEFAULT 0,
-- Cash flow
fcf_ttm NUMERIC DEFAULT 0,
operating_cf_ttm NUMERIC DEFAULT 0,
capex_ttm NUMERIC DEFAULT 0,
-- Dividend
dividend_yield NUMERIC DEFAULT 0,
payout_ratio NUMERIC DEFAULT 0,
-- Analyst consensus
analyst_target NUMERIC DEFAULT 0,
analyst_rec TEXT DEFAULT '',
num_analysts INTEGER DEFAULT 0,
-- Metadata
data_source TEXT DEFAULT 'api',
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TRIGGER trg_cf_updated BEFORE UPDATE ON public.company_financials
FOR EACH ROW EXECUTE FUNCTION public.touch_updated_at();
CREATE INDEX ON public.company_financials (peg_ratio);
CREATE INDEX ON public.company_financials (eps_growth_yoy DESC);
ALTER TABLE public.company_financials ENABLE ROW LEVEL SECURITY;
CREATE POLICY "cf_read_all" ON public.company_financials FOR SELECT USING (true);
CREATE POLICY "cf_auth_write" ON public.company_financials
FOR ALL TO authenticated USING (true) WITH CHECK (true);
-- 3. Annual Income History (multi-year per company)
CREATE TABLE public.income_history (
id BIGSERIAL PRIMARY KEY,
symbol TEXT NOT NULL REFERENCES public.company_profiles(symbol) ON DELETE CASCADE,
fiscal_year DATE NOT NULL,
revenue NUMERIC DEFAULT 0,
gross_profit NUMERIC DEFAULT 0,
ebitda NUMERIC DEFAULT 0,
net_income NUMERIC DEFAULT 0,
eps_diluted NUMERIC DEFAULT 0,
shares_diluted NUMERIC DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE (symbol, fiscal_year)
);
CREATE INDEX ON public.income_history (symbol, fiscal_year DESC);
ALTER TABLE public.income_history ENABLE ROW LEVEL SECURITY;
CREATE POLICY "ih_read_all" ON public.income_history FOR SELECT USING (true);
CREATE POLICY "ih_auth_write" ON public.income_history
FOR ALL TO authenticated USING (true) WITH CHECK (true);
-- 4. GARP Assessments (scored snapshots, one per company per day)
CREATE TABLE public.garp_assessments (
id BIGSERIAL PRIMARY KEY,
symbol TEXT NOT NULL REFERENCES public.company_profiles(symbol) ON DELETE CASCADE,
assessed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
classification TEXT DEFAULT '',
-- Five GARP pillar scores (0–10 each)
garp_valuation_score NUMERIC DEFAULT 0,
balance_sheet_score NUMERIC DEFAULT 0,
insider_alignment_score NUMERIC DEFAULT 0,
cash_flow_score NUMERIC DEFAULT 0,
competitive_adv_score NUMERIC DEFAULT 0,
-- Auto-computed composites
total_score NUMERIC GENERATED ALWAYS AS (
garp_valuation_score + balance_sheet_score + insider_alignment_score +
cash_flow_score + competitive_adv_score
) STORED,
score_100 NUMERIC GENERATED ALWAYS AS (
(garp_valuation_score + balance_sheet_score + insider_alignment_score +
cash_flow_score + competitive_adv_score) * 2
) STORED,
-- Key inputs captured at assessment time
peg_snap NUMERIC DEFAULT 0,
eps_growth_snap NUMERIC DEFAULT 0,
gross_margin_snap NUMERIC DEFAULT 0,
roe_snap NUMERIC DEFAULT 0,
debt_equity_snap NUMERIC DEFAULT 0
);
CREATE UNIQUE INDEX ON public.garp_assessments (symbol, (assessed_at::DATE));
CREATE INDEX ON public.garp_assessments (symbol, assessed_at DESC);
CREATE INDEX ON public.garp_assessments (score_100 DESC);
ALTER TABLE public.garp_assessments ENABLE ROW LEVEL SECURITY;
CREATE POLICY "ga_read_all" ON public.garp_assessments FOR SELECT USING (true);
CREATE POLICY "ga_auth_write" ON public.garp_assessments
FOR ALL TO authenticated USING (true) WITH CHECK (true);
Track your holdings and transactions
Your previously generated GARP analyses
AI-ranked · Updated in real-time · Educational only
| # | Company | GARP ⓘ | Price ⓘ | Jan 2027 ⓘ | Jan 2028 ⓘ | P/E ⓘ | Entry Price ⓘ | Conf. ⓘ |
|---|---|---|---|---|---|---|---|---|
| Click "AI Research" to start analysis… | ||||||||
Tap any row for full analysis · AI-generated · Educational only — not financial advice
| # | Company | GARP ⓘ | Price ⓘ | Jan 2027 ⓘ | Jan 2028 ⓘ | P/E ⓘ | Entry Price ⓘ | Conf. ⓘ |
|---|---|---|---|---|---|---|---|---|
| Click "AI Research" to start analysis… | ||||||||
Tap any row for full analysis · AI-generated · Educational only — not financial advice
Claude fetches live prices for 100 top S&P 500 stocks and picks today's 5 best trading setups.
Ready to scan
Tap "Scan Market" — Claude will fetch live prices and identify today's top 5 trading opportunities
AI-generated · Educational only — not financial advice · Always verify before trading
GARP Analysis |
Enter your email and we'll send a reset link
Check your inbox
If that email is registered, you'll receive a reset link shortly. The link expires in 1 hour.
Choose a strong new password for your account
Enter your current password then choose a new one