add market-regime guard (SPY trend) — inform + warn
Deploy / lint (push) Successful in 6s
Deploy / test (push) Successful in 36s
Deploy / deploy (push) Successful in 25s

New market_regime_service computes a benchmark (SPY) trend from its 50/200-day
SMAs, cached in a SystemSetting and refreshed by a nightly job; GET /market/regime
exposes it. Dashboard shows a regime banner; setup cards flag a counter-trend
caution when a setup fights the regime (LONG in a bearish market / SHORT in a
bullish one). Informational only — nothing is suppressed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 12:34:07 +02:00
parent 1951531453
commit c4f2673799
14 changed files with 354 additions and 6 deletions
+20
View File
@@ -4,6 +4,8 @@ import { useActivation } from '../hooks/useActivation';
import { useTrades } from '../hooks/useTrades';
import { useWatchlist } from '../hooks/useWatchlist';
import { usePerformance } from '../hooks/usePerformance';
import { useMarketRegime } from '../hooks/useMarketRegime';
import { regimeColor, regimeDot, regimeHeadline } from '../lib/regime';
import { Callout } from '../components/ui/Callout';
import { Section } from '../components/ui/Section';
import { SkeletonCard, SkeletonTable } from '../components/ui/Skeleton';
@@ -55,6 +57,7 @@ export default function DashboardPage() {
const watchlist = useWatchlist();
const activation = useActivation();
const performance = usePerformance();
const regime = useMarketRegime();
const qualifiedSetups = useMemo(
() =>
@@ -98,6 +101,23 @@ export default function DashboardPage() {
</h1>
</div>
{/* Market regime banner */}
{regime.data && (
<div className="glass-sm flex items-center gap-2.5 px-4 py-2.5">
<span className={`inline-block h-2 w-2 rounded-full ${regimeDot(regime.data.label)}`} />
<span className="text-sm text-gray-400">Market regime:</span>
<span className={`text-sm font-semibold ${regimeColor(regime.data.label)}`}>
{regimeHeadline(regime.data)}
</span>
{regime.data.label === 'bearish' && (
<span className="text-xs text-gray-500"> be cautious on new longs</span>
)}
{regime.data.label === 'bullish' && (
<span className="text-xs text-gray-500"> shorts are counter-trend</span>
)}
</div>
)}
{/* Metric strip */}
{(trades.isLoading || performance.isLoading) ? (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">