diff --git a/app/ai-hub/page.tsx b/app/ai-hub/page.tsx index a9badea5..fcb9724f 100644 --- a/app/ai-hub/page.tsx +++ b/app/ai-hub/page.tsx @@ -25,18 +25,15 @@ const ModelScoreboardPanel = dynamic( ); export const metadata = createPageMetadata({ - title: "TradeHax AI Hub - Beginner Friendly Crypto + Stocks Assistant", + title: "TradeHax AI Hub - AI Assistant for Market Intelligence & Services", description: - "A clear, beginner-friendly AI hub for crypto and stock workflows: chat, content creation, image generation, and guided next steps.", + "A clear, beginner-friendly AI hub for market workflows, content creation, image generation, and guided next steps.", path: "/ai-hub", keywords: [ - "beginner ai crypto trading assistant", "ai trading strategies for beginners", - "web3 token roadmap consulting", "ai-powered guitar lessons", "ai trading", - "crypto ai", - "stock ai", + "market ai", "smart environment", "image generation", "ai assistants", @@ -49,18 +46,10 @@ const aiHubFaqJsonLd = { mainEntity: [ { "@type": "Question", - name: "What is a beginner AI crypto trading assistant?", + name: "What can I do in the TradeHax AI Hub?", acceptedAnswer: { "@type": "Answer", - text: "A beginner AI crypto trading assistant helps new traders understand market context, risk controls, and step-by-step execution plans before placing trades.", - }, - }, - { - "@type": "Question", - name: "How does TradeHax support Web3 token roadmap consulting?", - acceptedAnswer: { - "@type": "Answer", - text: "TradeHax provides structured guidance for token utility phases, rollout milestones, and governance readiness so teams can launch responsibly.", + text: "The AI Hub provides chat, image generation, content creation, and guided workflows for market intelligence, music lessons, and digital services.", }, }, { @@ -101,7 +90,7 @@ export default async function AIHubPage({

TradeHax AI Hub

- Clean chat-first interface for crypto, stocks, and prediction markets. Backend intelligence stays fully intact; + Clean chat-first interface for market intelligence, music lessons, and digital services. Backend intelligence stays fully intact; the GUI is now focused, simpler, and easier for every experience level.

@@ -226,20 +215,20 @@ export default async function AIHubPage({
-

Beginner AI Trading + Web3 FAQ

+

AI Hub FAQ

- Structured answers for AI search engines and first-time users looking for practical next steps. + Structured answers for first-time users looking for practical next steps.

-

What is a beginner AI crypto trading assistant?

+

What can I do in the AI Hub?

- It helps new users plan entries, risk limits, and invalidation levels with plain-language guidance before execution. + Use it to chat with AI, generate images, create content, explore market intelligence, and navigate all platform services.

-

Do you support Web3 token roadmap consulting?

+

Do you support product consulting?

Yes — from utility design and phased rollout strategy to governance readiness and KPI mapping.

@@ -262,15 +251,6 @@ export default async function AIHubPage({ > Read AI Trading Guide - - Web3 Roadmap Guide -
diff --git a/app/api/backtest/run/route.ts b/app/api/backtest/run/route.ts deleted file mode 100644 index b38a3cec..00000000 --- a/app/api/backtest/run/route.ts +++ /dev/null @@ -1,84 +0,0 @@ -/** - * POST /api/backtest/run - * - * Accepts a BacktestConfig and returns a full BacktestResult. - * - * ⚠️ BETA FEATURE: Backtesting engine is under development. - * Currently disabled pending full feature completion. See /lib/feature-flags.ts - */ - -import { isFeatureEnabled } from "@/lib/feature-flags"; -import { - enforceRateLimit, - enforceTrustedOrigin, - isJsonContentType, - sanitizePlainText, -} from "@/lib/security"; -import { runBacktest } from "@/lib/trading/backtest-engine"; -import { nanoid } from "@/lib/utils"; -import type { BacktestConfig } from "@/types/trading"; -import { NextRequest, NextResponse } from "next/server"; - -export async function POST(request: NextRequest) { - // Feature flag check: Backtesting is BETA - if (!isFeatureEnabled("trading.backtesting")) { - return NextResponse.json( - { - ok: false, - error: "Strategy backtesting is currently in beta testing. Please check back soon.", - status: "BETA_UNAVAILABLE", - }, - { status: 503 } - ); - } - - const originBlock = enforceTrustedOrigin(request); - if (originBlock) return originBlock; - - if (!isJsonContentType(request)) { - return NextResponse.json({ ok: false, error: "Expected JSON body." }, { status: 415 }); - } - - const rateLimit = enforceRateLimit(request, { - keyPrefix: "api:backtest:run:post", - max: 10, - windowMs: 60_000, - }); - if (!rateLimit.allowed) return rateLimit.response; - - try { - const body: unknown = await request.json(); - if (typeof body !== "object" || body === null) { - return NextResponse.json({ ok: false, error: "Invalid request body." }, { status: 400, headers: rateLimit.headers }); - } - - const b = body as Record; - - const validTimeRanges = ["1M", "3M", "6M", "1Y", "custom"]; - const timeRange = validTimeRanges.includes(String(b.timeRange)) ? String(b.timeRange) : "3M"; - - const config: BacktestConfig = { - id: sanitizePlainText(String(b.id ?? ""), 64) || nanoid(), - symbol: sanitizePlainText(String(b.symbol ?? ""), 12).toUpperCase() || "BTC", - timeRange: timeRange as BacktestConfig["timeRange"], - customStartDate: typeof b.customStartDate === "string" ? b.customStartDate : undefined, - customEndDate: typeof b.customEndDate === "string" ? b.customEndDate : undefined, - initialCapital: typeof b.initialCapital === "number" && b.initialCapital > 0 ? Math.min(b.initialCapital, 10_000_000) : 10_000, - feePct: typeof b.feePct === "number" ? Math.max(0, Math.min(b.feePct, 5)) : 0.1, - slippagePct: typeof b.slippagePct === "number" ? Math.max(0, Math.min(b.slippagePct, 2)) : 0.05, - }; - - const result = runBacktest(config); - - return NextResponse.json( - { ok: true, data: result }, - { headers: rateLimit.headers }, - ); - } catch (error) { - console.error("Backtest run error:", error); - return NextResponse.json( - { ok: false, error: error instanceof Error ? error.message : "Backtest failed." }, - { status: 500 }, - ); - } -} diff --git a/app/api/cron/trading/signal-cadence/route.ts b/app/api/cron/trading/signal-cadence/route.ts deleted file mode 100644 index 5d75accd..00000000 --- a/app/api/cron/trading/signal-cadence/route.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { dispatchTradebotSignalsToDiscord, resolveCadenceTiers } from "@/lib/intelligence/discord-signals"; -import { buildDailyWatchlist } from "@/lib/trading/daily-watchlist"; -import { resolveSignalCadenceWindow } from "@/lib/trading/signal-cadence"; -import { generateTradebotSignalOutlooks } from "@/lib/trading/signal-outlook"; -import { NextRequest, NextResponse } from "next/server"; - -function isAuthorizedCronRequest(request: NextRequest) { - const expected = String(process.env.TRADEHAX_CRON_SECRET || "").trim(); - const auth = request.headers.get("authorization") || ""; - const bearer = auth.startsWith("Bearer ") ? auth.slice(7).trim() : ""; - const vercelCron = request.headers.get("x-vercel-cron"); - - if (expected && bearer === expected) { - return true; - } - if (vercelCron === "1") { - return true; - } - return false; -} - -function parseSymbols(search: URLSearchParams) { - const values = search.getAll("symbol").map((value) => value.trim().toUpperCase()).filter(Boolean); - return values.length > 0 ? values.slice(0, 8) : ["SOL/USDC", "BTC/USDC", "ETH/USDC", "NVDA", "SPY"]; -} - -function parseSeed(value: string | null) { - const parsed = Number.parseInt(String(value ?? ""), 10); - return Number.isFinite(parsed) ? parsed : 201; -} - -function parseDryRun(value: string | null) { - if (!value) return false; - const normalized = value.trim().toLowerCase(); - return normalized === "1" || normalized === "true" || normalized === "yes"; -} - -export async function GET(request: NextRequest) { - if (!isAuthorizedCronRequest(request)) { - return NextResponse.json({ ok: false, error: "Unauthorized cron request." }, { status: 401 }); - } - - const search = request.nextUrl.searchParams; - const dryRun = parseDryRun(search.get("dryRun")); - const cadenceWindow = resolveSignalCadenceWindow({ - forcedWindow: search.get("window") || undefined, - }); - - if (cadenceWindow.window === "offhours") { - return NextResponse.json({ - ok: true, - skipped: true, - reason: "Off-hours or no cadence window matched.", - cadenceWindow, - generatedAt: new Date().toISOString(), - }); - } - - const symbols = parseSymbols(search); - const seed = parseSeed(search.get("seed")); - const signals = generateTradebotSignalOutlooks({ symbols, seed: seed + cadenceWindow.window.length }); - - let dailyWatchlist = null; - if (cadenceWindow.window === "premarket" || search.get("buildWatchlist") === "1") { - dailyWatchlist = await buildDailyWatchlist({ - userId: process.env.TRADEHAX_SIGNAL_DAILY_WATCHLIST_USER || "market_daily_watchlist", - maxEquities: 10, - maxCrypto: 6, - }); - } - - const tiers = resolveCadenceTiers(); - - if (dryRun) { - return NextResponse.json({ - ok: true, - dryRun: true, - generatedAt: new Date().toISOString(), - cadenceWindow, - tiers, - signalsCount: signals.length, - dispatchSummary: { - okCount: 0, - failCount: 0, - skipped: true, - reason: "Dry run mode enabled. No Discord webhooks were called.", - results: [], - }, - dailyWatchlist, - }); - } - - const dispatchResults: Array<{ - ok: boolean; - deliveredAt: string; - deliveredCount: number; - webhookConfigured: boolean; - channelLabel: string; - error?: string; - tier?: "free" | "basic" | "pro" | "elite"; - cadenceWindow?: string; - }> = []; - - for (const tier of tiers) { - const result = await dispatchTradebotSignalsToDiscord({ - userId: `cadence_${tier}`, - tier, - cadenceWindow: cadenceWindow.window, - signals, - }); - dispatchResults.push(result); - } - - const okCount = dispatchResults.filter((item) => item.ok).length; - - return NextResponse.json({ - ok: okCount > 0, - generatedAt: new Date().toISOString(), - cadenceWindow, - tiers, - signalsCount: signals.length, - dispatchSummary: { - okCount, - failCount: dispatchResults.length - okCount, - results: dispatchResults, - }, - dailyWatchlist, - }); -} diff --git a/app/api/intelligence/crypto-flow/route.ts b/app/api/intelligence/crypto-flow/route.ts deleted file mode 100644 index e8153754..00000000 --- a/app/api/intelligence/crypto-flow/route.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { parsePositiveNumber, sanitizeQueryText } from "@/lib/intelligence/filters"; -import { getIntelligenceSnapshot } from "@/lib/intelligence/provider"; -import { SUPPORTED_CRYPTO_CHAINS } from "@/lib/intelligence/types"; -import { enforceRateLimit, enforceTrustedOrigin } from "@/lib/security"; -import { NextRequest, NextResponse } from "next/server"; - -const VALID_SIDES = new Set(["long", "short", "spot_buy", "spot_sell"]); - -export async function GET(request: NextRequest) { - const originBlock = enforceTrustedOrigin(request); - if (originBlock) { - return originBlock; - } - - const rateLimit = enforceRateLimit(request, { - keyPrefix: "intelligence:crypto", - max: 120, - windowMs: 60_000, - }); - if (!rateLimit.allowed) { - return rateLimit.response; - } - - const search = request.nextUrl.searchParams; - const pair = sanitizeQueryText(search.get("pair"), 18).toUpperCase(); - const chain = sanitizeQueryText(search.get("chain"), 32); - const requestedSide = sanitizeQueryText(search.get("side"), 12); - const side = VALID_SIDES.has(requestedSide) ? requestedSide : ""; - const minNotional = parsePositiveNumber(search.get("minNotional")); - const minConfidence = parsePositiveNumber(search.get("minConfidence")); - const snapshot = await getIntelligenceSnapshot(); - - const items = snapshot.cryptoTape - .filter((trade) => { - if (pair && trade.pair !== pair) return false; - if (chain && trade.chain !== chain) return false; - if (side && trade.side !== side) return false; - if (minNotional !== null && trade.notionalUsd < minNotional) return false; - if (minConfidence !== null && trade.confidence < minConfidence) return false; - return true; - }) - .sort((a, b) => Date.parse(b.triggeredAt) - Date.parse(a.triggeredAt)); - - return NextResponse.json( - { - ok: true, - items, - count: items.length, - generatedAt: new Date().toISOString(), - provider: snapshot.status, - supportedChains: SUPPORTED_CRYPTO_CHAINS, - appliedFilters: { - pair: pair || null, - chain: chain || null, - side: side || null, - minNotional, - minConfidence, - }, - }, - { headers: rateLimit.headers }, - ); -} diff --git a/app/api/portfolio/aggregate/route.ts b/app/api/portfolio/aggregate/route.ts deleted file mode 100644 index 071e0d20..00000000 --- a/app/api/portfolio/aggregate/route.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * POST /api/portfolio/aggregate - * - * Accepts a list of exchange connections and returns the aggregated portfolio snapshot. - */ - -import { aggregatePortfolio } from "@/lib/trading/portfolio-aggregator"; -import { - enforceRateLimit, - enforceTrustedOrigin, - isJsonContentType, -} from "@/lib/security"; -import { NextRequest, NextResponse } from "next/server"; -import type { ExchangeConnection } from "@/types/trading"; - -export async function POST(request: NextRequest) { - const originBlock = enforceTrustedOrigin(request); - if (originBlock) return originBlock; - - if (!isJsonContentType(request)) { - return NextResponse.json({ ok: false, error: "Expected JSON body." }, { status: 415 }); - } - - const rateLimit = enforceRateLimit(request, { - keyPrefix: "api:portfolio:aggregate:post", - max: 20, - windowMs: 60_000, - }); - if (!rateLimit.allowed) return rateLimit.response; - - try { - const body: unknown = await request.json(); - if (typeof body !== "object" || body === null || !Array.isArray((body as Record).connections)) { - return NextResponse.json( - { ok: false, error: "Request body must include a `connections` array." }, - { status: 400, headers: rateLimit.headers }, - ); - } - - const connections = (body as { connections: ExchangeConnection[] }).connections; - - // Sanitize connections — never log API keys - const sanitized: ExchangeConnection[] = connections.map((c) => ({ - id: String(c.id ?? "").slice(0, 64), - exchange: (["binance", "coinbase", "kraken", "manual"].includes(c.exchange) ? c.exchange : "manual"), - label: String(c.label ?? "").slice(0, 64), - apiKey: String(c.apiKey ?? "").slice(0, 256), - status: (["connected", "disconnected", "error", "testing"].includes(c.status) ? c.status : "disconnected"), - lastSynced: typeof c.lastSynced === "string" ? c.lastSynced : undefined, - })); - - const snapshot = await aggregatePortfolio(sanitized); - - // Mask API keys in response - const safeConnections = sanitized.map((c) => ({ - ...c, - apiKey: c.apiKey.length > 4 ? `${c.apiKey.slice(0, 4)}${"*".repeat(Math.min(c.apiKey.length - 4, 20))}` : "****", - })); - - return NextResponse.json( - { ok: true, data: { ...snapshot, connections: safeConnections } }, - { headers: rateLimit.headers }, - ); - } catch (error) { - console.error("Portfolio aggregation error:", error); - return NextResponse.json( - { ok: false, error: error instanceof Error ? error.message : "Aggregation failed." }, - { status: 500 }, - ); - } -} diff --git a/app/api/sentiment/route.ts b/app/api/sentiment/route.ts deleted file mode 100644 index dc9b5c84..00000000 --- a/app/api/sentiment/route.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * GET /api/sentiment - * - * Returns the current sentiment snapshot (market + per-asset scores, - * rolling history, and recent events). - * - * Query params: - * - symbols comma-separated list of asset symbols (default: BTC,ETH,SOL) - */ - -import { buildSentimentSnapshot } from "@/lib/trading/sentiment-engine"; -import { enforceRateLimit } from "@/lib/security"; -import { NextRequest, NextResponse } from "next/server"; - -export const dynamic = "force-dynamic"; - -export async function GET(request: NextRequest) { - const rateLimit = enforceRateLimit(request, { - keyPrefix: "api:sentiment:get", - max: 60, - windowMs: 60_000, - }); - - if (!rateLimit.allowed) { - return rateLimit.response; - } - - const { searchParams } = new URL(request.url); - const rawSymbols = searchParams.get("symbols") ?? "BTC,ETH,SOL"; - const symbols = rawSymbols - .split(",") - .map((s) => s.trim().toUpperCase()) - .filter((s) => /^[A-Z0-9]{1,12}$/.test(s)) - .slice(0, 10); // cap at 10 assets - - if (symbols.length === 0) { - return NextResponse.json( - { ok: false, error: "No valid symbols provided." }, - { status: 400, headers: rateLimit.headers }, - ); - } - - // Use a 1-minute seed window for lightweight cache coherence. - const seed = Math.floor(Date.now() / 60_000); - const snapshot = buildSentimentSnapshot(seed, symbols); - - return NextResponse.json( - { ok: true, data: snapshot }, - { - headers: { - ...rateLimit.headers, - "Cache-Control": "public, max-age=60, stale-while-revalidate=30", - }, - }, - ); -} diff --git a/app/api/signals/explain/route.ts b/app/api/signals/explain/route.ts deleted file mode 100644 index 57b30d96..00000000 --- a/app/api/signals/explain/route.ts +++ /dev/null @@ -1,66 +0,0 @@ -/** - * POST /api/signals/explain - * - * Accepts a TradingSignal and returns a full XAI explanation. - */ - -import { explainSignal } from "@/lib/trading/explainability-engine"; -import { - enforceRateLimit, - enforceTrustedOrigin, - isJsonContentType, - sanitizePlainText, -} from "@/lib/security"; -import { NextRequest, NextResponse } from "next/server"; -import type { TradingSignal } from "@/types/trading"; - -export async function POST(request: NextRequest) { - const originBlock = enforceTrustedOrigin(request); - if (originBlock) return originBlock; - - if (!isJsonContentType(request)) { - return NextResponse.json({ ok: false, error: "Expected JSON body." }, { status: 415 }); - } - - const rateLimit = enforceRateLimit(request, { - keyPrefix: "api:signals:explain:post", - max: 30, - windowMs: 60_000, - }); - if (!rateLimit.allowed) return rateLimit.response; - - try { - const body: unknown = await request.json(); - if (typeof body !== "object" || body === null) { - return NextResponse.json({ ok: false, error: "Invalid request body." }, { status: 400, headers: rateLimit.headers }); - } - - const b = body as Record; - - const signal: TradingSignal = { - id: sanitizePlainText(String(b.id ?? ""), 64) || `sig-${Date.now()}`, - symbol: sanitizePlainText(String(b.symbol ?? ""), 12).toUpperCase() || "BTC", - action: (["buy", "sell", "hold"].includes(String(b.action)) ? b.action : "hold") as TradingSignal["action"], - confidence: typeof b.confidence === "number" ? Math.max(0, Math.min(1, b.confidence)) : 0.5, - price: typeof b.price === "number" ? b.price : 0, - targetPrice: typeof b.targetPrice === "number" ? b.targetPrice : 0, - stopLoss: typeof b.stopLoss === "number" ? b.stopLoss : 0, - timeframe: sanitizePlainText(String(b.timeframe ?? ""), 8) || "1h", - generatedAt: typeof b.generatedAt === "string" ? b.generatedAt : new Date().toISOString(), - source: sanitizePlainText(String(b.source ?? ""), 64) || "ai-engine", - }; - - const explanation = explainSignal(signal); - - return NextResponse.json( - { ok: true, data: explanation }, - { headers: rateLimit.headers }, - ); - } catch (error) { - console.error("Signal explain error:", error); - return NextResponse.json( - { ok: false, error: error instanceof Error ? error.message : "Explanation failed." }, - { status: 500 }, - ); - } -} diff --git a/app/api/trading/bot/[id]/stats/route.ts b/app/api/trading/bot/[id]/stats/route.ts deleted file mode 100644 index d332c612..00000000 --- a/app/api/trading/bot/[id]/stats/route.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** - * GET /api/trading/bot/[id]/stats - * Get bot statistics and performance - */ - -import { enforceRateLimit, enforceTrustedOrigin, sanitizePlainText } from "@/lib/security"; -import { NextRequest, NextResponse } from "next/server"; - -interface BotStats { - totalTrades: number; - successfulTrades: number; - winRate: string; - totalProfit: string; - totalLoss: string; - netProfit: string; -} - -export async function GET( - request: NextRequest, - { params }: { params: Promise<{ id: string }> }, -) { - const originBlock = enforceTrustedOrigin(request); - if (originBlock) { - return originBlock; - } - - const rateLimit = enforceRateLimit(request, { - keyPrefix: "trading:bot:stats:get", - max: 60, - windowMs: 60_000, - }); - if (!rateLimit.allowed) { - return rateLimit.response; - } - - try { - const { id: botId } = await params; - const sanitizedBotId = sanitizePlainText(botId || "", 64).replace(/[^a-zA-Z0-9_-]/g, ""); - - if (!sanitizedBotId) { - return NextResponse.json( - { ok: false, error: "Bot ID is required" }, - { status: 400, headers: rateLimit.headers }, - ); - } - - // TODO: Fetch bot stats from database - const stats: BotStats = { - totalTrades: 42, - successfulTrades: 35, - winRate: "83.33", - totalProfit: "2.45", - totalLoss: "0.48", - netProfit: "1.97", - }; - - return NextResponse.json({ - ok: true, - botId: sanitizedBotId, - stats, - lastUpdated: new Date().toISOString(), - }, { headers: rateLimit.headers }); - } catch (error) { - console.error("Stats fetch error:", error); - return NextResponse.json( - { - ok: false, - error: error instanceof Error ? error.message : "Stats fetch failed", - }, - { status: 500 }, - ); - } -} diff --git a/app/api/trading/bot/create/route.ts b/app/api/trading/bot/create/route.ts deleted file mode 100644 index e3589bbd..00000000 --- a/app/api/trading/bot/create/route.ts +++ /dev/null @@ -1,133 +0,0 @@ -/** - * POST /api/trading/bot/create - * Create a new TradeHax bot - * - * ⚠️ BETA FEATURE: This endpoint requires full database persistence and execution logic. - * Currently disabled pending completion. See /lib/feature-flags.ts - */ - -import { isFeatureEnabled } from "@/lib/feature-flags"; -import { - enforceRateLimit, - enforceTrustedOrigin, - isJsonContentType, - sanitizePlainText, -} from "@/lib/security"; -import { NextRequest, NextResponse } from "next/server"; - -interface CreateBotRequest { - name: string; - strategy: "scalping" | "swing" | "long-term" | "arbitrage"; - riskLevel: "low" | "medium" | "high"; - allocatedCapital: number; -} - -export async function POST(request: NextRequest) { - // Feature flag check: Bot creation is BETA - if (!isFeatureEnabled("trading.bot-creation")) { - return NextResponse.json( - { - ok: false, - error: "Trading bot creation is currently in beta testing. Please check back soon.", - status: "BETA_UNAVAILABLE", - }, - { status: 503 } - ); - } - - const originBlock = enforceTrustedOrigin(request); - if (originBlock) { - return originBlock; - } - - if (!isJsonContentType(request)) { - return NextResponse.json({ ok: false, error: "Expected JSON body." }, { status: 415 }); - } - - const rateLimit = enforceRateLimit(request, { - keyPrefix: "trading:bot:create:post", - max: 30, - windowMs: 60_000, - }); - if (!rateLimit.allowed) { - return rateLimit.response; - } - - try { - const body: CreateBotRequest = await request.json(); - const name = sanitizePlainText(String(body.name ?? ""), 64); - const strategy = String(body.strategy ?? ""); - const riskLevel = String(body.riskLevel ?? ""); - const allocatedCapital = - typeof body.allocatedCapital === "number" - ? body.allocatedCapital - : Number.parseFloat(String(body.allocatedCapital ?? "NaN")); - - // Validate input - if (!name || !strategy || !riskLevel || !Number.isFinite(allocatedCapital)) { - return NextResponse.json( - { ok: false, error: "Missing required fields" }, - { status: 400, headers: rateLimit.headers }, - ); - } - - if ( - strategy !== "scalping" && - strategy !== "swing" && - strategy !== "long-term" && - strategy !== "arbitrage" - ) { - return NextResponse.json( - { ok: false, error: "Invalid strategy." }, - { status: 400, headers: rateLimit.headers }, - ); - } - - if (riskLevel !== "low" && riskLevel !== "medium" && riskLevel !== "high") { - return NextResponse.json( - { ok: false, error: "Invalid riskLevel." }, - { status: 400, headers: rateLimit.headers }, - ); - } - - if (allocatedCapital < 0.1 || allocatedCapital > 1000) { - return NextResponse.json( - { ok: false, error: "Allocated capital must be between 0.1 and 1000 native units" }, - { status: 400, headers: rateLimit.headers }, - ); - } - - // Create bot (would save to database) - const botId = `bot-${Date.now()}`; - const bot = { - id: botId, - name, - strategy, - riskLevel, - allocatedCapital, - enabled: true, - executedTrades: 0, - profitLoss: 0, - winRate: 0, - createdAt: Date.now(), - updatedAt: Date.now(), - }; - - // TODO: Save to database (Firebase, PostgreSQL, etc.) - - return NextResponse.json({ - ok: true, - bot, - message: `Bot "${name}" created successfully`, - }, { headers: rateLimit.headers }); - } catch (error) { - console.error("Bot creation error:", error); - return NextResponse.json( - { - ok: false, - error: error instanceof Error ? error.message : "Bot creation failed", - }, - { status: 500 }, - ); - } -} diff --git a/app/api/trading/signal/discord/route.ts b/app/api/trading/signal/discord/route.ts deleted file mode 100644 index d1549f98..00000000 --- a/app/api/trading/signal/discord/route.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { dispatchTradebotSignalsToDiscord } from "@/lib/intelligence/discord-signals"; -import { resolveRequestUserId } from "@/lib/monetization/identity"; -import { enforceRateLimit, enforceTrustedOrigin, isJsonContentType } from "@/lib/security"; -import { generateTradebotSignalOutlooks } from "@/lib/trading/signal-outlook"; -import { NextRequest, NextResponse } from "next/server"; - -type DiscordSignalRequest = { - symbols?: string[]; - seed?: number; - dispatch?: boolean; -}; - -function parseSymbols(value: unknown) { - if (!Array.isArray(value)) return ["SOL/USDC", "BTC/USDC", "ETH/USDC"]; - - const symbols = value - .map((s) => String(s || "").trim().toUpperCase()) - .filter((s) => s.length > 0 && s.length <= 16) - .slice(0, 8); - - return symbols.length > 0 ? symbols : ["SOL/USDC", "BTC/USDC", "ETH/USDC"]; -} - -function parseSeed(value: unknown) { - const num = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10); - return Number.isFinite(num) ? num : 101; -} - -function parseDispatch(value: unknown) { - return value === true || value === "true" || value === 1 || value === "1"; -} - -export async function GET(request: NextRequest) { - const originBlock = enforceTrustedOrigin(request); - if (originBlock) return originBlock; - - const rateLimit = enforceRateLimit(request, { - keyPrefix: "trading:signal:discord:get", - max: 60, - windowMs: 60_000, - }); - if (!rateLimit.allowed) return rateLimit.response; - - const search = request.nextUrl.searchParams; - const symbols = parseSymbols(search.getAll("symbol").length > 0 ? search.getAll("symbol") : undefined); - const seed = parseSeed(search.get("seed")); - const shouldDispatch = parseDispatch(search.get("dispatch")); - const userId = await resolveRequestUserId(request, search.get("userId")); - - const signals = generateTradebotSignalOutlooks({ symbols, seed }); - const dispatch = shouldDispatch - ? await dispatchTradebotSignalsToDiscord({ - userId, - signals, - }) - : null; - - return NextResponse.json( - { - ok: true, - userId, - generatedAt: new Date().toISOString(), - signals, - dispatch, - }, - { headers: rateLimit.headers }, - ); -} - -export async function POST(request: NextRequest) { - const originBlock = enforceTrustedOrigin(request); - if (originBlock) return originBlock; - - if (!isJsonContentType(request)) { - return NextResponse.json({ ok: false, error: "Expected JSON body." }, { status: 415 }); - } - - const rateLimit = enforceRateLimit(request, { - keyPrefix: "trading:signal:discord:post", - max: 40, - windowMs: 60_000, - }); - if (!rateLimit.allowed) return rateLimit.response; - - const body = (await request.json()) as DiscordSignalRequest; - const symbols = parseSymbols(body.symbols); - const seed = parseSeed(body.seed); - const userId = await resolveRequestUserId(request, undefined); - const dispatchRequested = body.dispatch !== false; - - const signals = generateTradebotSignalOutlooks({ symbols, seed }); - const dispatch = dispatchRequested - ? await dispatchTradebotSignalsToDiscord({ - userId, - signals, - }) - : null; - - return NextResponse.json( - { - ok: true, - userId, - generatedAt: new Date().toISOString(), - dispatchRequested, - signals, - dispatch, - }, - { headers: rateLimit.headers }, - ); -} diff --git a/app/api/trading/signal/predictive/route.ts b/app/api/trading/signal/predictive/route.ts deleted file mode 100644 index 7450118b..00000000 --- a/app/api/trading/signal/predictive/route.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { enforceRateLimit, enforceTrustedOrigin } from "@/lib/security"; -import { generateTradebotSignalOutlooks } from "@/lib/trading/signal-outlook"; -import { NextRequest, NextResponse } from "next/server"; - -const symbols = ["SOL/USDC", "ETH/USDC", "BTC/USDC"]; - -function generatePredictiveSignals() { - return generateTradebotSignalOutlooks({ - symbols, - seed: 101, - }); -} - -export async function GET(request: NextRequest) { - const originBlock = enforceTrustedOrigin(request); - if (originBlock) { - return originBlock; - } - - const rateLimit = enforceRateLimit(request, { - keyPrefix: "trading:signal:predictive", - max: 100, - windowMs: 60_000, - }); - if (!rateLimit.allowed) { - return rateLimit.response; - } - - const feedSource = - process.env.BLOOMBERG_API_KEY || process.env.BPIPE_TOKEN ? "bloomberg" : "simulated"; - - return NextResponse.json( - { - ok: true, - source: feedSource, - signals: generatePredictiveSignals(), - notes: { - model: "tradebot-signal-outlook-v1", - includes: ["timeframes", "macro", "micro", "options-flow", "hedge-fund-indicators", "learner/premium"], - }, - }, - { headers: rateLimit.headers }, - ); -} diff --git a/app/api/trading/signal/process/route.ts b/app/api/trading/signal/process/route.ts deleted file mode 100644 index e505237e..00000000 --- a/app/api/trading/signal/process/route.ts +++ /dev/null @@ -1,123 +0,0 @@ -/** - * POST /api/trading/signal/process - * Process trading signal and execute bot action - */ - -import { - enforceRateLimit, - enforceTrustedOrigin, - isFiniteNumberInRange, - isJsonContentType, - sanitizePlainText, -} from "@/lib/security"; -import { NextRequest, NextResponse } from "next/server"; - -interface TradeSignalRequest { - symbol: string; - action: "buy" | "sell" | "hold"; - confidence: number; - price: number; - targetPrice: number; - stopLoss: number; -} - -export async function POST(request: NextRequest) { - const originBlock = enforceTrustedOrigin(request); - if (originBlock) { - return originBlock; - } - - if (!isJsonContentType(request)) { - return NextResponse.json({ ok: false, error: "Expected JSON body." }, { status: 415 }); - } - - const rateLimit = enforceRateLimit(request, { - keyPrefix: "trading:signal:process:post", - max: 40, - windowMs: 60_000, - }); - if (!rateLimit.allowed) { - return rateLimit.response; - } - - try { - const body: TradeSignalRequest = await request.json(); - const symbol = sanitizePlainText(String(body.symbol ?? ""), 24).toUpperCase(); - const action = String(body.action ?? ""); - const confidence = - typeof body.confidence === "number" - ? body.confidence - : Number.parseFloat(String(body.confidence ?? "NaN")); - const price = - typeof body.price === "number" ? body.price : Number.parseFloat(String(body.price ?? "NaN")); - const targetPrice = - typeof body.targetPrice === "number" - ? body.targetPrice - : Number.parseFloat(String(body.targetPrice ?? "NaN")); - const stopLoss = - typeof body.stopLoss === "number" - ? body.stopLoss - : Number.parseFloat(String(body.stopLoss ?? "NaN")); - - // Validate signal - if (!symbol || !action || !Number.isFinite(confidence)) { - return NextResponse.json( - { ok: false, error: "Missing required fields" }, - { status: 400, headers: rateLimit.headers }, - ); - } - - if (action !== "buy" && action !== "sell" && action !== "hold") { - return NextResponse.json( - { ok: false, error: "Invalid action." }, - { status: 400, headers: rateLimit.headers }, - ); - } - - if (!isFiniteNumberInRange(confidence, 0, 1)) { - return NextResponse.json( - { ok: false, error: "Confidence must be between 0 and 1" }, - { status: 400, headers: rateLimit.headers }, - ); - } - - if ( - !isFiniteNumberInRange(price, 0, 100_000_000) || - !isFiniteNumberInRange(targetPrice, 0, 100_000_000) || - !isFiniteNumberInRange(stopLoss, 0, 100_000_000) - ) { - return NextResponse.json( - { ok: false, error: "Invalid price fields." }, - { status: 400, headers: rateLimit.headers }, - ); - } - - const signal = { - symbol, - action: action as "buy" | "sell" | "hold", - confidence, - price, - targetPrice, - stopLoss, - }; - - // TODO: Send to bot for execution - // bot.processSignal(signal) - - return NextResponse.json({ - ok: true, - signal, - status: "processing", - message: `Signal for ${symbol} is being processed`, - }, { headers: rateLimit.headers }); - } catch (error) { - console.error("Signal processing error:", error); - return NextResponse.json( - { - ok: false, - error: error instanceof Error ? error.message : "Signal processing failed", - }, - { status: 500 }, - ); - } -} diff --git a/app/beginner-ai-crypto-trading-assistant/page.tsx b/app/beginner-ai-crypto-trading-assistant/page.tsx index 14dc3105..979637aa 100644 --- a/app/beginner-ai-crypto-trading-assistant/page.tsx +++ b/app/beginner-ai-crypto-trading-assistant/page.tsx @@ -1,95 +1,5 @@ -import { TrackedCtaLink } from "@/components/monetization/TrackedCtaLink"; -import { createPageMetadata } from "@/lib/seo"; -import Script from "next/script"; - -export const metadata = createPageMetadata({ - title: "Beginner AI Crypto Trading Assistant | TradeHax AI", - description: - "Learn beginner AI crypto trading workflows with clear risk controls, scenario planning, and practical next actions.", - path: "/beginner-ai-crypto-trading-assistant", - keywords: [ - "beginner ai crypto trading assistant", - "ai trading strategies for beginners", - "crypto risk management beginner", - "how to start ai trading", - ], -}); - -const faqJsonLd = { - "@context": "https://schema.org", - "@type": "FAQPage", - mainEntity: [ - { - "@type": "Question", - name: "How can beginners use AI for crypto trading safely?", - acceptedAnswer: { - "@type": "Answer", - text: "Start with small position sizing, explicit invalidation levels, and scenario-based plans. AI should assist decision quality, not replace risk discipline.", - }, - }, - { - "@type": "Question", - name: "What should an AI trading plan include?", - acceptedAnswer: { - "@type": "Answer", - text: "Include market thesis, entry trigger, stop/invalidation, target zones, and one concrete next action for execution or stand-down.", - }, - }, - ], -}; +import { redirect } from "next/navigation"; export default function BeginnerAiCryptoTradingAssistantPage() { - return ( -
- - - -
-
-

Beginner Track

-

Beginner AI Crypto Trading Assistant

-

- Get operator-grade guidance without overwhelm. Build confidence with risk-aware playbooks, structured prompts, - and clear execution checkpoints. -

- -
- {[ - "Define thesis + invalidation before entry", - "Use bounded scenarios and confidence ranges", - "Execute only when trigger and risk profile align", - ].map((item) => ( -
- {item} -
- ))} -
- -
- - Start in AI Hub - - - Read Strategy Guide - -
-
-
-
- ); + redirect("/crypto-project"); } - diff --git a/app/crypto-project/page.tsx b/app/crypto-project/page.tsx index 24ca9c7b..e2a50d82 100644 --- a/app/crypto-project/page.tsx +++ b/app/crypto-project/page.tsx @@ -2,109 +2,326 @@ import { TrackedCtaLink } from "@/components/monetization/TrackedCtaLink"; import { createPageMetadata } from "@/lib/seo"; import { - BadgeDollarSign, - Blocks, - Gem, - ShieldCheck, - Sparkles, + Activity, + ArrowRight, + BarChart3, + BrainCircuit, + CheckCircle2, + FlaskConical, + LayoutDashboard, + Radar, + Sparkles, } from "lucide-react"; export const metadata = createPageMetadata({ - title: "Digital Services & Product Roadmap | TradeHax AI", + title: "Crypto Project | TradeHax AI — Cross-Chain Intelligence & Trading Tools", description: - "Explore TradeHax AI's service roadmap including AI consulting, web development, game experiences, and premium platform updates.", + "The TradeHax AI crypto project: cross-chain flow intelligence, AI-powered portfolio analytics, strategy building, backtesting, and sentiment analysis — all in one place.", path: "/crypto-project", - keywords: ["digital services", "ai consulting", "web development", "product roadmap", "platform updates"], + keywords: [ + "crypto intelligence", + "cross-chain flow", + "crypto portfolio tracker", + "AI trading tools", + "crypto strategy builder", + "backtesting crypto", + "crypto sentiment engine", + "web3 analytics", + "bitcoin ethereum solana", + ], }); -const features = [ +const capabilities = [ { - title: "AI Consulting", - text: "Get expert guidance on integrating AI into your workflow, products, and business operations.", - icon: ShieldCheck, + icon: Radar, + title: "Cross-Chain Flow Intelligence", + description: + "Monitor pair-level directional flow across Ethereum, Solana, Avalanche, BSC, and more. Filter by chain, pair, side, notional size, and confidence score in real time.", + color: "cyan", }, { - title: "Web Development", - text: "Custom websites, apps, and digital systems built for revenue and growth.", - icon: Gem, + icon: LayoutDashboard, + title: "Portfolio Dashboard", + description: + "Connect your exchanges and track your full multi-asset crypto portfolio in one place. Real-time value, allocation charts, and AI-powered rebalance suggestions.", + color: "emerald", }, { - title: "Premium Access", - text: "Unlock premium tiers tied to subscriptions, perks, and upcoming feature releases.", - icon: BadgeDollarSign, + icon: Activity, + title: "Sentiment Engine", + description: + "Fear & Greed analysis aggregated from social media, news, and on-chain signals. Watch market mood shift in real time across BTC, ETH, and SOL.", + color: "amber", }, { - title: "Game + Rewards Integration", - text: "Hyperborea rewards connect to scoring, with bonuses based on gameplay and skill progression.", - icon: Sparkles, + icon: BrainCircuit, + title: "Strategy Builder", + description: + "Drag-and-drop no-code strategy canvas. Combine indicators, filters, and actions, then export or push directly to a bot.", + color: "purple", + }, + { + icon: FlaskConical, + title: "Backtesting Sandbox", + description: + "Run your strategies against historical crypto data. Analyze equity curves, win rate, max drawdown, and monthly returns with one-click reports.", + color: "rose", + }, + { + icon: BarChart3, + title: "AI Signal Explainability", + description: + "See exactly why the AI generated each crypto signal. Factor weights, confidence breakdown, risk assessment, and similar historical precedents.", + color: "indigo", + }, +] as const; + +const roadmapItems = [ + { + phase: "Now", + label: "Live", + color: "emerald", + items: [ + "Cross-chain crypto flow tape (ETH, SOL, AVAX, BSC)", + "Real-time pair-level directional flow with confidence scoring", + "Multi-exchange portfolio aggregation and allocation charts", + "AI-powered rebalance suggestions", + "Fear & Greed sentiment gauge", + ], + }, + { + phase: "Next", + label: "In Progress", + color: "cyan", + items: [ + "Drag-and-drop strategy builder with no-code blocks", + "Historical backtesting engine with equity curve", + "AI explainability layer for each generated signal", + "On-chain whale radar and wallet tracking", + "Cross-asset correlation scanner", + ], + }, + { + phase: "Later", + label: "Planned", + color: "purple", + items: [ + "Automated bot execution with kill-switch controls", + "Decentralised exchange (DEX) analytics integration", + "Multi-signature portfolio management support", + "Advanced options flow for crypto derivatives", + "Institutional-grade reporting and export tools", + ], + }, +] as const; + +const faqs = [ + { + q: "Is this financial advice?", + a: "No. All signals, flow data, and analytics are strictly educational and informational. TradeHax AI does not provide personalised financial or investment advice. Always conduct your own research and consult a licensed financial professional before trading.", + }, + { + q: "Which blockchains are supported?", + a: "The crypto flow intelligence currently covers Ethereum, Solana, Avalanche (C-Chain), BSC, Polygon, Arbitrum, and Optimism. Coverage is expanding with each release.", + }, + { + q: "How is the flow data sourced?", + a: "Flow data is aggregated from on-chain transaction feeds, DEX APIs, and centralised exchange order-book tapes. All data is filtered for minimum notional thresholds and assigned a confidence score before display.", + }, + { + q: "Can I use these tools without connecting a wallet or exchange?", + a: "Yes. The flow intelligence and sentiment modules are fully read-only and require no wallet or API connection. The portfolio dashboard optionally connects to exchanges for real-time balance tracking.", + }, + { + q: "What is the risk disclaimer for automated strategies?", + a: "Automated crypto strategies carry significant risk including total loss of capital. Markets are volatile, APIs can fail, and past backtest performance is not indicative of future results. Use position sizing and hard stop-losses at all times.", }, ] as const; export default function CryptoProjectPage() { return (
-
-
- Platform Hub -

- Product Roadmap + + {/* ── Hero ── */} +
+ Crypto Project +

+ Cross-Chain Intelligence & AI Trading Tools

-

- Clear updates on service offerings, platform access, and premium utility planning tied to the broader platform. +

+ The TradeHax AI crypto platform unifies cross-chain flow intelligence, portfolio analytics, sentiment + monitoring, strategy building, and AI signal explainability — all under one roof.

-
+
- Open Hyperborea - + Launch AI Copilot + - View Upgrade Plans + View Intelligence Hub
- + + + {/* ── Capabilities ── */} +
+
+ What's Included +

Platform Capabilities

+

+ Six production-ready modules working together — from on-chain flow to automated strategy execution. +

+
+
+ {capabilities.map(({ icon: Icon, title, description, color }) => ( +
+
+ +
+

{title}

+

{description}

+
+ ))} +
+
+ + {/* ── Why Crypto Intelligence ── */} +
+ Edge +

Why Use AI-Powered Crypto Intelligence?

+
+
+ {[ + { text: "See directional flow before price moves — cross-chain notional data surfaces large coordinated buys and sells." }, + { text: "Risk-first framework with compliance language — educational signals only, never financial advice." }, + { text: "Multi-chain coverage unified in one view — no need to monitor five separate block explorers." }, + ].map(({ text }) => ( +
+ +

{text}

+
+ ))} +
+
+ {[ + { text: "Backtested confidence scoring — every signal comes with a historical win-rate context." }, + { text: "Explainable AI — understand the exact factors and weights behind each generated signal." }, + { text: "Sentiment-aware strategy tuning — sync strategy aggressiveness with live Fear & Greed conditions." }, + ].map(({ text }) => ( +
+ +

{text}

+
+ ))} +
+
+
-
- {features.map(({ title, text, icon: Icon }) => ( -
- -

{title}

-

{text}

-
- ))} + {/* ── Roadmap ── */} +
+
+ Progress +

Product Roadmap

+
+
+ {roadmapItems.map(({ phase, label, color, items }) => ( +
+
+ + {label} + +

{phase}

+
+
    + {items.map((item) => ( +
  • + + {item} +
  • + ))} +
+
+ ))} +
-
-

- Project Notes -

-
    -
  • All features are designed to support service value and reduce friction for visitors.
  • -
  • Premium access is built around subscriptions, not token gating.
  • -
  • We track conversion from game activity, bookings, and service inquiries.
  • -
+ {/* ── FAQ & Disclaimers ── */} +
+ FAQ & Disclaimers +

Common Questions

+
+ {faqs.map(({ q, a }) => ( +
+ {q} +

{a}

+
+ ))} +
+
+ Important Risk Disclosure + Cryptocurrency trading involves significant risk of loss and is not suitable for all investors. Past + performance of any tool, signal, or strategy shown on this platform is not indicative of future results. + TradeHax AI is an educational technology platform and does not hold any financial services licence. Nothing + on this page constitutes financial, investment, or trading advice. +
+
-
- Advanced implementation notes -
    -
  • Keep service APIs behind secure environment variables and server-side validation.
  • -
  • Route users into relevant service and subscription offers based on their interests.
  • -
  • Apply analytics across game sessions, booking submissions, and service inquiries for optimization.
  • -
-
+ {/* ── CTA Links ── */} +
+

Get Started

+
+ + AI Copilot + + + + Intelligence Hub + + + View Plans + + + Book Consult + +
+

); diff --git a/app/intelligence/crypto-flow/page.tsx b/app/intelligence/crypto-flow/page.tsx index 6f7bf5d6..d626677d 100644 --- a/app/intelligence/crypto-flow/page.tsx +++ b/app/intelligence/crypto-flow/page.tsx @@ -1,33 +1,5 @@ -import { CryptoFlowPanel } from "@/components/intelligence/CryptoFlowPanel"; -import { IntelligencePageShell } from "@/components/intelligence/IntelligencePageShell"; -import { createPageMetadata } from "@/lib/seo"; -import type { Metadata } from "next"; - -export const metadata: Metadata = createPageMetadata({ - title: "Crypto Flow Intelligence | TradeHax Intelligence", - description: "Cross-chain crypto flow monitor with confidence and notional filters.", - path: "/intelligence/crypto-flow", -}); +import { redirect } from "next/navigation"; export default function IntelligenceCryptoFlowPage() { - return ( -
- -
- - - -
-
- ); + redirect("/crypto-project"); } - diff --git a/app/intelligence/page.tsx b/app/intelligence/page.tsx index 3db8c3fe..56d8b1a5 100644 --- a/app/intelligence/page.tsx +++ b/app/intelligence/page.tsx @@ -15,7 +15,6 @@ import { CandlestickChart, Crosshair, Newspaper, - Radar, Shield, Sparkles, TrendingUp, @@ -24,9 +23,9 @@ import { export const metadata = createPageMetadata({ title: "Trade Intelligence | AI Quant Copilot for Real-Time Signals", description: - "AI quant copilot for real-time signals, backtesting, and explainable trade workflows. Options flow, dark pool activity, crypto signals, and institutional-grade analytics.", + "AI quant copilot for real-time signals, backtesting, and explainable trade workflows. Options flow, dark pool activity, and institutional-grade analytics.", path: "/intelligence", - keywords: ["market intelligence", "options flow", "dark pool", "crypto flow", "trading analytics", "AI copilot", "trade signals"], + keywords: ["market intelligence", "options flow", "dark pool", "trading analytics", "AI copilot", "trade signals"], }); export default async function IntelligenceHubPage() { @@ -80,7 +79,7 @@ export default async function IntelligenceHubPage() {

Real-Time Market Signals

- Live options flow, dark pool blocks, and crypto movements with unusual activity detection + Live options flow and dark pool blocks with unusual activity detection and AI scoring

@@ -113,7 +112,7 @@ export default async function IntelligenceHubPage() {

Multi-Asset Coverage

- Equities, options, crypto, political trades—all in one unified intelligence layer + Equities, options, and political trades — all in one unified intelligence layer

@@ -146,18 +145,17 @@ export default async function IntelligenceHubPage() { -
+
- } /> - } - /> Welcome to TradeHax AI Onboarding

Get Started

- This onboarding guide will help you quickly understand the platform, unlock AI features, and access trading tools. Follow the steps below for a seamless start. + This onboarding guide will help you quickly understand the platform, unlock AI features, and explore platform tools. Follow the steps below for a seamless start.

  1. Explore the AI Hub for advanced tools.
  2. -
  3. Visit Trading to start your journey.
  4. +
  5. Visit Crypto Project for trading tools and intelligence.
  6. Check Services for personalized options.
  7. Review Portfolio to track your progress.
  8. Need help? Use the Contact page for support.
  9. diff --git a/app/polymarket/PolymarketClientPage.tsx b/app/polymarket/PolymarketClientPage.tsx index 6ef28633..8d16f7cb 100644 --- a/app/polymarket/PolymarketClientPage.tsx +++ b/app/polymarket/PolymarketClientPage.tsx @@ -1,36 +1,11 @@ "use client"; - -import dynamic from "next/dynamic"; - -// Load the Polymarket terminal as a client-side only component to avoid SSR issues -// with browser-only APIs (JsonRpcProvider, fetch from Polymarket CLOB API, localStorage, etc.) -const PolymarketTerminal = dynamic( - () => import("@/components/trading/PolymarketTerminal"), - { - ssr: false, - loading: () => ( -
    -
    -
    - TRADEHAX GPT -
    -
    Loading Polymarket Terminal…
    -
    -
    - ), - } -); +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; export default function PolymarketClientPage() { - return ; + const router = useRouter(); + useEffect(() => { + router.replace("/crypto-project"); + }, [router]); + return null; } diff --git a/app/polymarket/page.tsx b/app/polymarket/page.tsx index 168a75d5..6a80e84c 100644 --- a/app/polymarket/page.tsx +++ b/app/polymarket/page.tsx @@ -1,24 +1,5 @@ -import { createPageMetadata } from "@/lib/seo"; -import PolymarketClientPage from "./PolymarketClientPage"; - -export const metadata = createPageMetadata({ - title: "TradeHax Polymarket Terminal - Prediction Market Trading", - description: - "Live Polymarket trading terminal with Fibonacci, Full Kelly, Bayesian, Monte Carlo, and multi-timeframe analysis. Predict market outcomes with AI-powered signals.", - path: "/polymarket", - keywords: [ - "polymarket", - "prediction markets", - "trading bot", - "kelly criterion", - "fibonacci trading", - "bayesian analysis", - "monte carlo", - "defi trading", - "polygon wallet", - ], -}); +import { redirect } from "next/navigation"; export default function PolymarketPage() { - return ; + redirect("/crypto-project"); } diff --git a/app/sitemap.ts b/app/sitemap.ts index b541e2d4..9df6d196 100644 --- a/app/sitemap.ts +++ b/app/sitemap.ts @@ -21,17 +21,11 @@ export default function sitemap(): MetadataRoute.Sitemap { priority: 0.95, }, { - url: `${baseUrl}/beginner-ai-crypto-trading-assistant`, + url: `${baseUrl}/crypto-project`, lastModified: now, changeFrequency: 'weekly', priority: 0.9, }, - { - url: `${baseUrl}/web3-token-roadmap-consulting`, - lastModified: now, - changeFrequency: 'weekly', - priority: 0.89, - }, { url: `${baseUrl}/ai-powered-guitar-lessons`, lastModified: now, @@ -44,12 +38,6 @@ export default function sitemap(): MetadataRoute.Sitemap { changeFrequency: 'daily', priority: 0.92, }, - { - url: `${baseUrl}/trading`, - lastModified: now, - changeFrequency: 'daily', - priority: 0.9, - }, { url: `${baseUrl}/services`, lastModified: now, diff --git a/app/trading/backtest/page.tsx b/app/trading/backtest/page.tsx index 2e8d6bec..1fae9779 100644 --- a/app/trading/backtest/page.tsx +++ b/app/trading/backtest/page.tsx @@ -1,134 +1,5 @@ -"use client"; +import { redirect } from "next/navigation"; -/** - * /trading/backtest — Backtesting Sandbox page. - */ - -import { BacktestForm } from "@/components/trading/backtest/BacktestForm"; -import { BacktestResults } from "@/components/trading/backtest/BacktestResults"; -import type { BacktestConfig, BacktestResult } from "@/types/trading"; -import { useState } from "react"; -import useSWR from "swr"; - -type PhaseStatusResponse = { - ok: boolean; - status?: { - complete?: boolean; - confidence?: number; - }; -}; - -const fetcher = async (url: string): Promise => { - const response = await fetch(url, { cache: "no-store" }); - if (!response.ok) { - throw new Error(`Failed to fetch ${url}`); - } - return (await response.json()) as PhaseStatusResponse; -}; - -// ─── Skeleton loader ────────────────────────────────────────────────────────── - -function Skeleton() { - return ( -
    -
    - {Array.from({ length: 8 }).map((_, i) => ( -
    - ))} -
    -
    -
    -
    - ); -} - -// ─── Page ───────────────────────────────────────────────────────────────────── - -export default function BacktestPage() { - const { data: phaseStatus } = useSWR("/api/phase03/status", fetcher, { - refreshInterval: 30_000, - dedupingInterval: 10_000, - revalidateOnFocus: false, - }); - const [result, setResult] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - - async function handleRun(config: BacktestConfig) { - setLoading(true); - setError(null); - - try { - const res = await fetch("/api/backtest/run", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(config), - }); - - if (!res.ok) { - const body = await res.json().catch(() => ({})); - throw new Error((body as { error?: string }).error ?? `HTTP ${res.status}`); - } - - const json = await res.json() as { ok: boolean; data: BacktestResult }; - setResult(json.data); - } catch (err) { - setError(err instanceof Error ? err.message : "Backtest failed."); - } finally { - setLoading(false); - } - } - - return ( -
    - {/* Header */} -
    -

    Backtesting Sandbox

    -

    - Simulate your trading strategy against historical price data. Powered by RSI-based signal generation. -

    - {phaseStatus?.ok && ( -

    - System status: {phaseStatus.status?.complete ? "ready" : "warming"} -

    - )} -
    - - {/* Config form */} -
    -

    Configuration

    - -
    - - {/* Error state */} - {error && ( -
    - {error} -
    - )} - - {/* Results */} - {loading && } - {!loading && result && ( -
    -
    -

    - Results — {result.config.symbol} / {result.config.timeRange} -

    - - Completed {new Date(result.completedAt).toLocaleTimeString()} - -
    - -
    - )} - - {!loading && !result && !error && ( -
    - 📈 -

    Configure and run a backtest to see results here.

    -
    - )} -
    - ); +export default function Page() { + redirect("/crypto-project"); } diff --git a/app/trading/page.tsx b/app/trading/page.tsx index 7a8288b6..1da16cda 100644 --- a/app/trading/page.tsx +++ b/app/trading/page.tsx @@ -1,140 +1,5 @@ -import { TradehaxBotDashboard } from "@/components/trading/TradehaxBotDashboard"; -import { createPageMetadata } from "@/lib/seo"; -import { - Activity, - BarChart3, - Bot, - BrainCircuit, - FlaskConical, - LayoutDashboard, - TrendingUp, - type LucideIcon, -} from "lucide-react"; -import Link from "next/link"; - -export const metadata = createPageMetadata({ - title: "TradeHax AI Trading - Automated Strategies, Sentiment & Portfolio", - description: - "Full-stack AI trading platform: manage bots, build strategies, analyze sentiment, track your portfolio, run backtests, and get full XAI signal explanations.", - path: "/trading", - keywords: [ - "automated trading", - "crypto bots", - "stock bots", - "trading dashboard", - "portfolio tracker", - "sentiment engine", - "backtesting", - "AI explainability", - ], -}); - -// ISR for mostly-static trading hub content to keep TTFB low under traffic. -export const revalidate = 300; - -// ─── Feature cards ──────────────────────────────────────────────────────────── - -interface FeatureCard { - href: string; - icon: LucideIcon; - title: string; - description: string; - badge?: string; -} - -const FEATURES: FeatureCard[] = [ - { - href: "/polymarket", - icon: TrendingUp, - title: "Polymarket Terminal", - description: "Live prediction market trading with Fibonacci, Full Kelly, Bayesian, Monte Carlo, and multi-timeframe analysis. Polygon wallet support.", - badge: "Live", - }, - { - href: "/trading/portfolio", - icon: LayoutDashboard, - title: "Portfolio Dashboard", - description: "Connect exchanges and monitor your full multi-asset portfolio with real-time value, allocation charts, and AI rebalance suggestions.", - badge: "Live", - }, - { - href: "/trading/sentiment", - icon: Activity, - title: "Sentiment Engine", - description: "Fear & Greed analysis aggregated from social media, news, and on-chain signals. Watch the market mood shift in real time.", - badge: "Live", - }, - { - href: "/trading/strategy-builder", - icon: BrainCircuit, - title: "Strategy Builder", - description: "Drag-and-drop no-code strategy canvas. Combine indicators, filters, and actions, then export or push directly to a bot.", - }, - { - href: "/trading/backtest", - icon: FlaskConical, - title: "Backtesting Sandbox", - description: "Run your strategies against historical data. Analyze the equity curve, win rate, max drawdown, and monthly returns.", - }, - { - href: "/trading/xai", - icon: BarChart3, - title: "AI Explainability", - description: "See exactly why the AI generated each signal. Factor weights, confidence breakdown, risk assessment, and similar past signals.", - }, -]; +import { redirect } from "next/navigation"; export default function TradingPage() { - return ( -
    - - -
    - {/* Hub header */} -
    -

    - TradeHax AI Trading Platform -

    -

    - Five production-grade AI tools working together — from sentiment analysis to live portfolio tracking, strategy building, backtesting, and full signal explainability. -

    -
    - - {/* Feature navigation grid */} -
    - {FEATURES.map(({ href, icon: Icon, title, description, badge }) => ( - - {badge && ( - - {badge} - - )} -
    - -
    -

    - {title} -

    -

    - {description} -

    - - ))} -
    - - {/* Bot dashboard */} -
    - -

    Bot Dashboard

    -
    - -
    - -
    - ); + redirect("/crypto-project"); } - diff --git a/app/trading/portfolio/page.tsx b/app/trading/portfolio/page.tsx index 7e9c3392..1fae9779 100644 --- a/app/trading/portfolio/page.tsx +++ b/app/trading/portfolio/page.tsx @@ -1,40 +1,5 @@ -import { PortfolioOverview } from "@/components/trading/PortfolioOverview"; -import { createPageMetadata } from "@/lib/seo"; +import { redirect } from "next/navigation"; -export const metadata = createPageMetadata({ - title: "Portfolio Dashboard - TradeHax AI", - description: - "Track your multi-exchange portfolio in real time. Monitor asset allocation, 24h performance, and receive AI-powered rebalance suggestions.", - path: "/trading/portfolio", - keywords: [ - "portfolio dashboard", - "crypto portfolio", - "asset allocation", - "rebalance suggestions", - "exchange tracker", - ], -}); - -export default function TradingPortfolioPage() { - return ( -
    - - -
    - {/* Page header */} -
    -

    - Portfolio Dashboard -

    -

    - Connect your exchanges and track your full portfolio in one place with AI-powered rebalance suggestions. -

    -
    - - -
    - -
    - ); +export default function Page() { + redirect("/crypto-project"); } - diff --git a/app/trading/sentiment/page.tsx b/app/trading/sentiment/page.tsx index d540fdb0..1fae9779 100644 --- a/app/trading/sentiment/page.tsx +++ b/app/trading/sentiment/page.tsx @@ -1,140 +1,5 @@ -"use client"; +import { redirect } from "next/navigation"; -/** - * /trading/sentiment — Market Sentiment Engine page. - * Displays the Fear & Greed gauge, per-asset scores, and live event feed. - */ - -import { useState, useCallback } from "react"; -import { RefreshCw } from "lucide-react"; -import { SentimentGauge } from "@/components/trading/SentimentGauge"; -import { SentimentFeed } from "@/components/trading/SentimentFeed"; -import { useSentimentStream } from "@/hooks/use-sentiment-stream"; - -// ─── Asset tabs ─────────────────────────────────────────────────────────────── - -const DEFAULT_SYMBOLS = ["BTC", "ETH", "SOL"] as const; - -// ─── Skeleton ───────────────────────────────────────────────────────────────── - -function GaugeSkeleton() { - return ( -
    -
    -
    -
    - {[0, 1, 2].map((i) => ( -
    - ))} -
    -
    - ); -} - -// ─── Page ───────────────────────────────────────────────────────────────────── - -export default function SentimentPage() { - const [symbols] = useState(DEFAULT_SYMBOLS.join(",")); - const { snapshot, loading, error, refresh, lastUpdated } = useSentimentStream({ - symbols, - pollIntervalMs: 60_000, - }); - - const handleRefresh = useCallback(() => refresh(), [refresh]); - - return ( -
    - - -
    - {/* Page header */} -
    -
    -

    - Sentiment Engine -

    -

    - Real-time Fear & Greed analysis aggregated from social, news, and on-chain signals. -

    -
    - -
    - {lastUpdated && ( - - Updated {lastUpdated.toLocaleTimeString()} - - )} - -
    -
    - - {/* Error state */} - {error && ( -
    - {error} — displaying last known data. -
    - )} - - {/* Market gauge + per-asset gauges */} -
    -

    Overall Market Sentiment

    - - {loading && !snapshot ? ( -
    - {[0, 1, 2, 3].map((i) => )} -
    - ) : snapshot ? ( -
    - {/* Market-wide gauge */} -
    -

    - All Markets -

    - -
    - - {/* Per-asset gauges */} - {snapshot.assets.map((asset) => ( -
    -

    - {asset.symbol} -

    - -
    - ))} -
    - ) : null} -
    - - {/* Live event feed */} -
    -

    Live Signal Feed

    - - {loading && !snapshot ? ( -
    - {[0, 1, 2, 3, 4].map((i) => ( -
    - ))} -
    - ) : snapshot ? ( - - ) : null} -
    -
    - -
    - ); +export default function Page() { + redirect("/crypto-project"); } - diff --git a/app/trading/strategy-builder/page.tsx b/app/trading/strategy-builder/page.tsx index f56178a2..1fae9779 100644 --- a/app/trading/strategy-builder/page.tsx +++ b/app/trading/strategy-builder/page.tsx @@ -1,272 +1,5 @@ -"use client"; +import { redirect } from "next/navigation"; -/** - * /trading/strategy-builder — Visual No-Code Strategy Builder page. - */ - -import { useState, useCallback } from "react"; -import { nanoid } from "@/lib/utils"; -import { StrategyCanvas } from "@/components/trading/strategy-builder/StrategyCanvas"; -import { StrategyToolbar, BlockTemplate, BLOCK_TEMPLATES } from "@/components/trading/strategy-builder/StrategyToolbar"; -import { StrategyPreview } from "@/components/trading/strategy-builder/StrategyPreview"; -import { serializeStrategy, deserializeStrategy } from "@/lib/trading/strategy-serializer"; -import type { StrategyBlock, StrategyDefinition } from "@/types/trading"; -import { Download, Upload, Trash2, Copy } from "lucide-react"; - -// ─── Template Presets ───────────────────────────────────────────────────────── - -const PRESET_NAMES = ["Conservative DCA", "Momentum Rider", "Grid Scalper", "Sentiment Surfer"] as const; -type PresetName = typeof PRESET_NAMES[number]; - -function getBlocksByTypes(types: StrategyBlock["type"][]): StrategyBlock[] { - return types.map((t, i) => { - const tmpl = BLOCK_TEMPLATES.find((b) => b.type === t)!; - return { - id: nanoid(), - type: tmpl.type, - category: tmpl.category, - label: tmpl.label, - description: tmpl.description, - params: tmpl.defaultParams.map((p) => ({ ...p })), - position: i, - enabled: true, - isPremium: tmpl.isPremium, - }; - }); -} - -const PRESETS: Record> = { - "Conservative DCA": { - name: "Conservative DCA", - description: "Dollar-cost average into dips using RSI oversold signals.", - blocks: getBlocksByTypes(["rsi_threshold", "stop_loss", "take_profit", "dca_increment", "buy"]), - tags: ["dca", "conservative"], - }, - "Momentum Rider": { - name: "Momentum Rider", - description: "Ride breakouts with MACD and volume confirmation.", - blocks: getBlocksByTypes(["macd_signal", "volume_spike", "trend_filter", "buy", "trailing_stop"]), - tags: ["momentum", "breakout"], - }, - "Grid Scalper": { - name: "Grid Scalper", - description: "Scale in/out with limit orders inside a price range.", - blocks: getBlocksByTypes(["price_cross", "limit_order", "take_profit", "stop_loss"]), - tags: ["grid", "scalping"], - }, - "Sentiment Surfer": { - name: "Sentiment Surfer", - description: "Trade based on Fear & Greed index transitions.", - blocks: getBlocksByTypes(["sentiment_threshold", "buy", "take_profit", "stop_loss"]), - tags: ["sentiment", "contrarian"], - }, -}; - -function buildPreset(name: PresetName): StrategyDefinition { - const now = new Date().toISOString(); - const template = PRESETS[name]; - const blocks = template.blocks.map((b, i) => ({ - ...b, - id: nanoid(), - position: i, - params: b.params.map((p) => ({ ...p })), - })); - return { ...template, id: nanoid(), createdAt: now, updatedAt: now, blocks }; -} - -function emptyStrategy(): StrategyDefinition { - const now = new Date().toISOString(); - return { - id: nanoid(), - name: "My Strategy", - description: "", - blocks: [], - tags: [], - createdAt: now, - updatedAt: now, - }; -} - -// ─── Page ───────────────────────────────────────────────────────────────────── - -export default function StrategyBuilderPage() { - const [strategy, setStrategy] = useState(emptyStrategy); - const [isPremium] = useState(false); // wire to your monetization hook - const [exportMsg, setExportMsg] = useState(null); - - const updateStrategy = useCallback((changes: Partial) => { - setStrategy((prev) => ({ ...prev, ...changes, updatedAt: new Date().toISOString() })); - }, []); - - // ── Add block ──────────────────────────────────────────────────────────── - - const addBlock = useCallback( - (tmpl: BlockTemplate) => { - if (tmpl.isPremium && !isPremium) return; - const newBlock: StrategyBlock = { - id: nanoid(), - type: tmpl.type, - category: tmpl.category, - label: tmpl.label, - description: tmpl.description, - params: tmpl.defaultParams.map((p) => ({ ...p })), - position: strategy.blocks.length, - enabled: true, - isPremium: tmpl.isPremium, - }; - updateStrategy({ blocks: [...strategy.blocks, newBlock] }); - }, - [isPremium, strategy.blocks, updateStrategy], - ); - - // ── Export / Import ────────────────────────────────────────────────────── - - function handleExport() { - const json = serializeStrategy(strategy); - const blob = new Blob([json], { type: "application/json" }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - const safeName = strategy.name.replace(/[^a-zA-Z0-9-]/gi, "-").toLowerCase(); - a.download = `${safeName}.json`; - a.click(); - URL.revokeObjectURL(url); - setExportMsg("Strategy exported!"); - setTimeout(() => setExportMsg(null), 2000); - } - - function handleImport() { - const input = document.createElement("input"); - input.type = "file"; - input.accept = ".json"; - input.onchange = (e) => { - const file = (e.target as HTMLInputElement).files?.[0]; - if (!file) return; - const reader = new FileReader(); - reader.onload = (ev) => { - const parsed = deserializeStrategy(String(ev.target?.result ?? "")); - if (parsed) { - setStrategy(parsed); - setExportMsg("Strategy imported!"); - } else { - setExportMsg("Invalid strategy file."); - } - setTimeout(() => setExportMsg(null), 2500); - }; - reader.readAsText(file); - }; - input.click(); - } - - function handleCopy() { - navigator.clipboard.writeText(serializeStrategy(strategy)).then(() => { - setExportMsg("Copied to clipboard!"); - setTimeout(() => setExportMsg(null), 2000); - }); - } - - return ( -
    - {/* ── Header ─────────────────────────────────────────────────────────── */} -
    -
    -

    Visual Strategy Builder

    -

    Build no-code trading strategies with drag-and-drop blocks.

    -
    - -
    - {/* Preset picker */} - - - - - - - - - - - {exportMsg && ( - {exportMsg} - )} -
    -
    - - {/* Strategy name input */} -
    - updateStrategy({ name: e.target.value })} - className="flex-1 max-w-xs text-sm rounded-lg border border-border bg-muted/30 px-3 py-1.5 text-foreground focus:outline-none focus:ring-1 focus:ring-ring" - aria-label="Strategy name" - placeholder="Strategy name" - /> - updateStrategy({ description: e.target.value })} - className="flex-1 text-sm rounded-lg border border-border bg-muted/30 px-3 py-1.5 text-foreground focus:outline-none focus:ring-1 focus:ring-ring" - aria-label="Strategy description" - placeholder="Optional description…" - /> -
    - - {/* ── Layout: toolbar | canvas | preview ─────────────────────────────── */} -
    - {/* Block palette */} - - - {/* Canvas */} -
    - updateStrategy({ blocks })} - /> -
    - - {/* Preview panel */} - -
    -
    - ); +export default function Page() { + redirect("/crypto-project"); } diff --git a/app/trading/xai/page.tsx b/app/trading/xai/page.tsx index e51567db..1fae9779 100644 --- a/app/trading/xai/page.tsx +++ b/app/trading/xai/page.tsx @@ -1,186 +1,5 @@ -"use client"; +import { redirect } from "next/navigation"; -/** - * /trading/xai — AI Explainability (XAI) Panel page. - * Let users enter a signal or pick a preset to see a full AI explanation. - */ - -import { useState, useCallback } from "react"; -import { Sparkles, ChevronDown } from "lucide-react"; -import { SignalExplainer } from "@/components/trading/SignalExplainer"; -import type { SignalExplanation, TradingSignal } from "@/types/trading"; - -// ─── Preset signals ─────────────────────────────────────────────────────────── - -interface PresetSignal { - label: string; - signal: Omit; -} - -const PRESETS: PresetSignal[] = [ - { - label: "BTC Strong Buy", - signal: { - symbol: "BTC", - action: "buy", - confidence: 0.87, - price: 68500, - targetPrice: 74000, - stopLoss: 65000, - timeframe: "4h", - source: "ai-engine", - tags: ["momentum", "on-chain"], - }, - }, - { - label: "ETH Sell Signal", - signal: { - symbol: "ETH", - action: "sell", - confidence: 0.72, - price: 3400, - targetPrice: 3100, - stopLoss: 3600, - timeframe: "1d", - source: "ai-engine", - tags: ["overbought", "resistance"], - }, - }, - { - label: "SOL Hold", - signal: { - symbol: "SOL", - action: "hold", - confidence: 0.55, - price: 145, - targetPrice: 160, - stopLoss: 130, - timeframe: "1h", - source: "ai-engine", - tags: ["neutral", "consolidation"], - }, - }, -]; - -// ─── Skeleton ───────────────────────────────────────────────────────────────── - -function ExplainSkeleton() { - return ( -
    -
    -
    - {[0, 1, 2, 3].map((i) => ( -
    - ))} -
    -
    -
    - ); -} - -// ─── Page ───────────────────────────────────────────────────────────────────── - -export default function XAIPage() { - const [explanation, setExplanation] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [activePreset, setActivePreset] = useState(null); - - const fetchExplanation = useCallback(async (preset: PresetSignal) => { - setActivePreset(preset.label); - setLoading(true); - setError(null); - - try { - const res = await fetch("/api/signals/explain", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - ...preset.signal, - id: `preset-${Date.now()}`, - generatedAt: new Date().toISOString(), - }), - }); - - const json = await res.json(); - if (!res.ok || !json.ok) { - throw new Error(json.error ?? "Failed to fetch explanation."); - } - setExplanation(json.data as SignalExplanation); - } catch (err) { - setError(err instanceof Error ? err.message : "Unexpected error."); - } finally { - setLoading(false); - } - }, []); - - return ( -
    - - -
    - {/* Page header */} -
    -

    - AI Explainability Panel -

    -

    - Understand exactly why the AI generated each signal — factor weights, risk levels, and historical accuracy in full detail. -

    -
    - - {/* Preset selector */} -
    -

    - - Choose a sample signal to explain -

    -
    - {PRESETS.map((preset) => ( - - ))} -
    -
    - - {/* Error */} - {error && ( -
    - {error} -
    - )} - - {/* Results */} - {loading && } - - {!loading && explanation && ( - - )} - - {!loading && !explanation && !error && ( -
    - -

    - Select a sample signal above to see the full AI explanation. -

    -
    - )} -
    - -
    - ); +export default function Page() { + redirect("/crypto-project"); } - diff --git a/app/web3-token-roadmap-consulting/page.tsx b/app/web3-token-roadmap-consulting/page.tsx index 691f5849..42b092e3 100644 --- a/app/web3-token-roadmap-consulting/page.tsx +++ b/app/web3-token-roadmap-consulting/page.tsx @@ -1,86 +1,5 @@ -import { TrackedCtaLink } from "@/components/monetization/TrackedCtaLink"; -import { createPageMetadata } from "@/lib/seo"; -import Script from "next/script"; +import { redirect } from "next/navigation"; -export const metadata = createPageMetadata({ - title: "Digital Product Roadmap Consulting | TradeHax AI", - description: - "Plan product utility phases, growth milestones, and measurable rollout KPIs with a practical consulting roadmap for your digital business.", - path: "/web3-token-roadmap-consulting", - keywords: [ - "digital product roadmap consulting", - "product strategy consulting", - "app development roadmap", - "digital business strategy", - ], -}); - -const serviceJsonLd = { - "@context": "https://schema.org", - "@type": "Service", - name: "Digital Product Roadmap Consulting", - provider: { - "@type": "Organization", - name: "TradeHax AI", - }, - serviceType: "Product Strategy Consulting", - areaServed: "United States", - description: - "Product utility planning, phased rollout strategy, growth readiness, and KPI mapping for sustainable digital business growth.", -}; - -export default function ProductRoadmapConsultingPage() { - return ( -
    - - - -
    -
    -

    Product Advisory

    -

    Digital Product Roadmap Consulting

    -

    - Build a forward-leaning roadmap with practical phases: onboarding, feature utility, retention loops, and growth milestones. - We focus on measurable outcomes and real business value. -

    - -
    - {[ - "Phase 1: onboarding + user experience", - "Phase 2: feature loops + engagement", - "Phase 3: growth + accountability", - ].map((item) => ( -
    - {item} -
    - ))} -
    - -
    - - Book a Consultation - - - View All Services - -
    -
    -
    -
    - ); +export default function WebTokenRoadmapPage() { + redirect("/crypto-project"); } - diff --git a/components/intelligence/CryptoFlowPanel.tsx b/components/intelligence/CryptoFlowPanel.tsx deleted file mode 100644 index 83ee839c..00000000 --- a/components/intelligence/CryptoFlowPanel.tsx +++ /dev/null @@ -1,163 +0,0 @@ -"use client"; - -import { CopilotPanel } from "@/components/intelligence/CopilotPanel"; -import { useIntelligenceFeed } from "@/components/intelligence/useIntelligenceFeed"; -import { formatDateTime, formatPct, formatUsd } from "@/lib/intelligence/format"; -import { CryptoFlowTrade, SUPPORTED_CRYPTO_CHAINS } from "@/lib/intelligence/types"; -import { useMemo, useState } from "react"; - -function formatChainLabel(chain: string) { - if (chain === "bsc") { - return "BSC"; - } - return chain - .split("-") - .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) - .join(" "); -} - -export function CryptoFlowPanel() { - const [pair, setPair] = useState(""); - const [chain, setChain] = useState(""); - const [side, setSide] = useState(""); - const [minNotional, setMinNotional] = useState(""); - const [minConfidence, setMinConfidence] = useState(""); - - const query = useMemo(() => { - const params = new URLSearchParams(); - if (pair.trim()) params.set("pair", pair.trim().toUpperCase()); - if (chain) params.set("chain", chain); - if (side) params.set("side", side); - if (minNotional) params.set("minNotional", minNotional); - if (minConfidence) params.set("minConfidence", minConfidence); - return params.toString(); - }, [pair, chain, side, minNotional, minConfidence]); - - const { items, count, generatedAt, loading, error, reload } = useIntelligenceFeed( - "/api/intelligence/crypto-flow", - query, - ); - const context = useMemo(() => JSON.stringify(items.slice(0, 6)), [items]); - - return ( -
    -
    -
    - - - - - -
    - -
    - -

    - {loading ? "Loading..." : `${count} rows`} {generatedAt ? `• ${formatDateTime(generatedAt)}` : ""} -

    -
    - - {error ? ( -

    - {error} -

    - ) : null} - -
    - - - - - - - - - - - - - - {items.map((item) => ( - - - - - - - - - - ))} - {items.length === 0 && !loading ? ( - - - - ) : null} - -
    PairChainSideNotionalConfidenceExchangeTriggered
    {item.pair}{item.chain}{item.side}{formatUsd(item.notionalUsd)}{formatPct(item.confidence)}{item.exchange}{formatDateTime(item.triggeredAt)}
    - No matching crypto signals. Relax filters and retry. -
    -
    -
    - - context} - /> -
    - ); -} diff --git a/components/trading/AssetAllocationChart.tsx b/components/trading/AssetAllocationChart.tsx deleted file mode 100644 index 5cfd746a..00000000 --- a/components/trading/AssetAllocationChart.tsx +++ /dev/null @@ -1,129 +0,0 @@ -"use client"; - -/** - * AssetAllocationChart — SVG donut chart for portfolio allocation visualization. - */ - -import type { PortfolioAsset } from "@/types/trading"; - -interface AssetAllocationChartProps { - assets: PortfolioAsset[]; - size?: number; -} - -/** Convert a slice to an SVG arc path on a unit circle. */ -function slicePath( - cx: number, - cy: number, - r: number, - startAngle: number, - endAngle: number, - holeRadius: number, -): string { - const toRad = (deg: number) => (deg * Math.PI) / 180; - const cos = Math.cos; - const sin = Math.sin; - - const x1 = cx + r * cos(toRad(startAngle - 90)); - const y1 = cy + r * sin(toRad(startAngle - 90)); - const x2 = cx + r * cos(toRad(endAngle - 90)); - const y2 = cy + r * sin(toRad(endAngle - 90)); - - const hx1 = cx + holeRadius * cos(toRad(startAngle - 90)); - const hy1 = cy + holeRadius * sin(toRad(startAngle - 90)); - const hx2 = cx + holeRadius * cos(toRad(endAngle - 90)); - const hy2 = cy + holeRadius * sin(toRad(endAngle - 90)); - - const largeArc = endAngle - startAngle > 180 ? 1 : 0; - - return [ - `M ${x1} ${y1}`, - `A ${r} ${r} 0 ${largeArc} 1 ${x2} ${y2}`, - `L ${hx2} ${hy2}`, - `A ${holeRadius} ${holeRadius} 0 ${largeArc} 0 ${hx1} ${hy1}`, - "Z", - ].join(" "); -} - -/** - * Donut chart showing portfolio asset allocation percentages. - */ -export function AssetAllocationChart({ assets, size = 200 }: AssetAllocationChartProps) { - if (assets.length === 0) { - return ( -
    - No data -
    - ); - } - - const cx = size / 2; - const cy = size / 2; - const r = size * 0.42; - const holeRadius = r * 0.55; - - let startAngle = 0; - const slices = assets.map((asset) => { - const sweep = (asset.allocationPct / 100) * 360; - const path = slicePath(cx, cy, r, startAngle, startAngle + sweep, holeRadius); - const midAngle = startAngle + sweep / 2; - const labelR = r * 1.25; - const toRad = (deg: number) => (deg * Math.PI) / 180; - const lx = cx + labelR * Math.cos(toRad(midAngle - 90)); - const ly = cy + labelR * Math.sin(toRad(midAngle - 90)); - startAngle += sweep; - return { asset, path, lx, ly }; - }); - - return ( - - {slices.map(({ asset, path }) => ( - - {`${asset.symbol}: ${asset.allocationPct.toFixed(1)}%`} - - ))} - - {/* Center total label */} - - Allocation - - - {assets.length} assets - - - {/* Percentage labels for slices ≥ 8% */} - {slices.map(({ asset, lx, ly }) => - asset.allocationPct >= 8 ? ( - - {asset.symbol} - - ) : null, - )} - - ); -} diff --git a/components/trading/ConfidenceMeter.tsx b/components/trading/ConfidenceMeter.tsx deleted file mode 100644 index 6e541028..00000000 --- a/components/trading/ConfidenceMeter.tsx +++ /dev/null @@ -1,59 +0,0 @@ -"use client"; - -/** - * ConfidenceMeter — visual 0-100% confidence indicator with color coding. - */ - -import { motion } from "framer-motion"; - -interface ConfidenceMeterProps { - /** Value from 0 to 1. */ - confidence: number; - size?: "sm" | "md" | "lg"; - showLabel?: boolean; -} - -function confidenceColor(confidence: number): string { - if (confidence >= 0.75) return "bg-green-500"; - if (confidence >= 0.5) return "bg-yellow-500"; - return "bg-red-500"; -} - -function confidenceLabel(confidence: number): string { - if (confidence >= 0.75) return "High"; - if (confidence >= 0.5) return "Medium"; - return "Low"; -} - -/** - * Horizontal progress-bar style confidence meter. - */ -export function ConfidenceMeter({ confidence, size = "md", showLabel = true }: ConfidenceMeterProps) { - const pct = Math.round(Math.max(0, Math.min(1, confidence)) * 100); - const colorClass = confidenceColor(confidence); - const label = confidenceLabel(confidence); - - const heightClass = size === "sm" ? "h-1.5" : size === "lg" ? "h-4" : "h-2.5"; - const textClass = size === "sm" ? "text-xs" : size === "lg" ? "text-base" : "text-sm"; - - return ( -
    - {showLabel && ( -
    - Confidence - = 0.75 ? "text-green-400" : confidence >= 0.5 ? "text-yellow-400" : "text-red-400"}`}> - {pct}% — {label} - -
    - )} -
    - -
    -
    - ); -} diff --git a/components/trading/ExchangeConnector.tsx b/components/trading/ExchangeConnector.tsx deleted file mode 100644 index d2d6118d..00000000 --- a/components/trading/ExchangeConnector.tsx +++ /dev/null @@ -1,198 +0,0 @@ -"use client"; - -/** - * ExchangeConnector — UI for adding/managing exchange API key connections. - */ - -import { useState } from "react"; -import { Plus, Trash2, RefreshCw, CheckCircle, XCircle, Loader2 } from "lucide-react"; -import { nanoid } from "@/lib/utils"; -import type { ExchangeConnection, SupportedExchange } from "@/types/trading"; - -const EXCHANGE_OPTIONS: { value: SupportedExchange; label: string }[] = [ - { value: "binance", label: "Binance" }, - { value: "coinbase", label: "Coinbase" }, - { value: "kraken", label: "Kraken" }, - { value: "manual", label: "Manual (CSV)" }, -]; - -interface ExchangeConnectorProps { - connections: ExchangeConnection[]; - onChange: (connections: ExchangeConnection[]) => void; -} - -/** - * Manages exchange API connections with masked key display and test-connection flow. - */ -export function ExchangeConnector({ connections, onChange }: ExchangeConnectorProps) { - const [adding, setAdding] = useState(false); - const [newExchange, setNewExchange] = useState("binance"); - const [newLabel, setNewLabel] = useState(""); - const [newKey, setNewKey] = useState(""); - const [testingId, setTestingId] = useState(null); - - function handleAdd() { - if (!newKey.trim()) return; - const conn: ExchangeConnection = { - id: nanoid(), - exchange: newExchange, - label: newLabel || (EXCHANGE_OPTIONS.find((e) => e.value === newExchange)?.label ?? newExchange), - apiKey: newKey.trim(), - status: "connected", - lastSynced: new Date().toISOString(), - }; - onChange([...connections, conn]); - setNewKey(""); - setNewLabel(""); - setAdding(false); - } - - function handleRemove(id: string) { - onChange(connections.filter((c) => c.id !== id)); - } - - async function handleTest(id: string) { - setTestingId(id); - // Simulate connection test - await new Promise((r) => setTimeout(r, 1200)); - onChange( - connections.map((c) => - c.id === id ? { ...c, status: "connected", lastSynced: new Date().toISOString() } : c, - ), - ); - setTestingId(null); - } - - const maskKey = (key: string) => - key.length > 4 ? `${key.slice(0, 4)}${"•".repeat(Math.min(key.length - 4, 16))}` : "••••"; - - return ( -
    - {/* Existing connections */} - {connections.map((conn) => ( -
    -
    -
    - {conn.label} - {conn.exchange} -
    -
    {maskKey(conn.apiKey)}
    -
    - - {/* Status */} -
    - {conn.status === "connected" ? ( - - ) : conn.status === "error" ? ( - - ) : ( - - )} - {conn.status} -
    - - {/* Test button */} - - - {/* Remove */} - -
    - ))} - - {/* Add form */} - {adding ? ( -
    -
    -
    - - -
    -
    - - setNewLabel(e.target.value)} - placeholder="My Binance" - className="w-full text-xs rounded border border-border bg-background px-2 py-1.5 text-foreground focus:outline-none focus:ring-1 focus:ring-ring" - aria-label="Connection label" - /> -
    -
    -
    - - setNewKey(e.target.value)} - placeholder="Paste your read-only API key…" - className="w-full text-xs rounded border border-border bg-background px-2 py-1.5 text-foreground font-mono focus:outline-none focus:ring-1 focus:ring-ring" - aria-label="API key" - autoComplete="off" - /> -

    - Use read-only API keys. Keys are stored client-side only and never logged. -

    -
    -
    - - -
    -
    - ) : ( - - )} -
    - ); -} diff --git a/components/trading/FactorBreakdown.tsx b/components/trading/FactorBreakdown.tsx deleted file mode 100644 index 0e24dbbb..00000000 --- a/components/trading/FactorBreakdown.tsx +++ /dev/null @@ -1,55 +0,0 @@ -"use client"; - -/** - * FactorBreakdown — animated horizontal bar chart of contributing signal factors. - */ - -import { motion } from "framer-motion"; -import type { SignalFactor } from "@/types/trading"; - -const DIRECTION_COLOR: Record = { - bullish: "bg-green-500", - bearish: "bg-red-500", - neutral: "bg-yellow-500", -}; - -interface FactorBreakdownProps { - factors: SignalFactor[]; -} - -/** - * Renders a sorted list of signal factors as animated horizontal bars. - */ -export function FactorBreakdown({ factors }: FactorBreakdownProps) { - const sorted = [...factors].sort((a, b) => b.weight - a.weight); - - return ( -
    - {sorted.map((factor, i) => { - const pct = Math.round(factor.weight * 100); - const barColor = DIRECTION_COLOR[factor.direction]; - return ( -
    -
    - {factor.name} -
    - {factor.value} - - {pct}% - -
    -
    -
    - -
    -
    - ); - })} -
    - ); -} diff --git a/components/trading/PolymarketTerminal.jsx b/components/trading/PolymarketTerminal.jsx deleted file mode 100644 index c0d8c2d9..00000000 --- a/components/trading/PolymarketTerminal.jsx +++ /dev/null @@ -1,1494 +0,0 @@ -"use client"; - -import { useState, useEffect, useRef, useMemo, useCallback } from "react"; -import { JsonRpcProvider, formatEther, getAddress } from "ethers"; - -// ╔══════════════════════════════════════════════════════════════════════════╗ -// ║ TRADEHAX GPT ◆ APEX EDITION ◆ tradehax.net ║ -// ║ The Premier Prediction Market Intelligence Engine ║ -// ║ Fibonacci · Full Kelly · Bayesian · Monte Carlo · Multi-TF ║ -// ║ Gabagool Arb · Smart Ape · Bollinger · RSI · MACD · Whale Radar ║ -// ╚══════════════════════════════════════════════════════════════════════════╝ - -// ─── MATHEMATICAL CONSTANTS ─────────────────────────────────────────────────── -const PHI = 1.6180339887; -const PHI_INV = 0.6180339887; -const FIB_R = [0.0, 0.236, 0.382, 0.500, 0.618, 0.786, 1.000]; -const FIB_EXT = [1.272, 1.618, 2.000, 2.618]; -const FIB_SEQ = [1,1,2,3,5,8,13,21,34,55,89,144]; -const GAMMA_API = "https://gamma-api.polymarket.com"; -const CLOB_API = "https://clob.polymarket.com"; -const POLYGON_RPC = "https://polygon-rpc.com"; -const polygonProvider = new JsonRpcProvider(POLYGON_RPC); - -// ─── QUANT ENGINE ───────────────────────────────────────────────────────────── - -// Full Kelly: f* = (p·b - q) / b where b = (1-p_mkt)/p_mkt -const kellyF = (implP, trueP, bank = 1000, frac = 0.25) => { - if (implP <= 0.001 || implP >= 0.999 || trueP <= 0) return 0; - const b = (1 - implP) / implP; - const f = (trueP * b - (1 - trueP)) / b; - return f <= 0 ? 0 : parseFloat(Math.min(f * frac * bank, bank * 0.05).toFixed(2)); -}; - -// Golden Ratio size boost: when price near 61.8% zone, multiply by φ -const goldenKelly = (base, price) => { - if (price >= 0.595 && price <= 0.645) return +(base * PHI).toFixed(2); - const onFib = FIB_R.some(f => Math.abs(price - f) < 0.018); - return onFib ? +(base * PHI_INV).toFixed(2) : base; -}; - -// Expected Value -const calcEV = (trueP, mktP) => - mktP <= 0 ? 0 : +(trueP * (1 / mktP - 1) - (1 - trueP)).toFixed(4); - -// EMA -const ema = (arr, n) => { - if (!arr?.length || arr.length < n) return arr?.[arr.length - 1] ?? 0; - const k = 2 / (n + 1); - let e = arr.slice(0, n).reduce((a, b) => a + b, 0) / n; - for (let i = n; i < arr.length; i++) e = arr[i] * k + e * (1 - k); - return e; -}; - -// RSI-14 -const calcRSI = (arr, p = 14) => { - if (!arr || arr.length < p + 1) return 50; - const d = arr.slice(1).map((v, i) => v - arr[i]); - const g = d.slice(-p).filter(x => x > 0).reduce((a, b) => a + b, 0) / p; - const l = d.slice(-p).filter(x => x < 0).reduce((a, b) => a + Math.abs(b), 0) / p; - return l === 0 ? 100 : +(100 - 100 / (1 + g / l)).toFixed(1); -}; - -// MACD -const calcMACD = (arr) => { - if (!arr || arr.length < 26) return { hist: 0, bias: "FLAT" }; - const fast = ema(arr, 12), slow = ema(arr, 26); - const line = fast - slow; - const sig = ema([...Array(8).fill(line * 0.95), line], 9); - return { line, sig, hist: +(line - sig).toFixed(5), bias: line > sig ? "BULL" : "BEAR" }; -}; - -// Bollinger Bands (20, 2σ) -const calcBB = (arr, p = 20, s = 2) => { - if (!arr || arr.length < p) return null; - const sl = arr.slice(-p); - const ma = sl.reduce((a, b) => a + b, 0) / p; - const sd = Math.sqrt(sl.reduce((x, v) => x + (v - ma) ** 2, 0) / p); - const cur = arr[arr.length - 1]; - return { - upper: ma + s * sd, mid: ma, lower: ma - s * sd, sd, - pctB: +((cur - (ma - s * sd)) / (2 * s * sd + 1e-9)).toFixed(3), - squeeze: sd / (ma + 1e-9) < 0.014, - bw: (2 * s * sd) / (ma + 1e-9) - }; -}; - -// Fibonacci retracement levels -const fibLevels = (arr) => { - if (!arr?.length) return []; - const hi = Math.max(...arr), lo = Math.min(...arr), rng = hi - lo || 0.001; - const cur = arr[arr.length - 1]; - return FIB_R.map(f => ({ - f, price: +(hi - rng * f).toFixed(4), - near: Math.abs(cur - (hi - rng * f)) / rng < 0.022, - label: `${(f * 100).toFixed(1)}%` - })); -}; - -// Fibonacci extension targets -const fibExts = (arr) => { - if (!arr?.length) return []; - const hi = Math.max(...arr), lo = Math.min(...arr), rng = hi - lo || 0.001; - const cur = arr[arr.length - 1]; - const base = cur > 0.5 ? lo : hi; - const dir = cur > 0.5 ? 1 : -1; - return FIB_EXT.map(f => ({ - f, price: +(base + rng * f * dir).toFixed(4), label: `${(f * 100).toFixed(1)}%` - })); -}; - -// Bayesian posterior update: P(true | signal) -const bayesUpdate = (prior, signalStr, dir) => { - const acc = Math.min(0.80, 0.60 + signalStr * 0.20); - const lr = dir > 0 ? acc / (1 - acc) : (1 - acc) / acc; - const priorOdds = (prior + 1e-9) / (1 - prior + 1e-9); - const postOdds = priorOdds * lr; - return +Math.max(0.01, Math.min(0.99, postOdds / (1 + postOdds))).toFixed(4); -}; - -// Monte Carlo: 500 paths, 30 periods -const monteCarlo = (winR, odds, bank, kf = 0.25, sims = 500, periods = 30) => { - if (winR <= 0 || winR >= 1 || odds <= 0) return null; - const results = []; - for (let s = 0; s < sims; s++) { - let bal = bank; - for (let p = 0; p < periods && bal > 0; p++) { - const bet = Math.min(kellyF(1 / (odds + 1), winR, bal, kf), bal * 0.05); - bal = Math.random() < winR ? bal + bet * odds : bal - bet; - } - results.push(Math.max(0, bal)); - } - results.sort((a, b) => a - b); - return { - p10: +results[Math.floor(sims * 0.1)].toFixed(0), - p50: +results[Math.floor(sims * 0.5)].toFixed(0), - p90: +results[Math.floor(sims * 0.9)].toFixed(0), - ruin: +(results.filter(r => r <= 0).length / sims).toFixed(3), - exp: +(results.reduce((a, b) => a + b, 0) / sims - bank).toFixed(0) - }; -}; - -// Sharpe (simplified daily) -const calcSharpe = (rets) => { - if (!rets?.length) return 0; - const mu = rets.reduce((a, b) => a + b, 0) / rets.length; - const sd = Math.sqrt(rets.reduce((s, r) => s + (r - mu) ** 2, 0) / rets.length); - return sd === 0 ? 0 : +((mu - 0.0002) / sd).toFixed(2); -}; - -// Sortino -const calcSortino = (rets) => { - if (!rets?.length) return 0; - const mu = rets.reduce((a, b) => a + b, 0) / rets.length; - const neg = rets.filter(r => r < 0); - if (!neg.length) return 5; - const dd = Math.sqrt(neg.reduce((s, r) => s + r ** 2, 0) / rets.length); - return dd === 0 ? 0 : +(mu / dd).toFixed(2); -}; - -// Smart Ape momentum -const smartApe = (arr) => { - if (!arr?.length || arr.length < 5) return { sig: 0, dir: "FLAT" }; - const r = arr.slice(-3).reduce((a, b) => a + b, 0) / 3; - const o = arr.slice(0, Math.ceil(arr.length / 2)).reduce((a, b) => a + b, 0) / Math.ceil(arr.length / 2); - const sig = (r - o) / (o + 1e-9); - return { sig: +sig.toFixed(4), dir: sig > 0.035 ? "LONG" : sig < -0.035 ? "SHORT" : "FLAT" }; -}; - -// Gabagool arb engine -const gabagool = (yes, no) => { - const sum = yes + no, dev = 1 - sum, edge = Math.abs(dev); - if (edge < 0.015) return { active: false }; - return { active: true, edge: +edge.toFixed(4), dev, side: dev > 0 ? (yes < no ? "BUY_YES" : "BUY_NO") : "SELL_BOTH", size: +(edge * 260).toFixed(0) }; -}; - -// OB imbalance -const obImbal = (bids = [], asks = []) => { - const b = bids.reduce((s, x) => s + +(x.size ?? x[1] ?? 0), 0); - const a = asks.reduce((s, x) => s + +(x.size ?? x[1] ?? 0), 0); - return b + a === 0 ? 0 : +((b - a) / (b + a)).toFixed(3); -}; - -// Whale score -const whaleScore = (vol, liq) => { - const r = (vol + 1) / (liq + 1); - return +(Math.min(1, r > 20 ? 1 : r > 10 ? 0.75 : r > 5 ? 0.45 : r / 15)).toFixed(2); -}; - -// UMA dispute risk -const umaRisk = (m) => { - let r = 0; - const q = (m.question || "").toLowerCase(); - if (!q.includes(" by ") && !q.includes(" before ")) r += 0.14; - if (/approximately|around|roughly/.test(q)) r += 0.24; - if (/major|significant|notable/.test(q)) r += 0.18; - const days = m.endDate ? (new Date(m.endDate) - Date.now()) / 86400000 : 999; - if (days < 3 && +(m.volumeNum || 0) > 50000) r += 0.24; - const y = +(m.outcomePrices?.[0] || 0.5); - if (y > 0.93 || y < 0.07) r += 0.14; - return +Math.min(r, 1).toFixed(2); -}; - -// Multi-timeframe signals -const multiTF = (arr) => { - const frames = [ - { id: "SCALP", label: "5-15m", sl: arr.slice(-6) }, - { id: "SWING", label: "1-4h", sl: arr.slice(-14) }, - { id: "POSITION", label: "4h-1d", sl: arr.slice(-25) }, - { id: "MACRO", label: "1d+", sl: arr } - ]; - return frames.map(({ id, label, sl }) => { - const r = calcRSI(sl, Math.min(sl.length - 1, 9)); - const m = smartApe(sl); - const bb = calcBB(sl, Math.min(sl.length, 20)); - const mc = calcMACD(sl); - const fl = fibLevels(sl).find(l => l.near) || null; - const score = (r > 65 ? -0.28 : r < 35 ? 0.28 : 0) + m.sig * 2 + - (mc.hist > 0 ? 0.18 : -0.18) + (bb?.pctB < 0.2 ? 0.22 : bb?.pctB > 0.8 ? -0.22 : 0); - const dir = score > 0.2 ? "LONG" : score < -0.2 ? "SHORT" : "FLAT"; - return { id, label, rsi: r, ape: m, bb, macd: mc, fib: fl, score: +score.toFixed(3), dir }; - }); -}; - -// True probability estimate (Bayesian composite) -const trueProb = (m, arr, obi, ws) => { - const mktP = +(m.outcomePrices?.[0] || 0.5); - const ape = smartApe(arr); - const wAdj = ws > 0.7 ? (mktP > 0.5 ? -0.022 : 0.022) : 0; - const raw = Math.max(0.01, Math.min(0.99, mktP + wAdj + ape.sig * 0.038 + obi * 0.022)); - return bayesUpdate(raw, Math.min(Math.abs(ape.sig) + Math.abs(obi), 1), ape.sig > 0 ? 1 : -1); -}; - -// Market grade A–F -const marketGrade = (evS, uma, vol, liq) => { - let g = 100 - uma * 34 + Math.min(evS * 17, 27); - if (vol < 1000) g -= 26; if (liq < 500) g -= 17; - return g >= 85 ? "A" : g >= 70 ? "B" : g >= 54 ? "C" : g >= 38 ? "D" : "F"; -}; - -// ─── API LAYER ──────────────────────────────────────────────────────────────── -const fetchMarkets = async (n = 28) => { - const r = await fetch(`${GAMMA_API}/markets?active=true&closed=false&archived=false&limit=${n}&order=volumeNum&ascending=false`); - const d = await r.json(); - return Array.isArray(d) ? d : d.markets || []; -}; -const fetchBook = async (tid) => { - try { return await (await fetch(`${CLOB_API}/book?token_id=${tid}`)).json(); } catch { return null; } -}; -const fetchHistory = async (tid) => { - try { - const d = await (await fetch(`${GAMMA_API}/prices-history?market=${tid}&interval=1d&fidelity=10`)).json(); - return d?.history?.map(h => +h.p) || []; - } catch { return []; } -}; -const verifyChain = async (addr) => { - try { - const checksum = getAddress(addr); - const balWei = await polygonProvider.getBalance(checksum); - return { ok: true, bal: Number(formatEther(balWei)), address: checksum }; - } catch (e) { - return { ok: false, err: e?.message || "RPC_ERROR" }; - } -}; - -// Full analysis pipeline -const analyzeMarket = async (m) => { - const tid = m.clobTokenIds?.[0] || m.conditionId; - const [book, ph] = await Promise.all([tid ? fetchBook(tid) : null, tid ? fetchHistory(tid) : []]); - const yes = +(m.outcomePrices?.[0] || 0.5); - const no = +(m.outcomePrices?.[1] || 0.5); - const obi = obImbal(book?.bids, book?.asks); - const ws = whaleScore(+m.volumeNum, +m.liquidityNum); - const tp = trueProb(m, ph, obi, ws); - const evv = calcEV(tp, yes); - const kBase = kellyF(yes, tp, 1000, 0.25); - const k = goldenKelly(kBase, yes); - const gab = gabagool(yes, no); - const uma = umaRisk(m); - const bb = calcBB(ph); - const r14 = calcRSI(ph); - const mc2 = calcMACD(ph); - const ape = smartApe(ph); - const tfs = multiTF(ph); - const fl = fibLevels(ph); - const fe = fibExts(ph); - const rets= ph.slice(1).map((p, i) => p - ph[i]); - const sh = calcSharpe(rets); - const so = calcSortino(rets); - const evS = evv * 2 + (gab.active ? gab.edge * 4 : 0) + Math.abs(obi) * 0.3 - uma * 0.6; - const gr = marketGrade(evS, uma, +m.volumeNum, +m.liquidityNum); - const mc5 = ph.length > 8 ? monteCarlo(tp, (1 - yes) / yes, 1000, 0.25) : null; - let action = "HOLD"; - if (gab.active && gab.edge > 0.024) action = "ARB"; - else if (evv > 0.06 && tp > yes + 0.04) action = "BUY_YES"; - else if (evv < -0.06 && tp < yes - 0.04) action = "BUY_NO"; - else if (Math.abs(obi) < 0.15 && +m.liquidityNum > 2000) action = "MKT_MAKE"; - return { ...m, yes, no, tp, ev: evv, kelly: k, gab, uma, bb, rsi: r14, macd: mc2, ape, tfs, fib: fl, fibExt: fe, evScore: evS, grade: gr, mc: mc5, sharpe: sh, sortino: so, obi, ws, action, ph, book }; -}; - -// ─── FORMATTING ─────────────────────────────────────────────────────────────── -const f2 = n => typeof n === "number" ? n.toFixed(2) : "—"; -const f3 = n => typeof n === "number" ? n.toFixed(3) : "—"; -const pct = n => typeof n === "number" ? `${(n * 100).toFixed(1)}%` : "—"; -const usd = n => typeof n === "number" ? `$${Math.abs(n).toFixed(0)}` : "—"; -const kfmt= n => typeof n === "number" ? (n >= 1000 ? `${(n/1000).toFixed(0)}k` : n.toFixed(0)) : "—"; -const hsh = a => a ? `${a.slice(0,6)}…${a.slice(-4)}` : "—"; - -// ─── COLOR TOKENS ────────────────────────────────────────────────────────────── -const C = { - bg: "#090B10", - surface: "#0E1117", - panel: "#12161E", - border: "#1C2333", - borderL: "#243044", - gold: "#F5A623", - goldL: "#FFD080", - green: "#00E5A0", - blue: "#3B9EFF", - violet: "#A78BFA", - rose: "#FF5757", - amber: "#FFB800", - text: "#C8D8E8", - textDim: "#4A6078", - textSub: "#2A3A50", -}; - -const GC = { A: "#00E5A0", B: "#7FFFCF", C: "#F5A623", D: "#FF8C00", F: "#FF5757" }; -const AC = { BUY_YES:"#00E5A0", BUY_NO:"#FF5757", ARB:"#A78BFA", MKT_MAKE:"#3B9EFF", HOLD:"#2A3A50" }; -const fC = f => ({ 0:"#4A6078","0.236":"#22D3EE","0.382":"#60A5FA","0.5":"#F5A623","0.618":"#F5A623","0.786":"#FB923C","1":"#4A6078" })[String(f)] || "#4A6078"; -const dC = d => d === "LONG" ? C.green : d === "SHORT" ? C.rose : C.textDim; - -// ═══════════════════════════════════════════════════════════════════════════════ -// MICRO-COMPONENTS -// ═══════════════════════════════════════════════════════════════════════════════ - -const Tag = ({ c, children, sm }) => ( - - {children} - -); - -const Pill = ({ c, children }) => ( - - {children} - -); - -const MetricCard = ({ label, value, color, sub }) => ( -
    -
    -
    {label}
    -
    {value}
    - {sub &&
    {sub}
    } -
    -); - -const ScoreBar = ({ value, max = 1, color }) => { - const w = Math.min(100, Math.abs(value / max) * 100); - return ( -
    -
    -
    - ); -}; - -// RSI meter -const RSIMeter = ({ val }) => { - const c = val > 70 ? C.rose : val < 30 ? C.green : C.textDim; - return ( -
    -
    -
    -
    -
    -
    - {val?.toFixed(0)} -
    - ); -}; - -// Fibonacci SVG chart -const FibChart = ({ prices, w = 460, h = 120 }) => { - if (!prices?.length || prices.length < 3) return ( -
    - NO PRICE HISTORY -
    - ); - const hi = Math.max(...prices), lo = Math.min(...prices), rng = hi - lo || 0.001; - const xp = i => (i / (prices.length - 1)) * w; - const yp = p => h - 4 - ((p - lo) / rng) * (h - 8); - const pts = prices.map((p, i) => `${xp(i)},${yp(p)}`).join(" "); - const bb = calcBB(prices); - const fls = fibLevels(prices); - const cur = prices[prices.length - 1]; - const bullish = cur >= prices[0]; - - return ( - - - - - - - - - - - - - {/* Grid lines */} - {[0.25, 0.5, 0.75].map(r => ( - - ))} - - {/* Bollinger fill */} - {bb && ( - <> - - - - - - )} - - {/* Fibonacci levels */} - {fls.map(({ f, price, near, label }) => { - const y = yp(price); - if (y < -4 || y > h + 4) return null; - const col = fC(f); - return ( - - - {near && } - {label} - - ); - })} - - {/* Price area fill */} - - - {/* Price line glow */} - - - - {/* Current price dot */} - - - - {/* Price labels */} - {pct(hi)} - {pct(lo)} - - ); -}; - -// Mini sparkline -const Spark = ({ data, color, w = 60, h = 18 }) => { - if (!data?.length || data.length < 2) return ──; - const mn = Math.min(...data), mx = Math.max(...data), rng = mx - mn || 0.001; - const pts = data.map((v, i) => `${(i/(data.length-1))*w},${h-((v-mn)/rng)*h}`).join(" "); - const trend = data[data.length-1] > data[0] ? C.green : C.rose; - return ( - - - - ); -}; - -// MC Distribution bar chart -const MCBars = ({ mc, bank }) => { - if (!mc) return null; - const vals = [mc.p10, mc.p50, mc.p90]; - const max = mc.p90 || bank * 2; - const labels = ["P10", "P50", "P90"]; - const cols = [C.rose, C.gold, C.green]; - return ( -
    - {vals.map((v, i) => ( -
    - {labels[i]} -
    -
    -
    - ${v} -
    - ))} -
    - ); -}; - -// ═══════════════════════════════════════════════════════════════════════════════ -// GPT SYSTEM PROMPT BUILDER -// ═══════════════════════════════════════════════════════════════════════════════ -const buildSystemPrompt = (ctx, bank, wallet, kf) => `You are TradeHax GPT — the world's most sophisticated prediction market trading AI assistant, built into TradeHax.net for a professional HFT algo trader. - -## YOUR QUANT STACK -- **Full Kelly Criterion**: f* = (p·b − q)/b × ${kf} fractional. Hard 5% bankroll cap. -- **Golden Ratio Kelly**: Position size ×φ (×1.618) at the 61.8% zone. Reduced at hard fib walls. -- **Fibonacci**: φ=1.618. Retracements: 23.6/38.2/50/61.8/78.6%. Extensions: 127.2/161.8/200/261.8%. -- **Bayesian Probability Update**: P(true|signal) via likelihood ratio on market prior. -- **Bollinger Bands**: 20-period MA ± 2σ. %B position. Squeeze detection. -- **MACD**: EMA(12)−EMA(26) vs 9-period signal line. -- **RSI-14**: Overbought >70, oversold <30. -- **Monte Carlo**: 500-path Kelly growth simulation with ruin rate. -- **Gabagool Arb**: Risk-free when YES+NO ≠ $1.00 (complete-set redemption). -- **Smart Ape Momentum**: Price trend + volume acceleration composite. -- **Whale Radar**: Vol/liq concentration → price distortion signal. -- **UMA Dispute Risk**: Resolution ambiguity scoring (penalizes vague markets). -- **Multi-Timeframe**: SCALP(5-15m) / SWING(1-4h) / POSITION(4h-1d) / MACRO(1d+). -- **Sharpe + Sortino Ratios**: Risk-adjusted quality scoring. - -## RESPONSE STYLE -- Sharp, confident, direct. You're a prop desk quant who also happens to be fun to talk to. -- Numbers-first. Always cite the Fibonacci level nearest to entry. -- For trade recommendations, use this format: - 🎯 **[MARKET]** — **[ACTION]** - Entry: [price] ([nearest Fib level]) - Kelly Size: $[amount] USDC - EV: [+/-X.X%] | Confidence: [X%] | TF: [SCALP/SWING/POSITION/MACRO] - Target: [Fib extension price] | Stop: [price] - Edge: [what's driving this] - Risk: [LOW/MED/HIGH] - -Active wallet: ${wallet || "not connected"} -Bankroll: $${bank} | Kelly Fraction: ${(kf*100).toFixed(0)}% - -## LIVE MARKET DATA (from scan): -${ctx || "No scan data yet. Ask the user to hit SCAN to load live markets."}`; - -// AI Endpoint: Use local API if available, with graceful degradation -const AI_ENDPOINT = "/api/signals/ai-signals"; - -const parseJsonSafe = (raw, fallback = null) => { - if (!raw || typeof raw !== "string") return fallback; - try { return JSON.parse(raw); } catch { return fallback; } -}; - -const buildLocalSignals = (mkts = []) => - mkts.slice(0, 6).map((m) => ({ - question: (m.question || "Unknown market").slice(0, 120), - action: m.action || "SKIP", - edge: +(m.ev || 0).toFixed(4), - confidence: +Math.max(0.35, Math.min(0.94, 0.5 + Math.abs(m.ev || 0) * 2 + (m.grade === "A" ? 0.1 : 0))).toFixed(2), - kelly: +(m.kelly || 0).toFixed(2), - tf: (m.tfs?.find((x) => x.dir !== "FLAT")?.id || "SWING"), - fibLevel: m.fib?.find((f) => f.near)?.label || "50.0%", - thesis: `${m.grade || "C"} grade, EV ${f3(m.ev)}, RSI ${m.rsi?.toFixed(0) || "50"}`.slice(0, 60), - risk: m.uma > 0.55 ? "HIGH" : m.uma > 0.3 ? "MED" : "LOW" - })); - -const buildLocalChatReply = ({ msg, markets, bankroll, kFrac, wallet }) => { - const top = markets?.[0]; - if (!top) { - return "No live market scan is loaded yet. Hit SCAN and I will generate ranked trade setups with Kelly sizing."; - } - - const q = (msg || "").toLowerCase(); - if (q.includes("wallet")) { - return wallet - ? `Wallet connected: ${hsh(wallet)}. Top setup right now is ${top.action} on \"${(top.question || "market").slice(0, 60)}\".` - : "Wallet is not connected yet. Verify an address in the Wallet tab before placing orders."; - } - - if (q.includes("risk") || q.includes("kelly") || q.includes("size")) { - return `Risk desk: bankroll $${bankroll}, Kelly fraction ${(kFrac * 100).toFixed(0)}%. Best current size is ${usd(top.kelly)} on ${top.action} with EV ${f3(top.ev)} and UMA risk ${f2(top.uma)}.`; - } - - return `Top trade: ${top.action} on \"${(top.question || "market").slice(0, 62)}\" at ${pct(top.yes)}. TrueP ${pct(top.tp)}, EV ${f3(top.ev)}, Kelly ${usd(top.kelly)}, Fib ${top.fib?.find((f) => f.near)?.label || "50.0%"}.`; -}; - -const requestAdapter = async (payload) => { - try { - const r = await fetch(AI_ENDPOINT, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(payload) - }); - if (!r.ok) throw new Error(`HTTP ${r.status}`); - return await r.json(); - } catch (e) { - console.warn("AI adapter failed:", e); - return null; - } -}; - -// ═══════════════════════════════════════════════════════════════════════════════ -// MAIN COMPONENT -// ═══════════════════════════════════════════════════════════════════════════════ -export default function PolymarketTerminal() { - // State - const [view, setView] = useState("scanner"); - const [markets, setMarkets] = useState([]); - const [loading, setLoading] = useState(false); - const [phase, setPhase] = useState("IDLE"); - const [sel, setSel] = useState(null); - const [aiSigs, setAiSigs] = useState([]); - const [orders, setOrders] = useState([]); - const [wallet, setWallet] = useState(""); - const [walInput, setWalInput] = useState(""); - const [walStatus, setWalStatus] = useState(null); - const [bankroll, setBankroll] = useState(1000); - const [kFrac, setKFrac] = useState(0.25); - const [minGrade, setMinGrade] = useState("C"); - const [paperMode, setPaperMode] = useState(true); // View-only mode by default - const [chatLog, setChatLog] = useState([ - { role:"assistant", text:"Hey! I'm **TradeHax GPT** — your elite prediction market co-pilot. 🎯\n\n**📊 VIEW-ONLY MODE ACTIVE** — Analyze markets, get predictions, and test strategies without executing real trades.\n\nHit **SCAN** to load live markets and I'll break down the best trades using Fibonacci confluence, full Kelly sizing, Bayesian probability, and Monte Carlo simulation.\n\nToggle to LIVE MODE in settings when you're ready to execute real trades." } - ]); - const [chatInput, setChatInput] = useState(""); - const [chatLoading, setChatLoading] = useState(false); - const [pnl, setPnl] = useState({ realized:0, trades:0, wins:0 }); - const [tick, setTick] = useState([]); - const [chatPanelOpen, setChatPanelOpen] = useState(true); - const [isMobile, setIsMobile] = useState(false); - const [isTablet, setIsTablet] = useState(false); - const chatEnd = useRef(null); - const autoTimer = useRef(null); - - // Load fonts - useEffect(() => { - const link = document.createElement("link"); - link.rel = "stylesheet"; - link.href = "https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;700;900&family=Fira+Code:wght@300;400;500;600&family=DM+Sans:wght@300;400;500;600&display=swap"; - document.head.appendChild(link); - }, []); - - useEffect(() => { chatEnd.current?.scrollIntoView({ behavior:"smooth" }); }, [chatLog]); - - // Ticker - useEffect(() => { - const msgs = ["φ=1.618 ARMED","KELLY ¼f*","GABAGOOL ARB","FIBONACCI LIVE","500-PATH MC","BAYESIAN UPDATE","BOLLINGER ACTIVE","MULTI-TF ONLINE","WHALE RADAR","POLYGON RPC OK","$HAX STAKING V2"]; - let i = 0; - const t = setInterval(() => { setTick(p => [...p.slice(-10), msgs[i++ % msgs.length]]); }, 1800); - return () => clearInterval(t); - }, []); - - const GO = { A:5, B:4, C:3, D:2, F:1 }; - const filtered = useMemo(() => - markets.filter(m => GO[m.grade] >= GO[minGrade]).sort((a, b) => b.evScore - a.evScore), - [markets, minGrade] - ); - - // Top-line stats - const stats = useMemo(() => ({ - gradeA: markets.filter(m => m.grade === "A").length, - arbOps: markets.filter(m => m.gab?.active).length, - topEV: markets.reduce((mx, m) => Math.max(mx, m.ev || 0), 0), - avgSharpe: markets.length > 0 - ? +(markets.reduce((s, m) => s + (m.sharpe || 0), 0) / markets.length).toFixed(2) - : 0 - }), [markets]); - - // Signal generation via optional adapter, with local quant fallback - const generateAISignals = async (mkts) => { - const fallback = { signals: buildLocalSignals(mkts) }; - const ctx = mkts.slice(0, 6).map(m => ({ - q: m.question?.slice(0, 65), yes: pct(m.yes), tp: pct(m.tp), - ev: f3(m.ev), kelly: usd(m.kelly), grade: m.grade, - arb: m.gab?.active ? pct(m.gab.edge) : "N", - whale: f2(m.ws), action: m.action, - fib: m.fib?.find(f => f.near)?.label || "—", rsi: m.rsi?.toFixed(0) || "—" - })); - - try { - const d = await requestAdapter({ mode: "signals", context: ctx }); - if (Array.isArray(d?.signals)) return { signals: d.signals }; - const parsed = parseJsonSafe(d?.content, null); - if (Array.isArray(parsed?.signals)) return { signals: parsed.signals }; - return fallback; - } catch { - return fallback; - } - }; - - // ── Full scan pipeline - const scan = useCallback(async (loader = true) => { - if (loader) setLoading(true); - setPhase("FETCHING"); - try { - const raw = await fetchMarkets(28); - setPhase("COMPUTING"); - const b1 = await Promise.all(raw.slice(0, 8).map(analyzeMarket)); - setMarkets(b1.sort((a, b) => b.evScore - a.evScore)); - - const b2 = await Promise.all(raw.slice(8, 20).map(analyzeMarket)); - const all = [...b1, ...b2].sort((a, b) => b.evScore - a.evScore); - setMarkets(all); - - setPhase("SIGNAL ENGINE"); - const sigs = await generateAISignals(all); - setAiSigs(sigs?.signals || []); - setPhase("LIVE ●"); - addChat("assistant", `Scan complete — **${all.length} markets** analyzed.\n\n🏆 **Grade A:** ${all.filter(m=>m.grade==="A").length} markets\n⚡ **Arb Ops:** ${all.filter(m=>m.gab?.active).length} active\n📈 **Top EV:** ${f3(all[0]?.ev)}\n\nTop pick: **${all[0]?.question?.slice(0,55)}…** — ${all[0]?.action} at ${pct(all[0]?.yes)}, EV: +${f3(all[0]?.ev)}, Kelly: ${usd(all[0]?.kelly)}`); - } catch(e) { setPhase("ERROR"); } - if (loader) setLoading(false); - }, []); - - - // Order placement - const placeOrder = (m, side) => { - if (paperMode) { - const price = side === "BUY_YES" ? m.yes : m.no || 0.5; - const size = Math.max(10, Math.round(m.kelly || 30)); - const o = { id:"PAPER-"+Math.random().toString(16).slice(2,10).toUpperCase(), market:m.question?.slice(0,42), side, size, price, ev:m.ev, kelly:m.kelly, grade:m.grade, status:"SIMULATED", ts:new Date().toLocaleTimeString() }; - setOrders(p => [o, ...p.slice(0, 24)]); - addChat("assistant", `📊 **PAPER TRADE LOGGED** (View-Only Mode)\n**${side}** $${size} on "${m.question?.slice(0,45)}…"\n@ ${pct(price)} | EV: ${f3(m.ev)} | Kelly: $${size} | Grade: ${m.grade}\n\n💡 This is a simulated order for analysis purposes only. Switch to LIVE MODE to execute real trades.`); - // Simulate immediate "fill" for paper trading - setTimeout(() => { - setOrders(p => p.map(x => x.id===o.id ? {...x, status:"PAPER-FILLED"} : x)); - setPnl(p => ({ realized:+(p.realized+(m.ev||0)*size*0.5).toFixed(2), trades:p.trades+1, wins:p.wins+(m.ev>0?1:0) })); - }, 800); - return; - } - - if (!wallet) { addChat("assistant","⚠️ Connect your wallet first! Head to the **Wallet** tab to verify on-chain."); return; } - const price = side === "BUY_YES" ? m.yes : m.no || 0.5; - const size = Math.max(10, Math.round(m.kelly || 30)); - const o = { id:"0x"+Math.random().toString(16).slice(2,10).toUpperCase(), market:m.question?.slice(0,42), side, size, price, ev:m.ev, kelly:m.kelly, grade:m.grade, status:"PENDING", ts:new Date().toLocaleTimeString() }; - setOrders(p => [o, ...p.slice(0, 24)]); - addChat("assistant", `Order placed! 🎯\n**${side}** $${size} on "${m.question?.slice(0,45)}…"\n@ ${pct(price)} | EV: ${f3(m.ev)} | Kelly: $${size} | Grade: ${m.grade}`); - setTimeout(() => { - const filled = Math.random() > 0.11; - setOrders(p => p.map(x => x.id===o.id ? {...x, status: filled?"FILLED":"CANCELLED"} : x)); - if (filled) setPnl(p => ({ realized:+(p.realized+(m.ev||0)*size).toFixed(2), trades:p.trades+1, wins:p.wins+(m.ev>0?1:0) })); - }, 2300); - }; - - // Wallet verify - const verifyWallet = async () => { - const a = walInput.trim(); - if (!/^0x[0-9a-fA-F]{40}$/.test(a)) { setWalStatus({ ok:false, err:"Invalid address format" }); return; } - setWalStatus("checking"); - const res = await verifyChain(a); - setWalStatus(res); - if (res.ok) { - setWallet(res.address || a); - addChat("assistant", `✅ Wallet verified on-chain!\n**${hsh(res.address || a)}** — ${res.bal?.toFixed(4)} POL on Polygon.\nYou're all set to execute trades.`); - } - }; - - // Chat - const addChat = (role, text) => setChatLog(p => [...p, { role, text, ts:new Date().toLocaleTimeString() }]); - - const sendChat = async () => { - const msg = chatInput.trim(); - if (!msg || chatLoading) return; - setChatInput(""); - addChat("user", msg); - setChatLoading(true); - - const ctx = filtered.slice(0, 8).map(m => - `${m.question?.slice(0, 55)} | Price:${pct(m.yes)} TrueP:${pct(m.tp)} EV:${f3(m.ev)} Kelly:${usd(m.kelly)} Grade:${m.grade} Fib:${m.fib?.find(f=>f.near)?.label||"—"} Action:${m.action} RSI:${m.rsi?.toFixed(0)||"—"} Arb:${m.gab?.active?pct(m.gab.edge):"N"}` - ).join("\n"); - - try { - const messages = chatLog.filter(m=>m.role!=="system").slice(-14) - .map(m => ({ role:m.role==="user"?"user":"assistant", content:m.text })) - .concat([{ role:"user", content:msg }]); - - let reply = ""; - if (AI_ENDPOINT) { - const d = await requestAdapter({ - mode: "chat", - system: buildSystemPrompt(ctx, bankroll, wallet, kFrac), - messages - }); - reply = d?.reply || d?.text || d?.content?.[0]?.text || d?.content || ""; - } - - if (!reply) { - reply = buildLocalChatReply({ msg, markets: filtered, bankroll, kFrac, wallet }); - } - - addChat("assistant", reply); - } catch { - addChat("assistant", buildLocalChatReply({ msg, markets: filtered, bankroll, kFrac, wallet })); - } - setChatLoading(false); - }; - - useEffect(() => { - const syncViewport = () => { - const w = window.innerWidth; - setIsMobile(w < 900); - setIsTablet(w >= 900 && w < 1200); - }; - syncViewport(); - window.addEventListener("resize", syncViewport); - return () => window.removeEventListener("resize", syncViewport); - }, []); - - const phaseColor = phase === "LIVE ●" ? C.green : phase === "IDLE" ? C.textDim : phase === "ERROR" ? C.rose : C.amber; - - // ───────────────────────────────────────────────────────────────────────────── - // RENDER - // ───────────────────────────────────────────────────────────────────────────── - const VIEWS = [ - { id:"scanner", icon:"◈", label:"Scanner" }, - { id:"analysis", icon:"⌬", label:"Fibonacci" }, - { id:"multitf", icon:"◫", label:"Multi-TF" }, - { id:"signals", icon:"▲", label:"Signals" }, - { id:"risk", icon:"◆", label:"Risk Desk" }, - { id:"orders", icon:"⊕", label:"Orders" }, - { id:"wallet", icon:"◉", label:"Wallet" }, - ]; - - return ( -
    - - - {/* ── TICKER TAPE ─────────────────────────────────────────────────────── */} -
    - {[...tick,...tick,...tick].map((t,i) => ( - ◆ {t} - ))} -
    - - {/* ── HEADER ──────────────────────────────────────────────────────────── */} -
    -
    -
    -
    - TRADEHAX -
    -
    - GPT APEX EDITION · tradehax.net -
    -
    -
    -
    - {phase} - {markets.length > 0 && {markets.length} MARKETS} -
    -
    - - {/* Stats strip */} -
    - {[ - { l:paperMode?"PAPER P&L":"P&L", v:`${pnl.realized >= 0 ? "+" : ""}$${pnl.realized.toFixed(0)}`, c: pnl.realized >= 0 ? C.green : C.rose }, - { l:"TRADES", v:pnl.trades, c:C.text }, - { l:"WIN RATE", v:pnl.trades > 0 ? pct(pnl.wins/pnl.trades) : "—", c:C.gold }, - { l:"GRADE A", v:stats.gradeA, c:C.green }, - { l:"ARB OPS", v:stats.arbOps, c:C.violet }, - ].map(({ l,v,c }) => ( -
    -
    {l}
    -
    {v}
    -
    - ))} -
    - -
    - - {wallet ? `✓ ${hsh(wallet)}` : "NO WALLET"} - - -
    -
    - - {/* ── MAIN BODY ────────────────────────────────────────────────────────── */} -
    - - {/* ── SIDEBAR NAV ─────────────────────────────────────────────────── */} - - - {/* ── MAIN CONTENT ────────────────────────────────────────────────── */} -
    -
    - - {/* ════════════════ SCANNER ════════════════════════════════════ */} - {view === "scanner" && ( -
    - {/* Stat cards */} - {markets.length > 0 && ( -
    - - - - -
    - )} - - {filtered.length === 0 && !loading && ( -
    -
    -
    - ALL ENGINES ARMED -
    -
    - Hit the ⟳ button to scan live Polymarket data -
    - -
    - )} - - {filtered.length > 0 && ( -
    - {/* Header row */} -
    - #MARKETYES↑TRUE PEVKELLY $GRARBWHALERSISIGNAL -
    - - {filtered.map((m, i) => ( -
    { setSel(m); setView("analysis"); }} - style={{ minWidth:isMobile?720:900, display:"grid", gridTemplateColumns:"20px 1fr 58px 58px 64px 62px 42px 52px 48px 52px 96px", gap:8, padding:"9px 14px", borderBottom:`1px solid ${C.border}`, background: i%2===0?C.bg:C.surface, cursor:"pointer", transition:"background 0.12s", alignItems:"center" }}> - {i+1} -
    -
    {m.question}
    -
    - {m.category||"MISC"} · ${kfmt(m.volumeNum)} vol · ${kfmt(m.liquidityNum)} liq -
    -
    - {pct(m.yes)} - (m.yes||0)+0.04?C.green:m.tp<(m.yes||0)-0.04?C.rose:C.textDim }}>{pct(m.tp)} - 0.05?C.green:m.ev<-0.05?C.rose:C.textDim }}> - {m.ev>0?"+":""}{f3(m.ev)} - - {usd(m.kelly)} - {m.grade} - - {m.gab?.active ? pct(m.gab.edge) : "—"} - - 0.6?C.amber:C.textSub }}> - {m.ws>0.4?`🐋${(m.ws*100).toFixed(0)}%`:"—"} - - -
    - {m.action} - {m.action !== "HOLD" && ( - - )} -
    -
    - ))} -
    - )} -
    - )} - - {/* ════════════════ FIBONACCI ANALYSIS ════════════════════════ */} - {view === "analysis" && ( -
    - {!sel ? ( -
    - Select a market from the Scanner to view Fibonacci analysis -
    - ) : ( -
    -
    -

    {sel.question}

    -
    - GRADE {sel.grade} - {sel.action} - {sel.fib?.find(f=>f.near) && φ {sel.fib.find(f=>f.near).label} CONFLUENCE} - {sel.bb?.squeeze && BB SQUEEZE} - {sel.gab?.active && GABAGOOL ARB {pct(sel.gab.edge)}} - - VOL ${kfmt(sel.volumeNum)} · LIQ ${kfmt(sel.liquidityNum)} · EXP {sel.endDate ? new Date(sel.endDate).toLocaleDateString() : "OPEN"} - -
    -
    - - {/* Chart */} -
    -
    - PRICE HISTORY · FIBONACCI RETRACEMENTS · BOLLINGER BANDS (20, 2σ) -
    - -
    - {FIB_R.map(f => ( - l.f===f)?.near?1:0.5 }}> - ── {(f*100).toFixed(1)}%{sel.fib?.find(l=>l.f===f)?.near?" ◆":""} - - ))} - ─── BB -
    -
    - - {/* Metrics grid */} -
    - {[ - ["MARKET PRICE", pct(sel.yes), C.green], - ["TRUE PROBABILITY", pct(sel.tp), sel.tp>(sel.yes||0)+0.04?C.green:sel.tp<(sel.yes||0)-0.04?C.rose:C.textDim], - ["EXPECTED VALUE", `${sel.ev>0?"+":""}${f3(sel.ev)}`, sel.ev>0.05?C.green:sel.ev<-0.05?C.rose:C.textDim], - ["KELLY ¼f*", usd(sel.kelly), C.blue], - ["BB %B", f2(sel.bb?.pctB), sel.bb?.pctB<0.2?C.green:sel.bb?.pctB>0.8?C.rose:C.textDim], - ["RSI-14", `${(sel.rsi||50).toFixed(0)}${sel.rsi>70?" OB":sel.rsi<30?" OS":""}`, sel.rsi>70?C.rose:sel.rsi<30?C.green:C.textDim], - ["SHARPE", f2(sel.sharpe), sel.sharpe>1?C.green:sel.sharpe<0?C.rose:C.textDim], - ["SORTINO", f2(sel.sortino), sel.sortino>1.5?C.green:sel.sortino<0?C.rose:C.textDim], - ["MACD BIAS", sel.macd?.bias||"—", sel.macd?.bias==="BULL"?C.green:C.rose], - ["WHALE SCORE", pct(sel.ws||0), sel.ws>0.6?C.amber:C.textDim], - ["UMA RISK", pct(sel.uma||0), sel.uma>0.5?C.rose:sel.uma>0.25?C.amber:C.green], - ["OB IMBALANCE", f2(sel.obi), sel.obi>0.15?C.green:sel.obi<-0.15?C.rose:C.textDim], - ].map(([l,v,c]) => )} -
    - - {/* Fib extension targets */} -
    -
    - φ FIBONACCI EXTENSION TARGETS — PROFIT LEVELS -
    -
    - {(sel.fibExt||[]).map(({ f, price, label }) => ( -
    -
    {label}
    -
    {pct(price)}
    -
    - ))} -
    -
    - - {/* Gabagool arb detail */} - {sel.gab?.active && ( -
    -
    - ◈ GABAGOOL ARBITRAGE — RISK-FREE COMPLETE-SET OPPORTUNITY -
    -
    - YES+NO Total: {pct(sel.yes+sel.no)} - Edge: {pct(sel.gab.edge)} - Side: {sel.gab.side} - Size: ${sel.gab.size} -
    -
    - Buy YES + NO for <$1.00, redeem complete set for $1.00. Pure arbitrage — no directional risk. -
    -
    - )} - - {/* Monte Carlo */} - {sel.mc && ( -
    -
    MONTE CARLO — 500 SIMULATIONS · 30 PERIODS · {(kFrac*100).toFixed(0)}% KELLY -
    -
    - -
    -
    - Ruin Rate: - 0.05 ? C.rose : C.green, fontWeight:600, fontFamily:"'Fira Code',monospace" }}>{pct(sel.mc.ruin)} -
    -
    - Expectancy: - 0 ? C.green : C.rose, fontWeight:600, fontFamily:"'Fira Code',monospace" }}> - {sel.mc.exp > 0 ? "+" : ""}${sel.mc.exp} - -
    - 0?C.green:C.rose} /> -
    -
    -
    - )} - - {/* Order buttons */} -
    - {["BUY_YES","BUY_NO","MKT_MAKE"].map(a => ( - - ))} -
    -
    - )} -
    - )} - - {/* ════════════════ MULTI-TIMEFRAME ════════════════════════════ */} - {view === "multitf" && ( -
    -
    - ◫ MULTI-TIMEFRAME CONFLUENCE — SCALP · SWING · POSITION · MACRO -
    - {filtered.length === 0 &&
    Run a scan first
    } - {filtered.slice(0, 12).map((m, mi) => ( -
    -
    -
    {m.question}
    -
    - GRADE {m.grade} - {m.action} -
    -
    -
    - {(m.tfs||[]).map(tf => ( -
    -
    - {tf.id} - {tf.label} -
    -
    {tf.dir}
    - -
    - -
    -
    - {tf.macd?.bias} - {tf.fib && φ {tf.fib.label}} -
    -
    - ))} -
    -
    - ))} -
    - )} - - {/* ════════════════ AI SIGNALS ══════════════════════════════════ */} - {view === "signals" && ( -
    -
    - ▲ AI SIGNAL ENGINE — QUANT ADAPTER · KELLY-WEIGHTED · FIBONACCI-TARGETED -
    - {aiSigs.length === 0 && ( -
    Run a scan to generate AI signals
    - )} -
    - {aiSigs.map((s, i) => ( -
    -
    - {s.question} - {s.action} -
    -
    - EDGE: {pct(s.edge||0)} - CONF: {pct(s.confidence||0)} - KELLY: ${(s.kelly||0).toFixed(0)} -
    -
    - {s.tf||"—"} - {s.risk} - {s.fibLevel && φ {s.fibLevel}} -
    -
    // {s.thesis}
    -
    - ))} -
    -
    - )} - - {/* ════════════════ RISK DESK ═══════════════════════════════════ */} - {view === "risk" && ( -
    -
    - ◆ RISK DESK — KELLY CONFIG · MONTE CARLO · CIRCUIT BREAKERS -
    -
    - {/* Kelly Config */} -
    -
    KELLY CRITERION
    -
    -
    BANKROLL (USDC)
    - setBankroll(+e.target.value)} style={{ fontFamily:"'Fira Code',monospace", background:C.panel, border:`1px solid ${C.border}`, color:C.gold, padding:"8px 12px", outline:"none", borderRadius:6, width:"100%", fontSize:13 }} /> -
    -
    -
    - KELLY FRACTION - {(kFrac*100).toFixed(0)}% -
    - setKFrac(+e.target.value)} style={{ width:"100%", accentColor:C.gold }} /> -
    - ConservativeAggressive -
    -
    -
    - f* = (p·b − q) / b × {kFrac}
    - Max/trade: ${(bankroll*0.05).toFixed(0)} (5% cap)
    - Golden zone ×φ at 61.8% -
    -
    - {/* Monte Carlo preview */} -
    -
    MONTE CARLO — 500 PATHS
    - {markets[0]?.mc ? ( - <> - -
    - Ruin Rate: - 0.05?C.rose:C.green,fontWeight:600}}>{pct(markets[0].mc.ruin)} -
    -
    - Expectancy: - 0?C.green:C.rose,fontWeight:600}}>{markets[0].mc.exp>0?"+":""}${markets[0].mc.exp} -
    -
    Top market: {markets[0]?.question?.slice(0,40)}…
    - - ) :
    Run a scan to compute
    } -
    -
    - {/* Signal architecture */} -
    -
    COMPOSITE SIGNAL ARCHITECTURE
    -
    - {[ - ["Full Kelly Criterion","f*=(p·b−q)/b · ¼ fractional",C.gold], - ["Fibonacci + Golden Ratio","φ=1.618 · 6 levels · ×φ at 61.8%",C.gold], - ["Bayesian Probability","P(true|signal) via likelihood ratio",C.violet], - ["Bollinger Bands","20MA ± 2σ · %B position · squeeze",C.blue], - ["RSI-14","Overbought/oversold reversal signals",C.rose], - ["MACD Binary","EMA(12)−EMA(26) vs 9-period signal",C.green], - ["Gabagool Arb","YES+NO≠$1 → risk-free complete-set",C.violet], - ["Smart Ape Momentum","Price trend + volume acceleration",C.green], - ["Whale Radar","Vol/liq concentration detection",C.amber], - ["UMA Dispute Risk","Resolution ambiguity penalty",C.rose], - ["Monte Carlo Growth","500-path Kelly simulation",C.blue], - ["Sharpe + Sortino","Risk-adjusted quality scoring",C.green], - ].map(([name, formula, c]) => ( -
    -
    -
    -
    {name}
    -
    {formula}
    -
    -
    - ))} -
    -
    -
    - )} - - {/* ════════════════ ORDERS ══════════════════════════════════════ */} - {view === "orders" && ( -
    -
    -
    - ⊕ EXECUTION LOG — {paperMode ? "PAPER TRADING MODE" : "CLOB · EIP-712 SIGNED · POLYGON"} -
    - {paperMode && ( - 📊 VIEW-ONLY MODE - )} -
    - {orders.length === 0 && ( -
    - {paperMode - ? "No paper trades yet — click order buttons to simulate trades" - : "No orders yet — connect wallet and scan markets"} -
    - )} - {orders.length > 0 && ( -
    -
    - TIMEMARKETSIDESIZEPRICEEVGRSTATUS -
    - {orders.map((o, i) => ( -
    - {o.ts} - {o.market} - {o.side} - ${o.size} - {pct(o.price)} - 0?C.green:C.rose }}>{f3(o.ev)} - {o.grade} - - {o.status==="PAPER-FILLED"?"PAPER":o.status==="SIMULATED"?"PAPER":o.status} - -
    - ))} -
    - )} -
    - )} - - {/* ════════════════ WALLET ══════════════════════════════════════ */} - {view === "wallet" && ( -
    -
    - ◉ WALLET — ON-CHAIN POLYGON VERIFICATION · EIP-712 -
    -
    -
    POLYGON WALLET ADDRESS
    -
    - setWalInput(e.target.value)} onKeyDown={e=>e.key==="Enter"&&verifyWallet()} placeholder="0x…" style={{ flex:1, fontFamily:"'Fira Code',monospace", background:C.panel, border:`1px solid ${C.border}`, color:C.green, padding:"10px 14px", outline:"none", borderRadius:8, fontSize:12 }} /> - -
    - {walStatus === "checking" &&
    ◌ Querying Polygon RPC…
    } - {walStatus && walStatus !== "checking" && ( -
    - {walStatus.ok ? `✓ Verified · ${hsh(wallet)} · ${walStatus.bal?.toFixed(4)} POL` : `✗ ${walStatus.err}`} -
    - )} -
    -
    -
    POLYMARKET CLOB API CREDENTIALS
    - {["API KEY","API SECRET","PASSPHRASE"].map(l => ( -
    -
    {l}
    - -
    - ))} -
    -
    - ◆ EIP-712 SIGNING FLOW
    - 1. eth_getBalance → confirm address on Polygon
    - 2. L1 auth: sign(address + timestamp + nonce)
    - 3. Derive L2 credentials from signed message
    - 4. Orders signed locally — only signature transmitted
    - ⚠ Private keys NEVER stored or transmitted -
    -
    - )} - -
    -
    - - {/* ═══ TRADEHAX GPT CHAT PANEL ══════════════════════════════════════ */} - {chatPanelOpen && ( -
    - {/* Chat header */} -
    -
    -
    -
    TRADEHAX GPT
    -
    - Kelly · Fibonacci · Bayesian · Multi-TF -
    -
    -
    -
    - LIVE -
    -
    -
    - - {/* Messages */} -
    - {chatLog.map((m, i) => ( -
    -
    - {m.role === "assistant" && ( -
    - TRADEHAX GPT {m.ts && `· ${m.ts}`} -
    - )} -
    - {m.text.split(/(\*\*[^*]+\*\*)/g).map((part, j) => - part.startsWith("**") && part.endsWith("**") - ? {part.slice(2,-2)} - : part - )} -
    - {m.ts && m.role !== "assistant" && ( -
    {m.ts}
    - )} -
    -
    - ))} - {chatLoading && ( -
    -
    - Thinking… -
    -
    - )} -
    -
    - - {/* Quick prompts */} -
    - {["🎯 Best trade now","📐 Fibonacci read","⏱ Multi-TF","⚡ Arb ops","💰 Size my bet","📊 Risk check"].map(q => ( - - ))} -
    - - {/* Input */} -
    - setChatInput(e.target.value)} - onKeyDown={e => e.key==="Enter" && !chatLoading && sendChat()} - placeholder="Ask anything — markets, sizing, strategy…" - style={{ flex:1, fontFamily:"'DM Sans',sans-serif", background:C.panel, border:`1px solid ${C.borderL}`, color:C.text, padding:"10px 14px", outline:"none", borderRadius:20, fontSize:12 }} - /> - -
    -
    - )} -
    -
    - ); -} diff --git a/components/trading/PortfolioOverview.tsx b/components/trading/PortfolioOverview.tsx deleted file mode 100644 index 5bda148a..00000000 --- a/components/trading/PortfolioOverview.tsx +++ /dev/null @@ -1,274 +0,0 @@ -"use client"; - -/** - * PortfolioOverview — main portfolio dashboard component. - * Shows total value, asset table, allocation chart, and rebalance suggestions. - */ - -import { useState, useCallback } from "react"; -import { RefreshCw, Download, TrendingUp, TrendingDown } from "lucide-react"; -import { ExchangeConnector } from "./ExchangeConnector"; -import { AssetAllocationChart } from "./AssetAllocationChart"; -import { RebalanceSuggestions } from "./RebalanceSuggestions"; -import { usePortfolio } from "@/hooks/use-portfolio"; -import type { ExchangeConnection, PortfolioAsset } from "@/types/trading"; - -// ─── CSV helpers ────────────────────────────────────────────────────────────── - -/** Escape a value for RFC 4180 CSV (wrap in quotes, escape embedded quotes). */ -function csvCell(value: string | number): string { - const str = String(value); - if (/[",\n\r]/.test(str)) { - return `"${str.replace(/"/g, '""')}"`; - } - return str; -} - -function exportCSV(assets: PortfolioAsset[]) { - const headers = ["Symbol", "Exchange", "Quantity", "Price (USD)", "Value (USD)", "24h Change (%)", "Allocation (%)"]; - const rows = assets.map((a) => [ - a.symbol, - a.exchange, - a.quantity, - a.currentPrice.toFixed(2), - a.valueUsd.toFixed(2), - a.change24hPct.toFixed(2), - a.allocationPct.toFixed(2), - ]); - const csv = [headers, ...rows].map((r) => r.map(csvCell).join(",")).join("\n"); - const blob = new Blob([csv], { type: "text/csv" }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = `portfolio-${new Date().toISOString().split("T")[0]}.csv`; - a.click(); - URL.revokeObjectURL(url); -} - -// ─── Stat card ──────────────────────────────────────────────────────────────── - -function StatCard({ label, value, sub }: { label: string; value: string; sub?: string }) { - return ( -
    -

    {label}

    -

    {value}

    - {sub &&

    {sub}

    } -
    - ); -} - -// ─── Main component ─────────────────────────────────────────────────────────── - -const DEMO_CONNECTIONS: ExchangeConnection[] = [ - { - id: "demo-1", - exchange: "binance", - label: "Binance", - apiKey: "demo-key", - status: "connected", - lastSynced: new Date().toISOString(), - }, - { - id: "demo-2", - exchange: "coinbase", - label: "Coinbase", - apiKey: "demo-key", - status: "connected", - lastSynced: new Date().toISOString(), - }, -]; - -/** - * Full-featured portfolio dashboard with exchange connectivity and AI rebalancing. - */ -export function PortfolioOverview() { - const [connections, setConnections] = useState(DEMO_CONNECTIONS); - const [sortKey, setSortKey] = useState("valueUsd"); - const [sortDir, setSortDir] = useState<"asc" | "desc">("desc"); - const [activeTab, setActiveTab] = useState<"holdings" | "rebalance" | "connect">("holdings"); - - const { snapshot, loading, error, refresh, lastUpdated } = usePortfolio({ - connections, - pollIntervalMs: 120_000, - }); - - const handleSort = useCallback((key: keyof PortfolioAsset) => { - setSortKey((prev) => { - if (prev === key) setSortDir((d) => (d === "asc" ? "desc" : "asc")); - return key; - }); - }, []); - - const sortedAssets = snapshot - ? [...snapshot.assets].sort((a, b) => { - const va = a[sortKey] as number | string; - const vb = b[sortKey] as number | string; - if (typeof va === "number" && typeof vb === "number") { - return sortDir === "asc" ? va - vb : vb - va; - } - return sortDir === "asc" ? String(va).localeCompare(String(vb)) : String(vb).localeCompare(String(va)); - }) - : []; - - return ( -
    - {/* Header */} -
    -
    -

    Portfolio Dashboard

    - {lastUpdated && ( -

    - Updated {lastUpdated.toLocaleTimeString()} -

    - )} -
    -
    - - {snapshot && ( - - )} -
    -
    - - {/* Error state */} - {error && ( -
    - {error} -
    - )} - - {/* Stats */} - {snapshot && ( -
    - - = 0 ? "+" : ""}${snapshot.change24hPct.toFixed(2)}%`} - sub={`$${Math.abs(snapshot.change24hUsd).toFixed(2)}`} - /> - - c.status === "connected").length)} /> -
    - )} - - {/* Tabs */} -
    - {(["holdings", "rebalance", "connect"] as const).map((tab) => ( - - ))} -
    - - {/* Tab content */} - {activeTab === "holdings" && ( -
    - {/* Holdings table */} -
    - {loading && !snapshot ? ( -
    - {Array.from({ length: 5 }).map((_, i) => ( -
    - ))} -
    - ) : ( - - - - {(["symbol", "exchange", "quantity", "currentPrice", "valueUsd", "change24hPct", "allocationPct"] as const).map((col) => ( - - ))} - - - - {sortedAssets.map((asset, i) => ( - - - - - - - - - - ))} - {sortedAssets.length === 0 && ( - - - - )} - -
    handleSort(col)} - > - {col === "currentPrice" ? "Price" : col === "valueUsd" ? "Value" : col === "change24hPct" ? "24h %" : col === "allocationPct" ? "Alloc %" : col.charAt(0).toUpperCase() + col.slice(1)} - {sortKey === col && (sortDir === "asc" ? " ↑" : " ↓")} -
    - - {asset.symbol} - {asset.exchange}{asset.quantity.toFixed(6)}${asset.currentPrice.toLocaleString()}${asset.valueUsd.toLocaleString("en-US", { maximumFractionDigits: 2 })}= 0 ? "text-green-400" : "text-red-400"}`}> - {asset.change24hPct >= 0 ? ( - - ) : ( - - )} - {asset.change24hPct >= 0 ? "+" : ""}{asset.change24hPct.toFixed(2)}% - {asset.allocationPct.toFixed(1)}%
    - No holdings found. Add exchange connections to get started. -
    - )} -
    - - {/* Allocation chart */} - {snapshot && snapshot.assets.length > 0 && ( -
    -

    Allocation

    - -
    - )} -
    - )} - - {activeTab === "rebalance" && ( -
    - {snapshot ? ( - - ) : ( -

    Load portfolio to see rebalance suggestions.

    - )} -
    - )} - - {activeTab === "connect" && ( - - )} -
    - ); -} diff --git a/components/trading/RebalanceSuggestions.tsx b/components/trading/RebalanceSuggestions.tsx deleted file mode 100644 index b07c43c1..00000000 --- a/components/trading/RebalanceSuggestions.tsx +++ /dev/null @@ -1,69 +0,0 @@ -"use client"; - -/** - * RebalanceSuggestions — displays AI-driven rebalance recommendations. - */ - -import { ArrowUpRight, ArrowDownLeft, Zap } from "lucide-react"; -import type { RebalanceSuggestion } from "@/types/trading"; - -const PRIORITY_STYLE: Record = { - high: "border-red-500/40 bg-red-500/5", - medium: "border-yellow-500/40 bg-yellow-500/5", - low: "border-border/30 bg-muted/10", -}; - -const PRIORITY_BADGE: Record = { - high: "bg-red-500/20 text-red-400", - medium: "bg-yellow-500/20 text-yellow-400", - low: "bg-muted text-muted-foreground", -}; - -interface RebalanceSuggestionsProps { - suggestions: RebalanceSuggestion[]; -} - -/** - * Renders AI-generated rebalance suggestions with action indicators. - */ -export function RebalanceSuggestions({ suggestions }: RebalanceSuggestionsProps) { - if (suggestions.length === 0) { - return ( -
    - - Portfolio is well-balanced. No immediate rebalancing needed. -
    - ); - } - - return ( -
    - {suggestions.map((s) => ( -
    -
    - {s.action === "sell" ? ( - - ) : ( - - )} - - {s.action.toUpperCase()} {s.quantity.toFixed(4)} {s.symbol} - - on {s.exchange} - - ≈ ${s.estimatedValueUsd.toFixed(2)} - - - {s.priority} - -
    -

    {s.reasoning}

    -
    - ))} -
    - ); -} diff --git a/components/trading/SentimentFeed.tsx b/components/trading/SentimentFeed.tsx deleted file mode 100644 index 7d14301b..00000000 --- a/components/trading/SentimentFeed.tsx +++ /dev/null @@ -1,133 +0,0 @@ -"use client"; - -/** - * SentimentFeed — live scrolling list of sentiment events. - * Each event shows: source icon, text snippet, score badge, timestamp. - */ - -import type { SentimentEvent } from "@/types/trading"; -import { AnimatePresence, motion } from "framer-motion"; - -// ─── Source icons (emoji fallbacks; swap to Lucide if preferred) ────────────── - -const SOURCE_ICON: Record = { - twitter: "𝕏", - reddit: "🤖", - news: "📰", - "on-chain": "⛓️", - derivatives: "📊", -}; - -const SOURCE_LABEL: Record = { - twitter: "X / Twitter", - reddit: "Reddit", - news: "News", - "on-chain": "On-Chain", - derivatives: "Derivatives", -}; - -// ─── Score Badge ───────────────────────────────────────────────────────────── - -function ScoreBadge({ score }: { score: number }) { - const isPositive = score >= 20; - const isNegative = score <= -20; - const colorClass = isPositive - ? "bg-green-500/20 text-green-400 border-green-500/30" - : isNegative - ? "bg-red-500/20 text-red-400 border-red-500/30" - : "bg-yellow-500/20 text-yellow-400 border-yellow-500/30"; - - return ( - - {score > 0 ? `+${score}` : score} - - ); -} - -// ─── Single event row ───────────────────────────────────────────────────────── - -function EventRow({ event }: { event: SentimentEvent }) { - const relTime = (() => { - const diffMs = Date.now() - new Date(event.timestamp).getTime(); - const mins = Math.floor(diffMs / 60_000); - if (mins < 60) return `${mins}m ago`; - return `${Math.floor(mins / 60)}h ago`; - })(); - - return ( - - {/* Source icon */} -
    - {SOURCE_ICON[event.source]} -
    - - {/* Content */} -
    -
    - {event.symbol} - {SOURCE_LABEL[event.source]} - {relTime} -
    -

    {event.text}

    -
    - - {/* Score badge */} -
    - -
    -
    - ); -} - -// ─── Main Component ─────────────────────────────────────────────────────────── - -interface SentimentFeedProps { - events: SentimentEvent[]; - /** Maximum number of events to display (default 15). */ - maxEvents?: number; - className?: string; -} - -/** - * Live sentiment event feed with animated entry/exit. - * Displays the most recent events from multiple sources. - */ -export function SentimentFeed({ events, maxEvents = 15, className = "" }: SentimentFeedProps) { - const displayed = events.slice(0, maxEvents); - - if (displayed.length === 0) { - return ( -
    - No sentiment events available. -
    - ); - } - - return ( -
    - - {displayed.map((event) => ( - - ))} - -
    - ); -} diff --git a/components/trading/SentimentGauge.tsx b/components/trading/SentimentGauge.tsx deleted file mode 100644 index 82b88607..00000000 --- a/components/trading/SentimentGauge.tsx +++ /dev/null @@ -1,164 +0,0 @@ -"use client"; - -/** - * SentimentGauge — circular arc gauge with animated needle. - * Displays a -100 to +100 sentiment score with Fear & Greed styling. - */ - -import { motion } from "framer-motion"; -import { categoryColor, categoryLabel } from "@/lib/trading/sentiment-engine"; -import type { SentimentScore } from "@/types/trading"; - -// ─── SVG Arc Helpers ────────────────────────────────────────────────────────── - -const CX = 100; -const CY = 100; -const R = 80; -const START_ANGLE = -210; // degrees (left-most of the arc) -const END_ANGLE = 30; // degrees (right-most) -const TOTAL_SWEEP = END_ANGLE - START_ANGLE; // 240 degrees - -function degToRad(deg: number) { - return (deg * Math.PI) / 180; -} - -function polarToXY(angle: number, r: number) { - return { - x: CX + r * Math.cos(degToRad(angle)), - y: CY + r * Math.sin(degToRad(angle)), - }; -} - -function describeArc(startDeg: number, endDeg: number, r: number) { - const start = polarToXY(startDeg, r); - const end = polarToXY(endDeg, r); - const largeArc = endDeg - startDeg > 180 ? 1 : 0; - return `M ${start.x} ${start.y} A ${r} ${r} 0 ${largeArc} 1 ${end.x} ${end.y}`; -} - -/** Map score (-100→+100) to an arc angle. */ -function scoreToAngle(score: number): number { - const clamped = Math.max(-100, Math.min(100, score)); - const normalized = (clamped + 100) / 200; // 0 → 1 - return START_ANGLE + normalized * TOTAL_SWEEP; -} - -// ─── Gradient segments ──────────────────────────────────────────────────────── - -const GRADIENT_SEGMENTS = [ - { from: START_ANGLE, to: START_ANGLE + TOTAL_SWEEP * 0.2, color: "#ef4444" }, // extreme fear - { from: START_ANGLE + TOTAL_SWEEP * 0.2, to: START_ANGLE + TOTAL_SWEEP * 0.4, color: "#f97316" }, // fear - { from: START_ANGLE + TOTAL_SWEEP * 0.4, to: START_ANGLE + TOTAL_SWEEP * 0.6, color: "#eab308" }, // neutral - { from: START_ANGLE + TOTAL_SWEEP * 0.6, to: START_ANGLE + TOTAL_SWEEP * 0.8, color: "#84cc16" }, // greed - { from: START_ANGLE + TOTAL_SWEEP * 0.8, to: END_ANGLE, color: "#22c55e" }, // extreme greed -]; - -// ─── Component ──────────────────────────────────────────────────────────────── - -interface SentimentGaugeProps { - /** The asset or market sentiment to display. */ - data: SentimentScore; - /** Rendered size in px (default 200). */ - size?: number; - /** Show sub-score breakdown below gauge (default true). */ - showBreakdown?: boolean; -} - -/** - * Visual sentiment gauge using an SVG arc with animated needle. - * Color transitions from red (extreme fear) through yellow (neutral) to green (extreme greed). - */ -export function SentimentGauge({ data, size = 200, showBreakdown = true }: SentimentGaugeProps) { - const needleAngle = scoreToAngle(data.score); - const needleTip = polarToXY(needleAngle, R - 10); - const needleBase1 = polarToXY(needleAngle + 90, 8); - const needleBase2 = polarToXY(needleAngle - 90, 8); - - const colorClass = categoryColor(data.category); - const label = categoryLabel(data.category); - - return ( -
    - {/* Gauge SVG */} -
    - - {/* Track background */} - - - {/* Colored segments */} - {GRADIENT_SEGMENTS.map((seg, i) => ( - - ))} - - {/* Animated needle */} - - - {/* Center dot */} - - - {/* Score text */} - - {data.score > 0 ? `+${data.score}` : data.score} - - -
    - - {/* Category label */} -
    {label}
    -
    {data.symbol}
    - - {/* Sub-score breakdown */} - {showBreakdown && ( -
    - {[ - { label: "Social", value: data.socialScore }, - { label: "News", value: data.newsScore }, - { label: "On-Chain", value: data.onChainScore }, - ].map(({ label: l, value: v }) => ( -
    - {l} - - {v > 0 ? `+${v}` : v} - -
    - ))} -
    - )} -
    - ); -} diff --git a/components/trading/SignalExplainer.tsx b/components/trading/SignalExplainer.tsx deleted file mode 100644 index c31d2be8..00000000 --- a/components/trading/SignalExplainer.tsx +++ /dev/null @@ -1,161 +0,0 @@ -"use client"; - -/** - * SignalExplainer — full AI Explainability Panel (XAI). - * Collapsible sections showing confidence, factors, data, risk, and similar signals. - */ - -import { useState } from "react"; -import { ChevronDown, ChevronUp, Database, TrendingUp, Shield, History } from "lucide-react"; -import { ConfidenceMeter } from "./ConfidenceMeter"; -import { FactorBreakdown } from "./FactorBreakdown"; -import { SignalTimeline } from "./SignalTimeline"; -import type { SignalExplanation } from "@/types/trading"; - -// ─── Risk badge ─────────────────────────────────────────────────────────────── - -function RiskBadge({ level }: { level: SignalExplanation["riskLevel"] }) { - const styles = { - low: "bg-green-500/20 text-green-400 border-green-500/30", - medium: "bg-yellow-500/20 text-yellow-400 border-yellow-500/30", - high: "bg-red-500/20 text-red-400 border-red-500/30", - }; - return ( - - {level} Risk - - ); -} - -// ─── Collapsible section ────────────────────────────────────────────────────── - -function Section({ - title, - icon, - children, - defaultOpen = true, -}: { - title: string; - icon: React.ReactNode; - children: React.ReactNode; - defaultOpen?: boolean; -}) { - const [open, setOpen] = useState(defaultOpen); - return ( -
    - - {open &&
    {children}
    } -
    - ); -} - -// ─── Main component ─────────────────────────────────────────────────────────── - -interface SignalExplainerProps { - explanation: SignalExplanation; - className?: string; -} - -/** - * Renders a full XAI breakdown panel for a single trading signal. - */ -export function SignalExplainer({ explanation, className = "" }: SignalExplainerProps) { - const { - symbol, - action, - confidence, - factors, - dataPointsAnalyzed, - timeRangeAnalyzed, - dataSources, - historicalPerformance, - riskLevel, - riskReason, - naturalLanguageSummary, - similarSignals, - } = explanation; - - const actionColor = - action === "buy" ? "text-green-400" : action === "sell" ? "text-red-400" : "text-yellow-400"; - - return ( -
    - {/* Header */} -
    -
    - {symbol} - {action} -
    - -
    - - {/* Natural language summary */} -

    - {naturalLanguageSummary} -

    - - {/* Confidence */} -
    }> - -
    - - {/* Contributing factors */} -
    }> - -
    - - {/* Data points */} -
    } defaultOpen={false}> -
    -
    Data Points Analyzed
    -
    {dataPointsAnalyzed.toLocaleString()}
    -
    Time Range
    -
    {timeRangeAnalyzed}
    -
    Sources
    -
    {dataSources.join(", ")}
    -
    -
    - - {/* Historical accuracy */} -
    } defaultOpen={false}> -
    -
    Win Rate
    -
    {Math.round(historicalPerformance.winRate * 100)}%
    -
    Avg Return
    -
    = 0 ? "text-green-400" : "text-red-400"}`}> - {historicalPerformance.avgReturnPct >= 0 ? "+" : ""}{historicalPerformance.avgReturnPct}% -
    -
    Sample Size
    -
    {historicalPerformance.sampleSize} signals
    -
    Time Range
    -
    {historicalPerformance.timeRange}
    -
    -
    - - {/* Risk assessment */} -
    } defaultOpen={false}> -
    - -

    {riskReason}

    -
    -
    - - {/* Similar signals */} -
    } defaultOpen={false}> - -
    -
    - ); -} diff --git a/components/trading/SignalTimeline.tsx b/components/trading/SignalTimeline.tsx deleted file mode 100644 index 35b18c55..00000000 --- a/components/trading/SignalTimeline.tsx +++ /dev/null @@ -1,71 +0,0 @@ -"use client"; - -/** - * SignalTimeline — historical signal accuracy timeline. - * Shows similar past signals and their outcomes. - */ - -import type { SimilarSignal } from "@/types/trading"; -import { CheckCircle, Clock, XCircle } from "lucide-react"; - -interface SignalTimelineProps { - signals: SimilarSignal[]; -} - -const OUTCOME_ICON = { - win: , - loss: , - pending: , -}; - -/** - * Timeline of similar historical signals with outcome indicators. - */ -export function SignalTimeline({ signals }: SignalTimelineProps) { - if (signals.length === 0) { - return

    No similar signals found.

    ; - } - - return ( -
    - {/* Vertical line */} -