diff --git a/README.md b/README.md
index da00779..a74c27f 100644
--- a/README.md
+++ b/README.md
@@ -32,6 +32,7 @@ A personal trading dashboard for [Hyperliquid](https://hyperliquid.xyz) — live
| **HL Pulse** | Hyperliquid ecosystem intel — HL-filtered news, HYPE stats, HyperEVM TVL, top protocols, AI content studio (X threads / posts / digests) |
| **Fundamentals** | Top 100 coins — price, 24h/7d/30d%, market cap, volume, ATH drawdown |
| **DeFi** | DeFiLlama macro dashboard — total TVL, chain dominance, protocol rankings, stablecoin supply |
+| **Settings** | Wallet switcher, API proxy, CoinGecko key, RSS proxy, bot worker URL, AI endpoints (Edge Function + Vercel backend), APIU proxy, Telegram notifications |
---
diff --git a/app.js b/app.js
index 5250242..441dedf 100644
--- a/app.js
+++ b/app.js
@@ -10,7 +10,7 @@ let activeNarrative = 'all';
let autoRefreshTimer = null;
let _silentRefresh = false;
let _lastRefreshTs = 0;
-const _SKIP_SILENT = new Set(['phases','monitor','journal','analytics','kb','mvrv','ai','capital']);
+const _SKIP_SILENT = new Set(['phases','monitor','journal','analytics','kb','mvrv','ai','capital','settings']);
let marketSortKey = 'volume';
let allMarketData = [];
let _recentPnlHours = 24;
@@ -106,7 +106,7 @@ async function getCGGlobal() {
}
async function getCGMarkets() {
if (_cgShared.markets && Date.now() - _cgShared.marketsTs < 3*60*1000) return _cgShared.markets;
- const r = await fetch('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=false&price_change_percentage=24h,7d,30d', { headers: _cgHeaders() });
+ const r = await fetch('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=true&price_change_percentage=24h,7d,30d', { headers: _cgHeaders() });
if (!r.ok) throw new Error('CG markets ' + r.status);
_cgShared.markets = await r.json();
_cgShared.marketsTs = Date.now();
@@ -626,7 +626,7 @@ function navigate(page) {
pageEl.classList.add('active');
document.querySelectorAll(`[data-page="${page}"]`).forEach(el=>el.classList.add('active'));
currentPage = page;
- const loaders={overview:loadOverview,capital:typeof loadCapital!=='undefined'?loadCapital:null,trades:loadTrades,funding:loadFunding,flows:loadFlows,monitor:loadMonitor,markets:loadMarkets,phases:loadPhases,intel:typeof loadIntel!=='undefined'?loadIntel:null,watchlist:loadWatchlist,journal:typeof loadJournal!=='undefined'?loadJournal:null,indicators:typeof loadIndicators!=='undefined'?loadIndicators:null,smartmoney:typeof loadNansen!=='undefined'?loadNansen:null,analytics:typeof loadAnalytics!=='undefined'?loadAnalytics:null,signals:typeof loadSignals!=='undefined'?loadSignals:null,news:typeof loadNews!=='undefined'?loadNews:null,hlpulse:typeof loadHLPulse!=='undefined'?loadHLPulse:null,fundamentals:typeof loadFundamentals!=='undefined'?loadFundamentals:null,ai:typeof loadAI!=='undefined'?loadAI:null,arb:typeof loadArb!=='undefined'?loadArb:null,defi:typeof loadDefi!=='undefined'?loadDefi:null,kb:typeof loadKB!=='undefined'?loadKB:null,trend:typeof loadTrend!=='undefined'?loadTrend:null,onchain:typeof loadOnchain!=='undefined'?loadOnchain:null,heatmap:typeof loadHeatmap!=='undefined'?loadHeatmap:null,brief:typeof loadDailyBrief!=='undefined'?loadDailyBrief:null,research:typeof loadResearch!=='undefined'?loadResearch:null};
+ const loaders={overview:loadOverview,capital:typeof loadCapital!=='undefined'?loadCapital:null,trades:loadTrades,funding:loadFunding,flows:loadFlows,monitor:loadMonitor,markets:loadMarkets,phases:loadPhases,intel:typeof loadIntel!=='undefined'?loadIntel:null,watchlist:loadWatchlist,journal:typeof loadJournal!=='undefined'?loadJournal:null,indicators:typeof loadIndicators!=='undefined'?loadIndicators:null,smartmoney:typeof loadNansen!=='undefined'?loadNansen:null,analytics:typeof loadAnalytics!=='undefined'?loadAnalytics:null,signals:typeof loadSignals!=='undefined'?loadSignals:null,news:typeof loadNews!=='undefined'?loadNews:null,hlpulse:typeof loadHLPulse!=='undefined'?loadHLPulse:null,fundamentals:typeof loadFundamentals!=='undefined'?loadFundamentals:null,ai:typeof loadAI!=='undefined'?loadAI:null,arb:typeof loadArb!=='undefined'?loadArb:null,defi:typeof loadDefi!=='undefined'?loadDefi:null,kb:typeof loadKB!=='undefined'?loadKB:null,trend:typeof loadTrend!=='undefined'?loadTrend:null,onchain:typeof loadOnchain!=='undefined'?loadOnchain:null,heatmap:typeof loadHeatmap!=='undefined'?loadHeatmap:null,brief:typeof loadDailyBrief!=='undefined'?loadDailyBrief:null,research:typeof loadResearch!=='undefined'?loadResearch:null,settings:loadSettings};
if(loaders[page]) loaders[page]();
} catch(e) { console.error('navigate error:', e); }
}
@@ -2344,64 +2344,7 @@ async function loadMonitor() {
-
⚡ API Proxy (Cloudflare Worker)
-
Optional: paste your Cloudflare Worker URL for edge-cached API calls (faster in Indonesia). Leave blank to use Hyperliquid directly.
-
-
-
-
-
-
${localStorage.getItem('hype_proxy_url') ? '✓ Proxy active — reload page to apply' : 'Using direct Hyperliquid API'}
-
-
-
-
🦎 CoinGecko Demo API Key
-
Free tier: get your key at coingecko.com/en/api → "Get Free API Key". Without a key the public endpoint is rate-limited and Fundamentals/Intel tabs may show empty data.
-
-
-
-
-
-
${localStorage.getItem('hype_cg_key') ? '✓ CoinGecko key active — 30 req/min, 10k/month' : 'No key — using unauthenticated public endpoint (may rate-limit)'}
-
-
-
-
🔮 APIU Macro Proxy (Cloudflare Worker)
-
Optional: deploy cloudflare/apiu-worker.js to surface apiu.ai's BTC daily verdict + regime state as a second-opinion card in the Intel tab. The APIU key stays server-side as a Worker secret — paste only the worker URL here.
-
-
-
-
-
-
${localStorage.getItem('hype_apiu_proxy_url') ? '✓ APIU proxy active — card appears in Intel tab' : 'Not configured — no card shown in Intel tab'}
-
-
-
-
📲 Telegram Notifications
-
Token stored in your browser only — never committed to code or sent anywhere except Telegram.
-
-
-
Bot Token
-
-
-
-
Your Chat ID
-
-
-
-
-
Send any message to your bot first, then click Auto-detect.
Looking for API proxy, CoinGecko key, APIU or Telegram configuration? It moved to the Settings tab.
@@ -3467,12 +3410,227 @@ document.addEventListener('visibilitychange',()=>{
document.addEventListener('keydown', e => {
if (e.key === 'Escape') closeMktDetail();
});
+// ── Settings page ─────────────────────────────────────────────────────────────
+
+function saveSettingKey(key, inputId, statusId, okMsg) {
+ const v = (document.getElementById(inputId)?.value || '').trim().replace(/\/+$/, '');
+ if (v) localStorage.setItem(key, v); else localStorage.removeItem(key);
+ const s = document.getElementById(statusId);
+ if (s) s.textContent = v ? (okMsg || '✓ Saved') : 'Cleared';
+}
+
+function saveKbSupabase() {
+ const url = (document.getElementById('kb-sb-url')?.value || '').trim().replace(/\/$/, '');
+ const key = (document.getElementById('kb-sb-key')?.value || '').trim();
+ const s = document.getElementById('kb-sb-status');
+ if (url && !key) { if (s) s.textContent = 'Enter the anon key too.'; return; }
+ if (url) { localStorage.setItem('hype_kb_supabase_url', url); localStorage.setItem('hype_kb_supabase_key', key); }
+ else { localStorage.removeItem('hype_kb_supabase_url'); localStorage.removeItem('hype_kb_supabase_key'); }
+ if (s) s.textContent = url ? '✓ Saved — reload page to apply' : 'Cleared — using built-in project (reload to apply)';
+}
+
+function clearKbSupabase() {
+ localStorage.removeItem('hype_kb_supabase_url');
+ localStorage.removeItem('hype_kb_supabase_key');
+ const u = document.getElementById('kb-sb-url'), k = document.getElementById('kb-sb-key');
+ if (u) u.value = ''; if (k) k.value = '';
+ const s = document.getElementById('kb-sb-status');
+ if (s) s.textContent = 'Cleared — using built-in project (reload to apply)';
+}
+
+function clearSettingKey(key, inputId, statusId) {
+ localStorage.removeItem(key);
+ const el = document.getElementById(inputId);
+ if (el) el.value = '';
+ const s = document.getElementById(statusId);
+ if (s) s.textContent = 'Cleared';
+}
+
+function _settingsUrlCard(title, desc, key, inputId, statusId, placeholder, okMsg, activeMsg, emptyMsg) {
+ const cur = localStorage.getItem(key) || '';
+ return `
+
+
${title}
+
${desc}
+
+
+
+
+
+
${cur ? activeMsg : emptyMsg}
+
`;
+}
+
+function loadSettings() {
+ const el = document.getElementById('settings-content');
+ if (!el) return;
+ el.innerHTML = `
+
+
Settings
+
+
Account
+
+
👛 Hyperliquid Wallet
+
All portfolio, trade, funding and flow data is read from this address via the public Hyperliquid API. No keys, read-only.
+
+ ${currentWallet}
+
+
+
+
+
+
Connection
+
+
⚡ API Proxy (Cloudflare Worker)
+
Optional: paste your Cloudflare Worker URL for edge-cached API calls. Leave blank to use Hyperliquid directly.
+
+
+
+
+
+
${localStorage.getItem('hype_proxy_url') ? '✓ Proxy active — reload page to apply' : 'Using direct Hyperliquid API'}
+
+
+
+
🦎 CoinGecko Demo API Key
+
Free tier: get your key at coingecko.com/en/api → "Get Free API Key". Without a key the public endpoint is rate-limited and Fundamentals/Intel tabs may show empty data.
+
+
+
+
+
+
${localStorage.getItem('hype_cg_key') ? '✓ CoinGecko key active — 30 req/min, 10k/month' : 'No key — using unauthenticated public endpoint (may rate-limit)'}
+
+
+ ${_settingsUrlCard(
+ '📰 RSS Proxy (Cloudflare Worker)',
+ 'Optional: deploy cloudflare/worker.js and paste its URL. News feeds will try your private proxy first, falling back to the public CORS proxies (allorigins / rss2json / corsproxy.io) — fewer silent failures and rate limits.',
+ 'hype_rss_proxy', 'rss-proxy-input', 'rss-proxy-status',
+ 'https://hype-rss.your-user.workers.dev',
+ '✓ Saved — used on next News refresh',
+ '✓ RSS proxy active — raced first for all feeds',
+ 'Not configured — using public CORS proxies only')}
+
+ ${_settingsUrlCard(
+ '🤖 Bot Worker URL',
+ 'Optional: your deployed cloudflare/bot-worker.js URL. Powers the bot status widget in News and AI drafts in HL Pulse.',
+ 'hype_bot_url', 'bot-url-input', 'bot-url-status',
+ 'https://hype-bot.your-subdomain.workers.dev',
+ '✓ Saved',
+ '✓ Bot worker configured',
+ 'Not configured')}
+
+
AI
+ ${_settingsUrlCard(
+ '🧠 Supabase Edge Function URL',
+ 'Your claude-proxy Edge Function URL (see AI tab → ⚙ Setup for the one-time deploy). Enables Claude chat, trade lessons, weekly reviews and intel synthesis. The llm-router URL is derived automatically.',
+ 'hype_edge_fn_url', 'edge-url-input', 'edge-url-status',
+ 'https://xyz.supabase.co/functions/v1/claude-proxy',
+ '✓ Saved — AI features enabled',
+ '✓ Configured — AI features enabled',
+ 'Not configured — AI features disabled')}
+
+ ${_settingsUrlCard(
+ '▲ App Backend URL (Vercel)',
+ 'Only needed when this page is served from GitHub Pages instead of your Vercel deployment. Points /api/chat (KB AI, MVRV chat) and /api/trigger-workflow (Daily Brief / Weekly Research "Generate Now") at your Vercel app.',
+ 'hype_trigger_backend_url', 'backend-url-input', 'backend-url-status',
+ 'https://your-app.vercel.app',
+ '✓ Saved',
+ '✓ Backend configured — AI endpoints routed to Vercel',
+ 'Not configured — relative /api/* (works only on the Vercel deployment)')}
+
+
Intel
+
+
🔮 APIU Macro Proxy (Cloudflare Worker)
+
Optional: deploy cloudflare/apiu-worker.js to surface apiu.ai's BTC daily verdict + regime state as a second-opinion card in the Intel tab. The APIU key stays server-side as a Worker secret — paste only the worker URL here.
+
+
+
+
+
+
${localStorage.getItem('hype_apiu_proxy_url') ? '✓ APIU proxy active — card appears in Intel tab' : 'Not configured — no card shown in Intel tab'}
+
+
+
Storage
+
+
📚 Knowledge Base Storage (Supabase)
+
Optional: point the KB tab at your own Supabase project (needs the kb_wiki and kb_trades tables). Leave blank to use the built-in project.