The Analytics Dashboard is your central hub for understanding trading performance on Solana. It provides real-time insights into profitability, risk metrics, trading behavior, and fee analysis.
Track your trading success with comprehensive win rate statistics:
export function calculateWinRate ( trades : Trade []) {
if ( trades . length === 0 ) {
return { winRate: '0' , wins: 0 , losses: 0 };
}
const wins = trades . filter ( t => t . isWin ). length ;
const losses = trades . length - wins ;
const winRate = (( wins / trades . length ) * 100 ). toFixed ( 1 );
return { winRate , wins , losses };
}
What you’ll see:
Overall win rate percentage
Win/loss breakdown (e.g., “145W / 95L”)
Period-over-period comparison
A win rate above 50% indicates positive trading performance, but always consider it alongside average win/loss size.
Average Win vs. Average Loss
Understand the quality of your trades beyond just win rate:
export function calculateAvgWin ( trades : Trade []) : number {
const winningTrades = trades . filter ( t => t . isWin );
if ( winningTrades . length === 0 ) return 0 ;
const totalWinPnL = winningTrades . reduce (( sum , t ) => sum + t . pnl , 0 );
return totalWinPnL / winningTrades . length ;
}
export function calculateAvgLoss ( trades : Trade []) : number {
const losingTrades = trades . filter ( t => t . pnl < 0 );
if ( losingTrades . length === 0 ) return 0 ;
const totalLossPnL = losingTrades . reduce (( sum , t ) => sum + t . pnl , 0 );
return totalLossPnL / losingTrades . length ;
}
Key Insight: A positive profit factor means your average win is larger than your average loss, which is crucial for long-term profitability.
PnL Chart & Equity Curve
Visualize your cumulative performance over time:
Features:
Daily PnL aggregation from src/lib/mockData.ts:231
Color-coded bars (green for profits, red for losses)
Cumulative equity curve overlay
Drawdown visualization toggle
export function calculateDailyPnL ( trades : Trade []) : DailyPnL [] {
const dailyMap = new Map < string , DailyPnL >();
trades . forEach ( trade => {
const dateKey = format ( startOfDay ( trade . closedAt ), 'yyyy-MM-dd' );
if ( ! dailyMap . has ( dateKey )) {
dailyMap . set ( dateKey , {
date: dateKey ,
pnl: 0 ,
trades: 0 ,
wins: 0 ,
losses: 0 ,
});
}
const daily = dailyMap . get ( dateKey ) ! ;
daily . pnl += trade . pnl ;
daily . trades += 1 ;
if ( trade . isWin ) daily . wins += 1 ;
else daily . losses += 1 ;
});
return Array . from ( dailyMap . values ()). sort (( a , b ) => a . date . localeCompare ( b . date ));
}
Toggle “Show Drawdown on Chart” to visualize periods where your equity was below its peak value.
Fee Breakdown Analysis
Understand exactly where your trading fees go:
export function calculateFeeBreakdown ( trades : Trade []) : FeeComposition [] {
const protocolMaker = trades
. filter ( t => t . isMaker )
. reduce (( sum , t ) => sum + ( t . feeBreakdown ?.[ 0 ]?. amount || 0 ), 0 );
const protocolTaker = trades
. filter ( t => ! t . isMaker )
. reduce (( sum , t ) => sum + ( t . feeBreakdown ?.[ 0 ]?. amount || 0 ), 0 );
const network = trades
. reduce (( sum , t ) => sum + ( t . feeBreakdown ?.[ 1 ]?. amount || 0 ), 0 );
const total = protocolMaker + protocolTaker + network ;
return [
{
type: 'Protocol (Maker)' ,
amount: protocolMaker ,
percent: total > 0 ? ( protocolMaker / total ) * 100 : 0 ,
},
{
type: 'Protocol (Taker)' ,
amount: protocolTaker ,
percent: total > 0 ? ( protocolTaker / total ) * 100 : 0 ,
},
{
type: 'Network' ,
amount: network ,
percent: total > 0 ? ( network / total ) * 100 : 0 ,
},
];
}
Fee Categories:
Protocol (Maker) : Fees paid when providing liquidity (0.025% default)
Protocol (Taker) : Fees paid when taking liquidity (0.05% default)
Network : Solana transaction fees
High taker fees can significantly impact profitability. Consider using limit orders to qualify for maker rates.
Long/Short Ratio
Analyze your directional bias in perpetual trading:
export function calculateLongShortRatio ( trades : Trade []) {
const perpTrades = trades . filter ( t => t . side === 'long' || t . side === 'short' );
if ( perpTrades . length === 0 ) {
return { longPercent: 50 , shortPercent: 50 , longCount: 0 , shortCount: 0 };
}
const longCount = perpTrades . filter ( t => t . side === 'long' ). length ;
const shortCount = perpTrades . filter ( t => t . side === 'short' ). length ;
const longPercent = Math . round (( longCount / perpTrades . length ) * 100 );
const shortPercent = 100 - longPercent ;
return { longPercent , shortPercent , longCount , shortCount };
}
Displayed as:
Long: 62% (148 trades)
Short: 38% (92 trades)
A balanced long/short ratio indicates market-neutral trading, while heavy directional bias may expose you to market trend risk.
Leverage Analysis
Track leverage usage across perpetual positions:
export function calculateAverageLeverage ( trades : Trade []) : number {
const perpTrades = trades . filter ( t => t . leverage !== undefined );
if ( perpTrades . length === 0 ) return 1 ;
const totalLeverage = perpTrades . reduce (( sum , t ) => sum + ( t . leverage || 1 ), 0 );
return totalLeverage / perpTrades . length ;
}
export function calculateLeverageVsWinRate ( trades : Trade []) {
const leverageMap = new Map < number , { wins : number ; total : number }>();
trades
. filter ( t => t . leverage !== undefined )
. forEach ( trade => {
const lev = trade . leverage ! ;
if ( ! leverageMap . has ( lev )) {
leverageMap . set ( lev , { wins: 0 , total: 0 });
}
const data = leverageMap . get ( lev ) ! ;
data . total += 1 ;
if ( trade . isWin ) data . wins += 1 ;
});
return Array . from ( leverageMap . entries ())
. map (([ leverage , data ]) => ({
leverage ,
winRate: data . total > 0 ? data . wins / data . total : 0 ,
trades: data . total ,
}))
. sort (( a , b ) => a . leverage - b . leverage );
}
Insights provided:
Average leverage across all perp trades
Win rate distribution by leverage level (1x, 2x, 3x, 5x, 8x, 10x)
Risk exposure per leverage tier
Higher leverage amplifies both gains and losses. The analytics show if your win rate decreases at higher leverage levels.
Identify when you trade most profitably:
Session Analysis
export function calculateSessionPerformance ( trades : Trade []) : SessionBucket [] {
const sessions : Record < string , { pnl : number ; trades : number ; wins : number }> = {
morning: { pnl: 0 , trades: 0 , wins: 0 },
afternoon: { pnl: 0 , trades: 0 , wins: 0 },
evening: { pnl: 0 , trades: 0 , wins: 0 },
night: { pnl: 0 , trades: 0 , wins: 0 },
};
trades . forEach ( trade => {
const hour = trade . closedAt . getHours ();
let session : 'morning' | 'afternoon' | 'evening' | 'night' ;
if ( hour >= 6 && hour < 12 ) session = 'morning' ;
else if ( hour >= 12 && hour < 18 ) session = 'afternoon' ;
else if ( hour >= 18 && hour < 22 ) session = 'evening' ;
else session = 'night' ;
sessions [ session ]. pnl += trade . pnl ;
sessions [ session ]. trades += 1 ;
if ( trade . isWin ) sessions [ session ]. wins += 1 ;
});
return Object . entries ( sessions ). map (([ session , data ]) => ({
session: session as 'morning' | 'afternoon' | 'evening' | 'night' ,
pnl: data . pnl ,
trades: data . trades ,
winRate: data . trades > 0 ? data . wins / data . trades : 0 ,
}));
}
Time Periods:
Morning: 6:00 AM - 12:00 PM
Afternoon: 12:00 PM - 6:00 PM
Evening: 6:00 PM - 10:00 PM
Night: 10:00 PM - 6:00 AM
Use this data to identify your most profitable trading hours and avoid sessions where you consistently underperform.
Time Filters
Analyze performance across different timeframes:
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, Yesterday, This Week (7 days), This Month (30 days), This Year (365 days), All
Trading Volume
Monitor your total market activity:
export function calculateTradingVolume ( trades : Trade []) : number {
return trades . reduce (( sum , t ) => sum + t . notional , 0 );
}
export function formatCompactNumber ( value : number ) : string {
const absValue = Math . abs ( value );
const sign = value >= 0 ? '' : '-' ;
if ( absValue >= 1_000_000 ) {
return ` ${ sign } $ ${ ( absValue / 1_000_000 ). toFixed ( 2 ) } M` ;
} else if ( absValue >= 1_000 ) {
return ` ${ sign } $ ${ ( absValue / 1_000 ). toFixed ( 2 ) } K` ;
} else {
return ` ${ sign } $ ${ absValue . toFixed ( 2 ) } ` ;
}
}
Displayed as: 1.23 M , 1.23M, 1.23 M , 456.78K, or $12.34 depending on magnitude
Higher trading volume doesn’t always mean better performance. Focus on profitability per trade.
Next Steps
Trade Journaling Add notes and lessons learned to your trades
Trade History Explore detailed trade-by-trade history