Marketplace architecture-reference
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.
git clone https://github.com/aiskillstore/marketplace
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/5minfutures/architecture-reference" ~/.claude/skills/aiskillstore-marketplace-architecture-reference && rm -rf "$T"
skills/5minfutures/architecture-reference/SKILL.mdPortfolio 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:
: Array of calculated metrics per strategymetrics
: Boolean loading stateisCalculating
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:
- Parse CSV file with PapaParseparseCSV(file)
- Clean currency values ($, commas)processCurrencyColumns(data)
- Extract symbol/direction/strategy from filenameparseFilenameComponents(filename)
- Format display namesgetDisplayName(symbol, direction, strategy)
- Normalize dates to midnight UTCnormalizeDate(date)
- Convert date to YYYY-MM-DD string keygetDateKey(date)
Metric Calculations:
- Calculate trade-level metrics for a strategycalculateMetrics(data, filename)- 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)
- Apply contract multiplier to metricsgetAdjustedMetrics(metrics, multiplier)
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:
- Build Spearman correlation matrixbuildCorrelationMatrix(strategies)
- Pearson correlation coefficientcalculatePearsonCorrelation(returns1, returns2)
- Rank calculation for Spearman correlationcalculateRanks(values)
Trading Calculations:
- Get margin requirements by symbolgetMarginRate(symbol)
- Build cumulative equity curvecalculateEquityCurve(trades)
- Calculate daily returns from equity curvecalculateDailyReturns(equity)
Formatting:
- Format numbers with decimalsformatNumber(value, decimals)
- Format as currency ($X,XXX.XX)formatCurrency(value)
- Format as percentage (X.XX%)formatPercent(value)
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) => { // upload logic }, [])
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
if neededuseSorting.ts - 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
oruseMetrics
for datausePortfolio - Add to appropriate section in
App.tsx
New Hook
- Create in
src/hooks/use[Feature].ts - Follow naming convention:
prefix, camelCaseuse - 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
anyCurrent violations (15 total) - see portfolio-context skill for details
Preferred approach:
// Bad const data: any = parseData() // Good interface ParsedData { trades: Trade[] errors: string[] } const data: ParsedData = parseData()
Performance Patterns
Memoization with useMemo
// Expensive correlation calculation 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