Skip to content

AnthonyM5/next-platform-chart

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

244 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“Š Cryptocurrency Dashboard

A modern, production-ready cryptocurrency tracking dashboard built with Next.js 16, TypeScript, and Chart.js. Features real-time price tracking, interactive charts, and professional-grade technical indicators.

TypeScript Next.js Chart.js

✨ Features

Core Functionality

  • Real-time Data β€” Live cryptocurrency prices from CoinGecko API with auto-refresh
  • Interactive Charts β€” Price history with customizable time periods (24h, 7d, 30d, 1y)
  • Technical Indicators β€” RSI, SMA, MACD, and Bollinger Bands
  • Dark/Light Mode β€” Seamless theme switching with system preference detection
  • Favorites Watchlist β€” Persistent favorites saved to localStorage
  • Fully Responsive β€” Optimized for desktop, tablet, and mobile

Technical Indicators

  • RSI (Relative Strength Index) β€” Momentum oscillator with dynamic periods
  • SMA (Simple Moving Average) β€” Short and long-term trend analysis
  • MACD (Moving Average Convergence Divergence) β€” Trend-following momentum
  • Bollinger Bands β€” Volatility and price level visualization

πŸš€ Quick Start

# Install dependencies
npm install

# Run development server
npm run dev

# Open in browser
http://localhost:3000/crypto

πŸ“ Project Structure

app/crypto/
β”œβ”€β”€ api/
β”‚   β”œβ”€β”€ coins/route.ts           # Cryptocurrency list endpoint
β”‚   β”œβ”€β”€ coin-history/route.ts    # Historical price data
β”‚   └── search/route.ts          # Search endpoint
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ CryptoDashboard.tsx      # Main dashboard container
β”‚   β”œβ”€β”€ CryptoTable.tsx          # Table/Grid view
β”‚   β”œβ”€β”€ CryptoChart.tsx          # Price chart with indicators
β”‚   β”œβ”€β”€ StudiesDropdown.tsx      # Technical indicator selector
β”‚   β”œβ”€β”€ ThemeToggle.tsx          # Dark/Light mode
β”‚   β”œβ”€β”€ TimePeriodSelector.tsx   # Time period buttons
β”‚   β”œβ”€β”€ ViewModeToggle.tsx       # Table/Grid toggle
β”‚   β”œβ”€β”€ LoadingSkeleton.tsx      # Loading states
β”‚   └── ErrorBoundary.tsx        # Error handling
β”œβ”€β”€ store/
β”‚   └── cryptoStore.ts           # Zustand state management
β”œβ”€β”€ utils/
β”‚   └── indicators.ts            # Technical indicator calculations
β”œβ”€β”€ types/
β”‚   └── index.ts                 # TypeScript type definitions
β”œβ”€β”€ crypto-dashboard.css         # Complete styling
β”œβ”€β”€ layout.tsx                   # Layout wrapper
└── page.tsx                     # Page entry point

⚑ Live Price Architecture

The dashboard combines two data sources so prices are always current:

Source Data Update frequency
CoinGecko REST Historical prices, market data Polled every 30 s
CoinCap WebSocket Current ticker price Streaming (sub-second)

How live prices reach the UI

CoinCap WS β†’ useRealtimePrice hook β†’ Zustand.rtPrices
                                            β”‚
                                            β”œβ”€β–Ί LivePrice (table rows + chart header)
                                            β”œβ”€β–Ί CryptoTable (via merged liveCoins)
                                            └─► CryptoChart (via livePrice prop β˜…)

β˜… Charts update without React re-renders β€” CryptoChart holds a ref to the Chart.js instance. When a live price arrives it mutates the last data-point directly (chart.data.datasets[0].data[lastIndex] = price) and calls chart.update('none') β€” a Chart.js internal repaint with no animations and no React reconciliation. Updates are throttled to ≀1 per second to keep the chart smooth and readable.

Why Zustand for rtPrices?

LivePrice components live inside every table row (up to 100 rows). Storing prices in Zustand and using per-coin selectors (state => state.rtPrices[coinId]) ensures that only the specific row whose coin changed re-renders, not the entire table.

WebSocket reconnect on coin-list changes

