-
{isZh ? '② BTC 信号' : '② BTC Signal'}
-
- {tab === 'bottom'
- ? `Macro cycle bottom · ${btcPosts.length} signals`
- : `Funding-rate extreme reversal · ${btcPosts.length} signals`}
-
+
{isZh ? '宏观氛围' : 'Macro Vibes'}
+ {/* PageHint: brand tagline for the page — same across both tabs so
+ the "what is this page" answer doesn't shift under the user when
+ they click between Bottom / Funding. Tab-specific notes live in
+ the section-hint card right below the tab bar. */}
+
+ Macro vibes for crypto. Read what's about to happen before price prints it.
+
Live
- {tab === 'bottom' && (
-
- This module tracks Bitcoin macro-bottom conditions. It only fires a long-only cycle signal when at least two of three classic bottom markers agree: AHR999, the 200-week moving average, and Pi Cycle Bottom.
-
- )}
-
@@ -107,20 +106,34 @@ export default function BtcSignalPage({
+ {/* Always-visible per-tab explanation. Was hidden behind a hover
+ tooltip on the tab button — users couldn't tell what they were
+ about to look at until they explicitly hovered. */}
{tab === 'bottom' && (
-
- <>
- Fires when
≥2 of 3 classic bottom signals agree:{' '}
-
AHR999 < 0.45 ·
price ≤ 200-week
- MA ·
Pi Cycle Bottom . Long only, low frequency
- (2–4 fires per cycle). Scans daily 00:45 UTC. Designed to ride the
- full cycle: holds up to
18 months , trailing-stop
- exit, no take-profit. Keep leverage ≤2× — amplification comes from
- pyramiding, not from cranking leverage.
- >
+
+ Fires when ≥2 of 3 classic bottom signals agree:{' '}
+ AHR999 < 0.45 · price ≤ 200-week MA
+ {' '}· Pi Cycle Bottom . Long only, 2–4 fires per cycle.
+ Holds up to 18 months with a trailing-stop exit — no take-profit.
)}
+ {/* Macro indicator panel — only relevant on the Macro Bottom tab where
+ users are reasoning about the broader risk regime. The Funding tab
+ has its own live funding panel below. */}
+ {tab === 'bottom' &&
}
+ {tab === 'funding' && (
+
+ Mean-reversion against crowded perp positioning. When 30-day cumulative
+ funding crosses ±3% AND the most recent cycles start
+ cooling off, the scanner bets against the side that's been paying for
+ weeks. Hourly check.
+
+ )}
+
+ {/* Old plain-text per-tab description removed — the same content
+ now lives in the section-hint block above the tab content. */}
+
{tab === 'funding' && (
= 0 ? '+' : ''}${cum.toFixed(2)}%`}
color={cumColor}
sub={`extreme @ ±${thr}%`}
+ hint="Sum of every funding payment over 30 days. Crosses ±3% = one side has been paying for weeks — overcrowded."
/>
@@ -310,16 +327,22 @@ function FundingPanel({
)
}
-function StatBox({ label, value, color, sub }: {
- label: string; value: string; color?: string; sub?: string
+function StatBox({ label, value, color, sub, hint }: {
+ label: string; value: string; color?: string; sub?: string; hint?: string
}) {
return (
{label}
+ letterSpacing: '.06em', marginBottom: 4,
+ display: 'flex', alignItems: 'center' }}>
+ {label}
+ {hint &&
}
+
{value}
{sub &&
{sub}
}
diff --git a/app/[locale]/macro/page.tsx b/app/[locale]/macro/page.tsx
new file mode 100644
index 0000000..4d5f65b
--- /dev/null
+++ b/app/[locale]/macro/page.tsx
@@ -0,0 +1,76 @@
+import { getFundingSnapshot, getPosts } from '@/lib/api'
+import type { Metadata } from 'next'
+import MacroVibesPageClient from './MacroVibesPageClient'
+
+const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://trumpsignal.com'
+export const revalidate = 30
+
+interface MacroVibesPageProps {
+ params: Promise<{ locale: string }>
+}
+
+export async function generateMetadata({
+ params,
+}: MacroVibesPageProps): Promise
{
+ const { locale } = await params
+ const isZh = false // i18n shelved — Chinese branches kept as dead code for future revival; see messages/zh.json
+
+ return {
+ title: isZh ? '宏观氛围 — 加密市场宏观读数' : 'Macro Vibes — read crypto macro before price prints',
+ description: isZh
+ ? 'Trump Alpha 的宏观氛围面板:AHR999、Fear & Greed、BTC 主导率、ETH/BTC、稳定币供应、ETF 资金流、永续 OI、Altcoin Season Index 八大公开宏观指标合一,外加 BTC 周期底部 + 资金费率反转两条触发器。'
+ : 'Macro vibes for crypto. Eight public macro signals in one view — AHR999, Fear & Greed, BTC dominance, ETH/BTC, stablecoin supply, ETF flows, perp OI, Altcoin Season Index — plus BTC bottom and funding-rate triggers.',
+ keywords: isZh
+ ? [
+ '宏观氛围',
+ '加密宏观',
+ 'AHR999',
+ 'Fear and Greed',
+ 'BTC 主导率',
+ 'ETH/BTC',
+ 'ETF 资金流',
+ '稳定币供应',
+ '资金费率反转',
+ 'Altcoin Season Index',
+ ]
+ : [
+ 'crypto macro',
+ 'macro vibes',
+ 'AHR999',
+ 'Fear and Greed Index',
+ 'BTC dominance',
+ 'ETH/BTC ratio',
+ 'stablecoin supply',
+ 'Bitcoin ETF flow',
+ 'funding rate reversal',
+ 'Altcoin Season Index',
+ ],
+ openGraph: {
+ title: isZh ? '宏观氛围 | Trump Alpha' : 'Macro Vibes | Trump Alpha',
+ description: isZh
+ ? '加密宏观一屏看完:八大宏观指标 + BTC 周期底部 + 资金费率反转触发器。'
+ : 'Macro vibes for crypto. Read what is about to happen before price prints it.',
+ },
+ alternates: {
+ canonical: `${siteUrl}/${locale}/macro`,
+ languages: {
+ en: `${siteUrl}/en/macro`,
+ 'x-default': `${siteUrl}/en/macro`,
+ },
+ },
+ }
+}
+
+export default async function MacroVibesPage() {
+ const [posts, fundingSnapshot] = await Promise.all([
+ getPosts(500, 1).catch(() => null),
+ getFundingSnapshot().catch(() => null),
+ ])
+
+ return (
+
+ )
+}
diff --git a/app/[locale]/methodology/page.tsx b/app/[locale]/methodology/page.tsx
index aef65ea..337d708 100644
--- a/app/[locale]/methodology/page.tsx
+++ b/app/[locale]/methodology/page.tsx
@@ -367,11 +367,12 @@ SHORT_INTENT + SHORT_ACTION => ALIGNMENT`,
}
}
-export function generateMetadata({
- params: { locale },
+export async function generateMetadata({
+ params,
}: {
- params: { locale: string }
-}): Metadata {
+ params: Promise<{ locale: string }>
+}): Promise {
+ const { locale } = await params
const copy = getCopy(locale)
return {
@@ -431,7 +432,8 @@ function Formula({ children }: { children: React.ReactNode }) {
)
}
-export default function MethodologyPage({ params: { locale } }: { params: { locale: string } }) {
+export default async function MethodologyPage({ params }: { params: Promise<{ locale: string }> }) {
+ const { locale } = await params
const copy = getCopy(locale)
const isZh = false // i18n shelved — Chinese branches kept as dead code for future revival; see messages/zh.json
diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx
index 2546068..ec787af 100644
--- a/app/[locale]/page.tsx
+++ b/app/[locale]/page.tsx
@@ -18,8 +18,8 @@ export async function generateMetadata({ params }: OverviewPageProps): Promise
}) {
- redirect(`/${params.locale}/trump`)
+ const { locale } = await params
+ redirect(`/${locale}/trump`)
}
diff --git a/app/[locale]/privacy/page.tsx b/app/[locale]/privacy/page.tsx
index f2266c2..40e8a88 100644
--- a/app/[locale]/privacy/page.tsx
+++ b/app/[locale]/privacy/page.tsx
@@ -1,7 +1,8 @@
import Link from 'next/link'
import { getLocale } from 'next-intl/server'
-export default async function PrivacyPage({ params: { locale } }: { params: { locale: string } }) {
+export default async function PrivacyPage({ params }: { params: Promise<{ locale: string }> }) {
+ const { locale } = await params
const intlLocale = await getLocale()
const isZh = false // i18n shelved — Chinese branches kept as dead code for future revival; see messages/zh.json
diff --git a/app/[locale]/settings/SettingsClient.tsx b/app/[locale]/settings/SettingsClient.tsx
index 3b02a59..8978b42 100644
--- a/app/[locale]/settings/SettingsClient.tsx
+++ b/app/[locale]/settings/SettingsClient.tsx
@@ -7,6 +7,7 @@ import { useLocale } from 'next-intl'
import { useAccount } from 'wagmi'
import BotConfigPanel from '@/components/trades/BotConfigPanel'
import TelegramCard from '@/components/telegram/TelegramCard'
+import PageHint from '@/components/ui/PageHint'
/**
* Settings page — the home for all configuration.
@@ -30,7 +31,17 @@ export default function SettingsClient() {
const href = (path: string) => `/${locale}${path}`
return (
-
+
+
+
+
{isZh ? '设置' : 'Settings'}
+
+ Everything that controls your account — subscription, Hyperliquid
+ API key, bot risk parameters, and Telegram alerts.
+
+
+
+
{/* Account card — quick "who am I logged in as" */}
{isZh ? '交易执行' : 'Trades'}
-
{isZh ? '当前持仓、执行历史和按信号来源拆分的盈亏。' : 'Open positions · execution history · P&L by source'}
+
+ What the bot actually did with your money — currently-open positions
+ on top, closed-trade history with realized P&L below.
+
diff --git a/app/[locale]/trump/TrumpPageClient.tsx b/app/[locale]/trump/TrumpPageClient.tsx
index acf7df6..866aa4f 100644
--- a/app/[locale]/trump/TrumpPageClient.tsx
+++ b/app/[locale]/trump/TrumpPageClient.tsx
@@ -7,6 +7,8 @@ import { getPosts } from '@/lib/api'
import { swrFetch } from '@/lib/cache'
import PostRow from '@/components/dashboard/PostCards'
import SystemControl from '@/components/signals/SystemControl'
+import PageHint from '@/components/ui/PageHint'
+import InfoTip from '@/components/ui/InfoTip'
/**
* System 1 — Trump (event-driven scalp). Its own dedicated page.
@@ -80,17 +82,14 @@ export default function TrumpSignalPage({ initialPosts = null }: TrumpSignalPage
{isZh ? '① Trump 信号' : '① Trump Signal'}
-
- {`Event-driven scalp · ${sigCounts.actionable} actionable · ${trumpPosts.length} posts`}
-
+
+ Watches Trump's Truth Social posts in real time, AI-scores each one,
+ and only fires a trade when the conviction is high enough to move price.
+
Live
-
- This engine watches Trump Truth Social in real time, classifies each post, and only opens trades on high-confidence market-moving events. It is built for tight risk, short holds, and a 12-hour cooldown between entries.
-
-
{([
- { key: 'all' },
- { key: 'actionable' },
- { key: 'buy' },
- { key: 'short' },
+ { key: 'all', hint: 'Every post the scraper has captured.' },
+ { key: 'actionable', hint: 'Only posts the AI flagged as BUY or SHORT.' },
+ { key: 'buy', hint: 'Posts where the AI verdict is long BTC.' },
+ { key: 'short', hint: 'Posts where the AI verdict is short BTC.' },
] as const).map(f => (
setSigFilter(f.key)}
>
- {f.key === 'actionable' && !isZh ? '🔥 ' : ''}
- {f.key === 'actionable' && isZh ? '🔥 ' : ''}
+ {f.key === 'actionable' ? '🔥 ' : ''}
{signalLabels[f.key]}
{sigCounts[f.key]}
))}
-
+
+
+ Sentiment
+
+
{SENTIMENTS.map(f => (
-
+
{/* Umami analytics — loaded after interactive so it never blocks render */}