Skip to Content
TutorialsBasic Integration

πŸ”§ Basic Integration Tutorial

Step-by-step guide to integrating GoCharting SDK into your application with built-in AutoFit and detailed explanations.

πŸ“‹ Prerequisites

Before starting this tutorial, ensure you have:

  • Node.js 16+ installed
  • Basic JavaScript/TypeScript knowledge
  • Modern web browser (Chrome 80+, Firefox 75+, Safari 13+, Edge 80+)
  • GoCharting SDK license key (use demo-550e8400-e29b-41d4-a716-446655440000 for testing)

🎯 Tutorial Overview

This tutorial will guide you through:

  1. Project Setup - Creating a new project and installing dependencies
  2. Basic Chart - Creating your first chart with built-in AutoFit
  3. Custom Datafeed - Implementing your own data source (composition-based)
  4. Configuration - Customizing chart appearance and behavior
  5. Event Handling - Responding to chart interactions
  6. Production Ready - Optimizing for production deployment

✨ What’s New in This Version:

  • πŸš€ Built-in AutoFit - No more sizing headaches, works everywhere automatically
  • πŸ”§ Composition-based Datafeed - Simpler, cleaner architecture
  • πŸ“± Responsive by Default - Charts adapt to any screen size
  • πŸ›‘οΈ Bulletproof Error Handling - Graceful failures with helpful messages

πŸ“¦ Step 1: Project Setup

Create New Project

# Create project directory mkdir my-trading-app cd my-trading-app # Initialize package.json npm init -y # Install GoCharting SDK npm install @gocharting/chart-sdk # Install peer dependencies npm install react react-dom luxon # Install development dependencies npm install --save-dev webpack webpack-cli webpack-dev-server html-webpack-plugin

Project Structure

my-trading-app/ β”œβ”€β”€ src/ β”‚ β”œβ”€β”€ index.js # Main application file β”‚ β”œβ”€β”€ dataProvider.js # Custom data provider β”‚ └── styles.css # Application styles β”œβ”€β”€ public/ β”‚ └── index.html # HTML template β”œβ”€β”€ package.json └── webpack.config.js # Webpack configuration

Basic HTML Template

