← Back
β˜†
import { useState, useEffect, useCallback } from 'react';

export interface WhaleConsensus {
  marketId: string;
  question: string | null;
  slug: string | null;
  whales: number;       // distinct whales trading this market
  trades: number;
  netSide: 'Yes' | 'No';
  netFlowUsd: number;   // |yes_flow - no_flow|
  totalUsd: number;     // yes_flow + no_flow
  agreement: number;    // 0.5 = split, 1.0 = unanimous
  avgPrice: number;     // 0..1 volume-weighted entry of the dominant side
  currentPrice: number | null; // 0..1 current market price of the dominant side
  lastTradeAt: string | null;  // ISO timestamp of the most recent whale trade
}

interface Options {
  days?: number;
  minAmount?: number;
  limit?: number;
}

export function useWhaleConsensus(options: Options = {}) {
  const { days = 7, minAmount = 5000, limit = 40 } = options;
  const [rows, setRows] = useState<WhaleConsensus[]>([]);
  const [loading, setLoading] = useState(true);

  const fetchConsensus = useCallback(async () => {
    setLoading(true);
    try {
      const params = new URLSearchParams({
        days: String(days),
        min_amount: String(minAmount),
        limit: String(limit),
      });
      const res = await fetch(`/api/signals/whales/consensus?${params}`);
      const d = await res.json();
      if (d.success) setRows(d.data ?? []);
    } catch { /* ignore */ }
    finally { setLoading(false); }
  }, [days, minAmount, limit]);

  useEffect(() => {
    const t = setTimeout(fetchConsensus, 0);
    const interval = setInterval(fetchConsensus, 5 * 60_000);
    return () => { clearTimeout(t); clearInterval(interval); };
  }, [fetchConsensus]);

  return { rows, loading, refresh: fetchConsensus };
}

πŸ“œ Git History

f5cc0aefeat(poli): Flow consensus chunk 2 — entry→now delta, freshness, sort, filters4 days ago
6c47fa4chore: local Polikopi project home + Phase 1 redesign artifacts12 days ago
Show last diff
Loading...