useRealtimePrice tracks a sorted key of all coin IDs. When the 30-second REST refresh returns a different coin set, the hook closes the existing WebSocket and opens a new one subscribed to the updated asset list.

Full details: See app/crypto/ARCHITECTURE.md


πŸ“ˆ Technical Indicators Deep Dive

RSI (Relative Strength Index)

The RSI measures momentum by comparing recent gains to recent losses on a 0-100 scale.

Formula:

RSI = 100 - (100 / (1 + RS))
RS = Average Gain / Average Loss

Implementation: Uses Wilder's smoothing method (exponential moving average) for accuracy.

Dynamic Periods by Timeframe:

Timeframe RSI Period Rationale
24h (hourly data) 9 Shorter period for intraday momentum shifts
7d 14 Standard Wilder period
30d 14 Balanced for medium-term analysis
1y (daily data) 21 Longer period filters noise for yearly trends

Signal Levels:

  • > 70: Overbought β€” potential reversal or strong uptrend
  • < 30: Oversold β€” potential reversal or strong downtrend
  • 50: Neutral centerline

Reference: Investopedia - RSI


SMA (Simple Moving Average)

The SMA calculates the arithmetic mean of prices over a specified period, creating a smoothed trend line.

Formula:

SMA = (P1 + P2 + ... + Pn) / n

Implementation: Dual SMA strategy with short and long periods to identify crossovers.

Dynamic Periods by Timeframe:

Timeframe Short SMA Long SMA Rationale
24h 8 21 Fast response for hourly data
7d 10 30 Standard short-term periods
30d 20 50 Classic trading periods
1y 50 200 Golden/Death cross signals

Trading Signals:

  • Golden Cross: Short SMA crosses above Long SMA β†’ Bullish
  • Death Cross: Short SMA crosses below Long SMA β†’ Bearish

Reference: Investopedia - SMA


MACD (Moving Average Convergence Divergence)

MACD reveals changes in strength, direction, momentum, and duration of a trend.

Components:

MACD Line = EMA(fast) - EMA(slow)
Signal Line = EMA(MACD Line, signal period)
Histogram = MACD Line - Signal Line

Implementation: Uses EMA (Exponential Moving Average) for responsiveness.

Dynamic Periods by Timeframe:

Timeframe Fast Slow Signal Rationale
24h 8 17 9 Tighter for hourly volatility
7d 12 26 9 Standard MACD settings
30d 12 26 9 Traditional parameters
1y 19 39 9 Extended for daily data smoothing

Trading Signals:

  • MACD crosses above Signal: Bullish momentum
  • MACD crosses below Signal: Bearish momentum
  • Histogram increasing: Strengthening trend
  • Divergence: Price/MACD disagreement suggests reversal

Reference: Investopedia - MACD


Bollinger Bands

Bollinger Bands measure volatility and identify overbought/oversold conditions relative to recent price action.

Formula:

Middle Band = SMA(period)
Upper Band = Middle Band + (stdDev Γ— multiplier)
Lower Band = Middle Band - (stdDev Γ— multiplier)

Implementation: Standard 2Οƒ deviation captures ~95% of price action.

Dynamic Periods by Timeframe:

Timeframe Period Std Dev Rationale
24h 14 2 Responsive for intraday
7d 20 2 Standard Bollinger settings
30d 20 2 Classic parameters
1y 30 2 Smoothed for yearly view

Trading Signals:

  • Price at Upper Band: Potentially overbought
  • Price at Lower Band: Potentially oversold
  • Band Squeeze: Low volatility, breakout expected
  • Band Expansion: High volatility, trend in progress

Reference: Investopedia - Bollinger Bands


πŸ›  Chart.js Implementation

Architecture

The chart implementation uses react-chartjs-2 as a React wrapper for Chart.js with the following registered components:

ChartJS.register(
  CategoryScale,    // X-axis labels
  LinearScale,      // Y-axis numbers
  PointElement,     // Data points
  LineElement,      // Line connections
  BarElement,       // MACD histogram
  Title,
  Tooltip,
  Legend,
  Filler           // Area fills (Bollinger Bands)
);

Multi-Dataset Management

The price chart dynamically builds datasets based on enabled studies:

// Base price dataset
const priceDatasets = [{ label: 'Price', data: prices, ... }];