Create public/index.html:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>My Trading App - GoCharting SDK</title> <style> body { margin: 0; padding: 20px; font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; background-color: #1a1a1a; color: white; } .header { text-align: center; margin-bottom: 20px; } .controls { display: flex; gap: 15px; justify-content: center; margin-bottom: 20px; flex-wrap: wrap; } .controls select, .controls button { padding: 8px 12px; border: 1px solid #555; background-color: #2d2d2d; color: white; border-radius: 4px; cursor: pointer; } .controls select:hover, .controls button:hover { background-color: #3d3d3d; } #chart-container { width: 100%; height: 600px; border: 1px solid #444; border-radius: 8px; background-color: #1e1e1e; } .status { margin-top: 10px; padding: 10px; background-color: #2d2d2d; border-radius: 4px; text-align: center; } .loading { display: flex; align-items: center; justify-content: center; height: 600px; font-size: 18px; } .error { color: #ff6b6b; background-color: #2d1b1b; border: 1px solid #ff6b6b; } </style> </head> <body> <div class="header"> <h1>πŸš€ My Trading Application</h1> <p>Powered by GoCharting SDK</p> </div> <div class="controls"> <select id="symbol-selector"> <option value="NASDAQ:AAPL">Apple (AAPL)</option> <option value="NASDAQ:MSFT">Microsoft (MSFT)</option> <option value="NASDAQ:GOOGL">Google (GOOGL)</option> <option value="NYSE:TSLA">Tesla (TSLA)</option> <option value="BINANCE:BTCUSDT">Bitcoin (BTC)</option> </select> <select id="interval-selector"> <option value="1">1 Minute</option> <option value="5">5 Minutes</option> <option value="15">15 Minutes</option> <option value="60">1 Hour</option> <option value="1D" selected>1 Day</option> </select> <select id="theme-selector"> <option value="dark" selected>Dark Theme</option> <option value="light">Light Theme</option> </select> <button id="refresh-btn">Refresh Data</button> </div> <div id="chart-container"> <div class="loading">Loading chart...</div> </div> <div id="status" class="status">Initializing...</div> <script src="bundle.js"></script> </body> </html>

πŸ“Š Step 2: Create Custom Datafeed

Create src/datafeed.js:

// Create a simple datafeed object (no inheritance needed) export const myDatafeed = { initialized: false, cache: new Map(), // Optional initialization method async _init(datacenter, token) { this.datacenter = datacenter; this.token = token; this.initialized = true; console.log("βœ… Datafeed initialized"); }, async getBars(symbolInfo, resolution, periodParams) { const { from, to, firstDataRequest } = periodParams; console.log( `πŸ“Š Fetching bars for ${symbolInfo.name}, resolution: ${resolution}` ); try { // Check cache first const cacheKey = `${symbolInfo.name}-${resolution}-${from}-${to}`; if (this.cache.has(cacheKey)) { console.log("πŸ“‹ Returning cached data"); return this.cache.get(cacheKey); } // For demo purposes, we'll generate sample data // In production, replace this with your actual API call const bars = this.generateSampleData( symbolInfo, from, to, resolution ); const result = { bars: bars, meta: { noData: bars.length === 0, }, }; // Cache the result this.cache.set(cacheKey, result); console.log(`βœ… Fetched ${bars.length} bars`); return result; } catch (error) { console.error("❌ Error fetching bars:", error); return { bars: [], meta: { noData: true }, }; } } async resolveSymbol(symbolName, onResolve, onError) { console.log(`πŸ” Resolving symbol: ${symbolName}`); try { // Parse symbol name (e.g., "NASDAQ:AAPL") const [exchange, ticker] = symbolName.split(":"); // Create symbol info const symbolInfo = { name: symbolName, full_name: symbolName, description: this.getSymbolDescription(ticker), type: this.getSymbolType(exchange), session: this.getSessionHours(exchange), timezone: this.getTimezone(exchange), ticker: ticker, has_intraday: true, has_daily: true, supported_resolutions: [ "1", "5", "15", "30", "60", "240", "1D", "1W", "1M", ], // Price precision (SDK calculates pricescale internally) max_tick_precision: 2, tick_size: 0.01, display_tick_size: 0.01, }; console.log("βœ… Symbol resolved:", symbolInfo); onResolve(symbolInfo); } catch (error) { console.error("❌ Error resolving symbol:", error); onError("Symbol not found"); } } async searchSymbols(userInput, callback) { console.log(`πŸ”Ž Searching symbols: ${userInput}`); // Sample symbols for demo const allSymbols = [ { symbol: "AAPL", full_name: "NASDAQ:AAPL", description: "Apple Inc.", exchange: "NASDAQ", ticker: "AAPL", type: "stock", }, { symbol: "MSFT", full_name: "NASDAQ:MSFT", description: "Microsoft Corporation", exchange: "NASDAQ", ticker: "MSFT", type: "stock", }, { symbol: "GOOGL", full_name: "NASDAQ:GOOGL", description: "Alphabet Inc.", exchange: "NASDAQ", ticker: "GOOGL", type: "stock", }, { symbol: "TSLA", full_name: "NYSE:TSLA", description: "Tesla Inc.", exchange: "NYSE", ticker: "TSLA", type: "stock", }, { symbol: "BTCUSDT", full_name: "BINANCE:BTCUSDT", description: "Bitcoin / Tether", exchange: "BINANCE", ticker: "BTCUSDT", type: "crypto", }, ]; const filteredSymbols = allSymbols.filter( (symbol) => symbol.symbol.toLowerCase().includes(userInput.toLowerCase()) || symbol.description .toLowerCase() .includes(userInput.toLowerCase()) ); console.log(`βœ… Found ${filteredSymbols.length} symbols`); callback(filteredSymbols); } // Helper methods generateSampleData(symbolInfo, from, to, resolution) { const bars = []; const interval = this.getIntervalMs(resolution); const startTime = from * 1000; const endTime = to * 1000; let currentTime = startTime; let price = 100 + Math.random() * 100; // Random starting price while (currentTime <= endTime) { const change = (Math.random() - 0.5) * 5; // Random price change const open = price; const close = Math.max(0.01, price + change); const high = Math.max(open, close) + Math.random() * 3; const low = Math.min(open, close) - Math.random() * 3; const volume = Math.floor(Math.random() * 1000000) + 100000; bars.push({ time: currentTime, open: Math.round(open * 100) / 100, high: Math.round(high * 100) / 100, low: Math.round(Math.max(0.01, low) * 100) / 100, close: Math.round(close * 100) / 100, volume: volume, }); price = close; currentTime += interval; } return bars; } getIntervalMs(resolution) { const intervals = { 1: 60 * 1000, // 1 minute 5: 5 * 60 * 1000, // 5 minutes 15: 15 * 60 * 1000, // 15 minutes 30: 30 * 60 * 1000, // 30 minutes 60: 60 * 60 * 1000, // 1 hour 240: 4 * 60 * 60 * 1000, // 4 hours "1D": 24 * 60 * 60 * 1000, // 1 day "1W": 7 * 24 * 60 * 60 * 1000, // 1 week "1M": 30 * 24 * 60 * 60 * 1000, // 1 month (approximate) }; return intervals[resolution] || intervals["1D"]; } getSymbolDescription(ticker) { const descriptions = { AAPL: "Apple Inc.", MSFT: "Microsoft Corporation", GOOGL: "Alphabet Inc.", TSLA: "Tesla Inc.", BTCUSDT: "Bitcoin / Tether", }; return descriptions[ticker] || `${ticker} Stock`; } getSymbolType(exchange) { const types = { NASDAQ: "stock", NYSE: "stock", BINANCE: "crypto", FOREX: "forex", }; return types[exchange] || "stock"; } getSessionHours(exchange) { const sessions = { NASDAQ: "0930-1600", NYSE: "0930-1600", BINANCE: "24x7", FOREX: "24x5", }; return sessions[exchange] || "0930-1600"; } getTimezone(exchange) { const timezones = { NASDAQ: "America/New_York", NYSE: "America/New_York", BINANCE: "Etc/UTC", FOREX: "Etc/UTC", }; return timezones[exchange] || "America/New_York"; } }

πŸ“ˆ Step 3: Main Application

Create src/index.js:

import { createChart } from "@gocharting/chart-sdk"; import { MyDataProvider } from "./dataProvider.js"; import "./styles.css"; class TradingApp { constructor() { this.chart = null; this.dataProvider = null; this.currentSymbol = "NASDAQ:AAPL"; this.currentInterval = "1D"; this.currentTheme = "dark"; this.init(); } async init() { try { this.updateStatus("Initializing application..."); // Create data provider this.dataProvider = new MyDataProvider(); // Create chart await this.createChart(); // Set up event listeners this.setupEventListeners(); this.updateStatus("Application ready"); } catch (error) { console.error("❌ Failed to initialize app:", error); this.updateStatus("Failed to initialize application", "error"); } } async createChart() { this.updateStatus("Creating chart..."); const chartConfig = { theme: { name: this.currentTheme }, chart: { chartType: "candlestick", animations: true, grid: { horizontal: true, vertical: true, }, }, ui: { showToolbar: true, showVolumePanel: true, showDrawingTools: true, }, trading: { enableTrading: false, // Disable trading for basic integration }, performance: { maxCandles: 5000, animations: true, }, }; // πŸš€ Use the simplified createChart function this.chart = createChart("#chart-container", { symbol: this.currentSymbol, interval: this.currentInterval, datafeed: this.dataProvider, licenseKey: "demo-550e8400-e29b-41d4-a716-446655440000", // Replace with your license key config: chartConfig, }); // Set up chart event handlers this.setupChartEvents(); } setupChartEvents() { this.chart.onChartReady(() => { console.log("βœ… Chart is ready"); this.updateStatus( `Chart loaded: ${this.currentSymbol} (${this.currentInterval})` ); }); this.chart.onSymbolChange((symbolInfo) => { console.log("πŸ“Š Symbol changed:", symbolInfo.name); this.currentSymbol = symbolInfo.name; this.updateSymbolSelector(); this.updateStatus(`Symbol: ${symbolInfo.description}`); }); this.chart.onIntervalChange((interval) => { console.log("⏱️ Interval changed:", interval); this.currentInterval = interval; this.updateIntervalSelector(); this.updateStatus(`Interval changed to ${interval}`); }); this.chart.onError((error) => { console.error("❌ Chart error:", error); this.updateStatus(`Error: ${error.message}`, "error"); }); } setupEventListeners() { // Symbol selector document .getElementById("symbol-selector") .addEventListener("change", (e) => { this.changeSymbol(e.target.value); }); // Interval selector document .getElementById("interval-selector") .addEventListener("change", (e) => { this.changeInterval(e.target.value); }); // Theme selector document .getElementById("theme-selector") .addEventListener("change", (e) => { this.changeTheme(e.target.value); }); // Refresh button document.getElementById("refresh-btn").addEventListener("click", () => { this.refreshChart(); }); } async changeSymbol(symbol) { if (this.chart && symbol !== this.currentSymbol) { this.updateStatus(`Loading ${symbol}...`); try { await this.chart.setSymbol(symbol); this.currentSymbol = symbol; } catch (error) { console.error("❌ Failed to change symbol:", error); this.updateStatus("Failed to change symbol", "error"); } } } async changeInterval(interval) { if (this.chart && interval !== this.currentInterval) { this.updateStatus(`Changing interval to ${interval}...`); try { await this.chart.setInterval(interval); this.currentInterval = interval; } catch (error) { console.error("❌ Failed to change interval:", error); this.updateStatus("Failed to change interval", "error"); } } } changeTheme(theme) { if (this.chart && theme !== this.currentTheme) { this.updateStatus(`Changing theme to ${theme}...`); try { this.chart.setTheme(theme); this.currentTheme = theme; this.updateBodyTheme(theme); } catch (error) { console.error("❌ Failed to change theme:", error); this.updateStatus("Failed to change theme", "error"); } } } refreshChart() { if (this.chart) { this.updateStatus("Refreshing chart data..."); // Clear cache and refresh this.dataProvider.cache.clear(); this.chart.refreshData(); } } updateStatus(message, type = "info") { const statusElement = document.getElementById("status"); statusElement.textContent = message; statusElement.className = `status ${type}`; console.log(`πŸ“’ Status: ${message}`); } updateSymbolSelector() { const selector = document.getElementById("symbol-selector"); selector.value = this.currentSymbol; } updateIntervalSelector() { const selector = document.getElementById("interval-selector"); selector.value = this.currentInterval; } updateBodyTheme(theme) { document.body.className = `theme-${theme}`; } destroy() { if (this.chart) { this.chart.destroy(); this.chart = null; } } } // Initialize app when DOM is loaded document.addEventListener("DOMContentLoaded", () => { console.log("πŸš€ Starting Trading App..."); window.tradingApp = new TradingApp(); }); // Cleanup on page unload window.addEventListener("beforeunload", () => { if (window.tradingApp) { window.tradingApp.destroy(); } });

🎨 Step 4: Styling

Create src/styles.css:

/* Additional styles for the application */ .theme-light { background-color: #ffffff; color: #333333; } .theme-light .controls select, .theme-light .controls button { background-color: #f5f5f5; color: #333333; border-color: #ddd; } .theme-light #chart-container { background-color: #ffffff; border-color: #ddd; } .theme-light .status { background-color: #f5f5f5; color: #333333; } /* Loading animation */ .loading::after { content: ""; display: inline-block; width: 20px; height: 20px; border: 3px solid #333; border-radius: 50%; border-top-color: #00d4aa; animation: spin 1s ease-in-out infinite; margin-left: 10px; } @keyframes spin { to { transform: rotate(360deg); } } /* Responsive design */ @media (max-width: 768px) { .controls { flex-direction: column; align-items: center; } .controls select, .controls button { width: 200px; } #chart-container { height: 400px; } }

πŸ”§ Step 5: Build Configuration

Create webpack.config.js:

const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { mode: "development", entry: "./src/index.js", output: { path: path.resolve(__dirname, "dist"), filename: "bundle.js", clean: true, }, module: { rules: [ { test: /\.css$/i, use: ["style-loader", "css-loader"], }, { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], }, }, }, ], }, plugins: [ new HtmlWebpackPlugin({ template: "./public/index.html", }), ], devServer: { static: "./dist", port: 3000, open: true, hot: true, }, resolve: { fallback: { fs: false, path: false, }, }, };

πŸš€ Step 6: Run Your Application

Add scripts to package.json:

{ "scripts": { "start": "webpack serve", "build": "webpack --mode=production", "dev": "webpack serve --mode=development" } }

Run the application:

# Start development server npm start # Or build for production npm run build

🎯 Next Steps

Congratulations! You now have a working GoCharting SDK integration. Here’s what to explore next:

  1. Trading Integration - Add real trading capabilities
  2. Configuration Guide - Customize chart appearance

Ready to add more features? Check out our advanced tutorials!

Last updated on