Skip to main content
The Trade History view provides a comprehensive table of all your executed trades with powerful filtering and analysis tools.

Overview

Trade History is accessible from:
  • Home Analytics: Scrollable table below analytics cards
  • Wallet Lookup: After fetching trades from blockchain
Trade History Table

Table Features

Columns Displayed

src/lib/types.ts
export interface Trade {
    id: string;
    symbol: string;              // e.g., "SOL-PERP", "BTC-USDC"
    quoteCurrency: string;        // "USDC"
    side: 'buy' | 'sell' | 'long' | 'short';
    orderType: OrderType;         // 'limit' | 'market' | 'stop_limit' | 'stop_market'
    quantity: number;             // Position size
    price: number;                // Execution price
    notional: number;             // Total value (price × quantity)
    pnl: number;                  // Profit/Loss in USDC
    fee: number;                  // Total fees paid
    feeCurrency: string;          // "USDC"
    openedAt: Date;               // Trade entry time
    closedAt: Date;               // Trade exit time
    durationSeconds: number;      // How long the position was held
    isWin: boolean;               // True if pnl > 0
    txSignature: string;          // Solana transaction signature

    // Fee breakdown
    feeBreakdown?: FeeComposition[];
    isMaker?: boolean;            // Maker vs. Taker order

    // Leverage fields (for perpetuals)
    leverage?: number;            // 1x, 2x, 3x, 5x, 8x, 10x
    liquidationPrice?: number;    // Liquidation threshold
    marginUsed?: number;          // Collateral used
}
Visible columns:
  • Time (formatted timestamp)
  • Symbol (token pair)
  • Side (Buy/Sell/Long/Short with color coding)
  • Order Type (Limit, Market, Stop)
  • Price
  • Quantity
  • Notional Value
  • PnL (color-coded: green for profit, red for loss)
  • Fees
  • Duration
  • Leverage (perps only)
  • Transaction Signature (clickable link to Solscan)

Color Coding

src/components/features/DeriverseTradesTable.tsx
// PnL Color Coding
<td className={`px-6 py-4 whitespace-nowrap text-sm font-semibold ${
    trade.pnl >= 0 ? 'text-green-400' : 'text-red-400'
}`}>
    {trade.pnl >= 0 ? '+' : ''}${trade.pnl.toFixed(2)}
</td>

// Side Color Coding
<td className="px-6 py-4 whitespace-nowrap">
    <span className={`px-3 py-1.5 rounded-none text-xs font-semibold ${
        trade.side === 'long' || trade.side === 'buy'
            ? 'bg-green-500/20 text-green-300 border border-green-500/30'
            : 'bg-red-500/20 text-red-300 border border-red-500/30'
    }`}>
        {trade.side.toUpperCase()}
    </span>
</td>

Date Filtering

Filter trades by time period using the top bar:
src/lib/tradeFilters.ts
export type FilterType = 'All' | 'Yesterday' | 'Today' | 'This Week' | 'This Month' | 'This Year';

export function filterTradesByDate(trades: Trade[], filter: FilterType): Trade[] {
    const now = new Date();

    switch (filter) {
        case 'Today':
            return trades.filter(t => isToday(t.closedAt));

        case 'Yesterday':
            return trades.filter(t => isYesterday(t.closedAt));

        case 'This Week':
            // Last 7 days (rolling)
            const sevenDaysAgo = startOfDay(subDays(now, 7));
            return trades.filter(t => t.closedAt >= sevenDaysAgo);

        case 'This Month':
            // Last 30 days (rolling)
            const thirtyDaysAgo = startOfDay(subDays(now, 30));
            return trades.filter(t => t.closedAt >= thirtyDaysAgo);

        case 'This Year':
            // Last 365 days (rolling)
            const yearAgo = startOfDay(subDays(now, 365));
            return trades.filter(t => t.closedAt >= yearAgo);

        case 'All':
        default:
            return trades;
    }
}
Available filters:
  • Today: Trades executed today
  • Yesterday: Trades from previous day
  • This Week: Last 7 days (rolling window)
  • This Month: Last 30 days (rolling window)
  • This Year: Last 365 days (rolling window)
  • All: Complete trade history
Time filters use rolling windows, not calendar periods. “This Week” means the last 7 days from today.

Custom Date Range

src/components/features/Home.tsx
const handleApplyFilters = () => {
    setAppliedDateRange(draftDateRange);
    setAppliedSelectedPairs(draftSelectedPairs);
    setActiveFilter(undefined); // No filter active when date range is applied
};

// Filter trades based on active filter
const filteredTrades = useMemo(() => {
    let trades;

    if (activeFilter && activeFilter !== 'All') {
        // Use quick filter, ignore date range completely
        trades = filterTradesByDate(displayTrades, activeFilter);
    } else {
        // Use date range if applied, otherwise show all trades
        trades = displayTrades;
        if (appliedDateRange?.from) {
            const from = startOfDay(appliedDateRange.from);
            trades = trades.filter((t) => t.closedAt >= from);
        }
        if (appliedDateRange?.to) {
            const to = endOfDay(appliedDateRange.to);
            trades = trades.filter((t) => t.closedAt <= to);
        }
    }

    if (appliedSelectedPairs.length > 0) {
        trades = trades.filter((t) => appliedSelectedPairs.includes(t.symbol));
    }

    return trades;
}, [activeFilter, appliedDateRange, appliedSelectedPairs, displayTrades]);
Use the calendar picker to select a custom start and end date. Click Apply to filter.
Custom date ranges override quick filters. To return to quick filters, clear the date range.

Trading Pair Selection

Filter by specific tokens:
src/components/features/Home.tsx
const availablePairs = useMemo(() => {
    const symbols = new Set<string>();
    for (const t of displayTrades) symbols.add(t.symbol);
    return Array.from(symbols).sort((a, b) => a.localeCompare(b));
}, [displayTrades]);

<TopBar
    activeFilter={activeFilter}
    onFilterChange={handleFilterChange}
    dateRange={draftDateRange}
    onDateRangeChange={setDraftDateRange}
    availablePairs={availablePairs}
    selectedPairs={draftSelectedPairs}
    onSelectedPairsChange={setDraftSelectedPairs}
    onApply={handleApplyFilters}
/>
How it works:
  1. Deriverse scans all trades and extracts unique symbols
  2. Symbols are sorted alphabetically
  3. Select multiple pairs to compare performance
  4. Click Apply to filter the table
Available pairs (based on src/lib/mockData.ts:17):
  • SOL-USDC / SOL-PERP
  • BTC-USDC / BTC-PERP
  • ETH-USDC / ETH-PERP
  • JUP-USDC / JUP-PERP
  • JTO-USDC / JTO-PERP
  • BONK-USDC / BONK-PERP
  • WIF-USDC / WIF-PERP
  • RNDR-USDC / RNDR-PERP

Search Functionality

Quickly find specific trades by:
  • Transaction signature
  • Symbol/pair name
  • Date/time
Search is currently in development. For now, use the browser’s built-in find (Ctrl+F / Cmd+F) to search within the visible table.

Export Capabilities

Export filtered trade data to CSV:
function exportTradesToCSV(trades: Trade[]) {
    const headers = [
        'Date',
        'Symbol',
        'Side',
        'Order Type',
        'Quantity',
        'Price',
        'Notional',
        'PnL',
        'Fees',
        'Duration (sec)',
        'Leverage',
        'Tx Signature'
    ];

    const rows = trades.map(t => [
        format(t.closedAt, 'yyyy-MM-dd HH:mm:ss'),
        t.symbol,
        t.side,
        t.orderType,
        t.quantity,
        t.price,
        t.notional,
        t.pnl,
        t.fee,
        t.durationSeconds,
        t.leverage || 'N/A',
        t.txSignature
    ]);

    const csv = [headers, ...rows]
        .map(row => row.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 = `deriverse-trades-${format(new Date(), 'yyyy-MM-dd')}.csv`;
    a.click();
}
Export includes:
  • All visible columns
  • Respects active filters (date, pairs, etc.)
  • Formatted timestamps
  • Transaction signatures for verification
Export trades after filtering to create focused datasets for external analysis in Excel or Google Sheets.

Transaction Verification

Every trade includes a clickable transaction signature:
<a
    href={`https://solscan.io/tx/${trade.txSignature}?cluster=devnet`}
    target="_blank"
    rel="noopener noreferrer"
    className="text-blue-400 hover:text-blue-300 transition-colors font-mono group-hover:underline"
>
    {trade.txSignature.slice(0, 8)}...{trade.txSignature.slice(-8)}
</a>
Click the signature to:
  • View on-chain transaction details on Solscan
  • Verify trade execution
  • Inspect instruction logs
  • Confirm fees and token transfers
All trades are verifiable on the Solana blockchain. Deriverse never invents or modifies trade data.

Trade Card View (Mobile)

On smaller screens, trades display as cards instead of a table:
src/components/features/TradeCard.tsx
<div className="glass-morphism border border-white/10 overflow-hidden hover:border-white/20 transition-all">
    <div className="p-4 space-y-3">
        <div className="flex items-center justify-between">
            <div className="flex items-center gap-2">
                <span className="text-white font-mono text-sm">{trade.symbol}</span>
                <span className={`px-2 py-0.5 text-[10px] font-bold ${
                    trade.side === 'long' || trade.side === 'buy'
                        ? 'bg-green-500/20 text-green-400'
                        : 'bg-red-500/20 text-red-400'
                }`}>
                    {trade.side.toUpperCase()}
                </span>
            </div>
            <span className="text-white/40 text-xs">
                {format(trade.closedAt, 'MMM dd, HH:mm')}
            </span>
        </div>
        
        <div className="flex justify-between items-baseline">
            <span className="text-white/60 text-xs">PnL</span>
            <span className={`text-lg font-bold ${
                trade.pnl >= 0 ? 'text-green-400' : 'text-red-400'
            }`}>
                {trade.pnl >= 0 ? '+' : ''}${trade.pnl.toFixed(2)}
            </span>
        </div>
    </div>
</div>
Trade cards are optimized for touch interfaces and display the most important info at a glance.

Performance Optimization

For large trade histories, Deriverse uses:

Pagination

const ITEMS_PER_PAGE = 50;
const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
const endIndex = startIndex + ITEMS_PER_PAGE;
const paginatedTrades = filteredTrades.slice(startIndex, endIndex);

Virtualization (planned)

For 1000+ trades, virtual scrolling will render only visible rows.

Memoization

const filteredTrades = useMemo(() => {
    let trades = displayTrades;
    
    if (activeFilter) {
        trades = filterTradesByDate(trades, activeFilter);
    }
    
    if (appliedSelectedPairs.length > 0) {
        trades = trades.filter(t => appliedSelectedPairs.includes(t.symbol));
    }
    
    return trades;
}, [activeFilter, appliedSelectedPairs, displayTrades]);
Expensive filtering operations are cached and only recalculate when dependencies change.

Next Steps

Analytics Dashboard

See aggregated metrics from your trade history

Data Modes

Learn about mock data vs. real blockchain data

Build docs developers (and LLMs) love