// Conditionally add Bollinger Bands (behind price)
if (enabledStudies.bollingerBands) {
  priceDatasets.unshift(bbUpper, bbMiddle, bbLower);
}

// Conditionally add SMA overlays (on top)
if (enabledStudies.sma) {
  priceDatasets.push(smaShort, smaLong);
}

Fill Between Lines (Bollinger Bands)

Chart.js fill property creates the shaded band area:

{
  label: 'BB Upper',
  fill: '+1',  // Fill to next dataset (BB Middle)
  backgroundColor: 'rgba(34, 197, 94, 0.15)',
}

Separate Indicator Panels

RSI and MACD render in separate chart instances below the main price chart:

  • RSI Panel: Fixed 0-100 scale with overbought/oversold zones
  • MACD Panel: Dual-chart with histogram (Bar) and lines (Line)

Tooltip Customization

callbacks: {
  label: function(context) {
    const label = context.dataset.label;
    if (label === 'Price' || label.includes('SMA')) {
      return `${label}: $${value.toLocaleString()}`;
    }
    return `${label}: ${value.toFixed(2)}`;
  }
}

Performance Optimizations

  • pointRadius: 0 β€” Disable point rendering for performance
  • tension: 0.4 β€” Smooth curves without excessive computation
  • useMemo β€” Memoize indicator calculations
  • Conditional rendering β€” Only calculate enabled indicators

πŸ—„ State Management

Zustand store with localStorage persistence:

interface CryptoState {
  theme: 'light' | 'dark';
  timePeriod: '1' | '7' | '30' | '365';
  favorites: string[];
  enabledStudies: {
    rsi: boolean;
    sma: boolean;
    bollingerBands: boolean;
    macd: boolean;
  };
  // ... actions
}

Persisted to localStorage:

  • Theme preference
  • Favorite coins
  • View mode (table/grid)
  • Enabled technical studies

🌐 API Routes

GET /crypto/api/coins

Fetches cryptocurrency list with market data.

Parameter Default Description
vs_currency usd Price currency
per_page 100 Results per page

GET /crypto/api/coin-history

Fetches historical price data for charts.

Parameter Default Description
id required Coin ID (e.g., bitcoin)
days 7 Days of history
vs_currency usd Price currency

Caching Strategy

  • Coin list: 30 seconds
  • Historical data: 5 minutes
  • Search results: 1 hour

πŸ“± Responsive Design

Breakpoints

Screen Width Adjustments
Desktop > 1024px Full layout
Tablet 768-1024px Condensed controls
Mobile < 768px Stacked layout, bottom sheet menus
Small < 480px Compact indicators, touch-optimized

Mobile Optimizations

  • Studies dropdown becomes bottom sheet modal
  • Chart heights reduced for viewport fit
  • Touch-friendly button sizes
  • Horizontal scroll for time periods

🎨 Theming

CSS custom properties for consistent theming:

:root {
  --bg-primary: #f8fafc;
  --text-primary: #0f172a;
  --accent-primary: #3b82f6;
  --positive: #10b981;
  --negative: #ef4444;
  /* Indicator colors */
  --sma-short-color: #f59e0b;
  --sma-long-color: #8b5cf6;
  --bollinger-middle-color: #22c55e;
  --macd-line-color: #06b6d4;
  --macd-signal-color: #ec4899;
}

[data-theme="dark"] {
  --bg-primary: #0f172a;
  --text-primary: #f1f5f9;
  /* ... dark variants */
}

πŸ“¦ Dependencies

Package Version Purpose
next 16.x React framework
react 19.x UI library
typescript 5.x Type safety
chart.js ^4.4 Chart rendering
react-chartjs-2 ^5.2 React Chart.js wrapper
zustand ^4.4 State management
date-fns ^3.0 Date formatting

πŸš€ Deployment

Netlify (Recommended)

npm run build
# Deploy via Netlify CLI or Git integration

Vercel

npx vercel

Environment Variables (Optional)

NEXT_PUBLIC_COINGECKO_API_KEY=your_api_key

πŸ“š Resources


πŸ“„ License

MIT License - See LICENSE for details.


Built with ❀️ using Next.js, TypeScript, and Chart.js

About

A modern, responsive cryptocurrency tracking dashboard built with Next.js 16, TypeScript, and Chart.js

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors