| name | architecture-reference |
| description | Quick reference for Portfolio Buddy 2 project structure. Use when: adding new features, modifying existing components, understanding data flow, or onboarding to the codebase. Contains component hierarchy, hook patterns, and utility functions. |
Portfolio Buddy 2 - Architecture Reference
Component Hierarchy
App.tsx (351 lines)
โโโ Header
โ โโโ App title and branding
โโโ UploadSection
โ โโโ File upload to Supabase
โ โโโ CSV parsing and validation
โ โโโ Error handling
โโโ ErrorList
โ โโโ Display parsing/validation errors
โโโ UploadedFilesList
โ โโโ List of successfully uploaded files
โโโ AnalyticsControls
โ โโโ Toggle Metrics view
โ โโโ Toggle Portfolio view
โ โโโ Toggle Correlation view
โโโ PortfolioSection (591 lines - NEEDS REFACTOR!)
โ โโโ usePortfolio hook (date filtering)
โ โโโ useContractMultipliers hook
โ โโโ Chart.js equity curves
โ โโโ Portfolio statistics
โ โโโ ContractInput components
โ โโโ MasterContractControl
โ โโโ MetricsTable integration
โโโ CorrelationSection
โ โโโ CorrelationHeatmap (Chart.js)
โ โโโ Spearman correlation
โ โโโ Pearson correlation
โโโ MetricsTable (242 lines)
โ โโโ useMetrics hook
โ โโโ useSorting hook (advanced multi-column)
โ โโโ SortableHeader components
โ โโโ Selection state management
โโโ SessionComplete
โโโ Completion UI/messaging
Key Hooks
useMetrics
Location: src/hooks/useMetrics.ts
Purpose: Calculate trading metrics from uploaded portfolio data
Features:
- Calculates Sharpe Ratio, Sortino Ratio, Max Drawdown, CAGR, Win Rate, etc.
- Memoized calculations for performance
- Handles empty/invalid data gracefully
Usage:
const { metrics, isCalculating } = useMetrics(portfolioData, riskFreeRate)
Returns:
metrics: Array of calculated metrics per strategy
isCalculating: Boolean loading state
Note: Contains 4 TypeScript any violations in sort comparisons (tech debt)
usePortfolio
Location: src/hooks/usePortfolio.ts
Purpose: Manage portfolio data with date range filtering
Features:
- Parses CSV trade data
- Filters by date range (start/end date)
- Builds equity curves
- Aggregates daily returns
Usage:
const {
portfolioData,
filteredData,
dateRange,
setDateRange
} = usePortfolio(uploadedFiles)
Recent Addition: Date range filtering (commit 258ba3a)
Note: Contains 11 TypeScript any violations in trade/metrics types (tech debt)
useContractMultipliers
Location: src/hooks/useContractMultipliers.ts
Purpose: Manage contract multipliers for futures trading
Features:
- Per-strategy contract size tracking
- Apply multipliers to metrics
- Master control to set all contracts at once
Usage:
const {
multipliers,
setMultiplier,
setAllMultipliers,
getAdjustedMetrics
} = useContractMultipliers(strategies)
useSorting
Location: src/hooks/useSorting.ts
Purpose: Advanced multi-column sorting for MetricsTable
Features:
- Sort by multiple columns with priority
- Toggle ascending/descending
- Custom comparison logic per data type
Usage:
const {
sortedData,
sortColumn,
sortDirection,
handleSort
} = useSorting(data, defaultColumn)
Utility Functions
dataUtils.ts
Location: src/utils/dataUtils.ts
Contains Core Functions:
CSV & Data Processing:
parseCSV(file) - Parse CSV file with PapaParse
processCurrencyColumns(data) - Clean currency values ($, commas)
parseFilenameComponents(filename) - Extract symbol/direction/strategy from filename
getDisplayName(symbol, direction, strategy) - Format display names
normalizeDate(date) - Normalize dates to midnight UTC
getDateKey(date) - Convert date to YYYY-MM-DD string key
Metric Calculations:
calculateMetrics(data, filename) - Calculate trade-level metrics for a strategy
- Net Profit, Gross Profit/Loss
- Profit Factor, Win Rate
- Average Win/Loss, Expected Value
- Max Drawdown (from equity curve)
- CAGR equivalent (annualGrowthRate)
- Total trades, winning/losing counts
- Note: Does NOT calculate Sharpe or Sortino (those are in PortfolioSection.tsx)
getAdjustedMetrics(metrics, multiplier) - Apply contract multiplier to metrics
Risk-Adjusted Metrics (PortfolioSection.tsx):
- Sharpe Ratio (line 533): Calculated inline as
(annualGrowthRate / 100) / (maxDrawdown / startingCapital)
- Sortino Ratio (lines 133-158): Calculated inline with downside deviation, uses risk-free rate state
Correlation Analysis:
buildCorrelationMatrix(strategies) - Build Spearman correlation matrix
calculatePearsonCorrelation(returns1, returns2) - Pearson correlation coefficient
calculateRanks(values) - Rank calculation for Spearman correlation
Trading Calculations:
getMarginRate(symbol) - Get margin requirements by symbol
calculateEquityCurve(trades) - Build cumulative equity curve
calculateDailyReturns(equity) - Calculate daily returns from equity curve
Formatting:
formatNumber(value, decimals) - Format numbers with decimals
formatCurrency(value) - Format as currency ($X,XXX.XX)
formatPercent(value) - Format as percentage (X.XX%)
Note: Contains 1 TypeScript any violation in Metrics interface (tech debt)
Data Flow
Upload & Processing Flow
1. User uploads CSV via UploadSection
โ
2. parseCSV() extracts trade data
โ
3. processCurrencyColumns() cleans data
โ
4. File uploaded to Supabase storage
โ
5. usePortfolio hook fetches and aggregates data
โ
6. Date range filter applied (if set)
โ
7. useMetrics calculates all metrics
โ
8. MetricsTable displays results
Contract Multiplier Flow
1. User inputs contract size in ContractInput
โ
2. useContractMultipliers stores value
โ
3. getAdjustedMetrics() applies multiplier
โ
4. Adjusted metrics shown in MetricsTable
โ
5. Portfolio charts update with adjusted values
Sorting Flow
1. User clicks SortableHeader
โ
2. useSorting updates sort column/direction
โ
3. Custom comparison logic applied
โ
4. MetricsTable re-renders with sorted data
Correlation Flow
1. User selects assets in MetricsTable
โ
2. Selection state passed to CorrelationSection
โ
3. buildCorrelationMatrix() calculates correlations
โ
4. CorrelationHeatmap renders Chart.js heatmap
โ
5. Spearman & Pearson correlations both shown
State Management
Plain React Hooks (No Zustand/TanStack Query)
- Local component state โ
useState
- Derived state โ
useMemo
- Stable callbacks โ
useCallback
- Refs for values โ
useRef
Example Pattern:
const [data, setData] = useState<Trade[]>([])
const metrics = useMemo(() => calculateMetrics(data), [data])
const handleUpload = useCallback((file: File) => {
}, [])
No Global State Library
- Props passed down component tree
- Custom hooks encapsulate shared logic
- No Redux, Zustand, or Jotai
Adding New Features
New Metric Calculation
- Add calculation logic to
dataUtils.calculateMetrics()
- Update return type in
calculateMetrics()
- Add column to
MetricsTable.tsx
- Update sort logic in
useSorting.ts if needed
- Test with sample data
Example: Sortino Ratio was added in commits 258ba3a & 9f25040
New Chart Component
- Create component in
src/components/
- Use Chart.js (NOT Recharts - it's unused)
- Import chart type and plugins needed:
import { Line } from 'react-chartjs-2'
import { Chart, registerables } from 'chart.js'
import zoomPlugin from 'chartjs-plugin-zoom'
- Hook into
useMetrics or usePortfolio for data
- Add to appropriate section in
App.tsx
New Hook
- Create in
src/hooks/use[Feature].ts
- Follow naming convention:
use prefix, camelCase
- Return object with clear property names
- Use TypeScript for all types (avoid
any)
- Add JSDoc comments for complex logic
Chart.js Architecture
Current Setup
- Library: Chart.js 4.x (NOT Recharts)
- React Wrapper: react-chartjs-2
- Plugins Used:
- chartjs-plugin-zoom (pan & zoom)
- chartjs-plugin-annotation (trend lines, markers)
- chartjs-adapter-date-fns (time scales)
Where Charts Are Used
- PortfolioSection: Equity curve line charts
- CorrelationHeatmap: Correlation matrix heatmap
- CustomTooltip: Shared tooltip component for charts
Recharts Note
โ ๏ธ Recharts is installed but NEVER imported - should be removed (11.5KB waste)
Component Size Guidelines
Target: 200 Lines Max
Current Violations:
- โ PortfolioSection.tsx: 591 lines (295% of limit) - HIGH PRIORITY REFACTOR
- โ App.tsx: 351 lines (175% of limit)
- โ MetricsTable.tsx: 242 lines (121% of limit) - improved from 350
Refactoring Strategy
For PortfolioSection (591 lines):
- Extract equity chart into
EquityChartSection.tsx
- Extract statistics into
PortfolioStats.tsx
- Extract contract controls into
ContractControls.tsx
- Keep only orchestration logic in main component
TypeScript Patterns
Interfaces for Data Structures
interface Trade {
date: Date
symbol: string
pnl: number
}
interface Metric {
name: string
sharpe: number
sortino: number
}
Avoid any Types
Current violations (15 total) - see portfolio-context skill for details
Preferred approach:
const data: any = parseData()
interface ParsedData {
trades: Trade[]
errors: string[]
}
const data: ParsedData = parseData()
Performance Patterns
Memoization with useMemo
const correlationMatrix = useMemo(
() => buildCorrelationMatrix(selectedStrategies),
[selectedStrategies]
)
Stable Callbacks with useCallback
const handleSort = useCallback((column: string) => {
setSortColumn(column)
setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc')
}, [])
Avoid Premature Optimization
- Build features first
- Profile if performance issues arise
- Optimize based on data, not assumptions