DEV Community

Cover image for Precious Metals App: Real-Time Charts & TradingView
San Si wu
San Si wu

Posted on

Precious Metals App: Real-Time Charts & TradingView

Introduction

In today's rapidly evolving fintech landscape, real-time and accurate precious metals market data has become the core foundation for investment decision-making. Whether for professional quantitative trading teams or individual investors, obtaining millisecond-level gold and silver price feeds, coupled with intuitive chart analysis and precise price alert functionality, constitutes a fundamental requirement for building an excellent precious metals investment APP.

However, from data source integration and backend architecture design to frontend visualization, the entire data pipeline involves the coordinated collaboration of multiple technical components. This article comprehensively analyzes the full-stack development approach for precious metals investment APPs, covering overall architecture design, key module implementation, and engineering practices, in conjunction with a common financial data interface. Special attention is given to the integration of TradingView's open-source charting library—the mainstream solution currently used across the industry for implementing professional-grade candlestick charts on both mobile and web platforms.

I. Overall Architecture Design

The data pipeline for a precious metals investment APP can be divided into five core layers, each performing distinct functions while collaboratively forming a complete data loop.

Data Source Layer: Establishes bidirectional communication with third-party financial data providers—RESTful APIs handle batch retrieval of historical market data and basic queries, while WebSocket channels receive millisecond-level real-time data pushes.

Data Access Layer: Deploys an independent market data gateway service to uniformly manage and maintain WebSocket persistent connections (a single connection can subscribe to multiple products depending on data source capabilities), parse and route multi-instrument data pushed from upstream, and provide standardized data interfaces for downstream modules.

Business Processing Layer: Serving as the core hub, it handles real-time cleansing and aggregation of market data, implements an efficient matching engine for price alert conditions, and performs real-time computation and updates of candlestick data, ensuring every push is accurately processed.

Persistence Layer: Adopts a hybrid storage strategy—Redis caches the latest quotes, relational databases store historical candlesticks, and time-series databases archive complete tick-level transaction records to meet query and backtesting requirements across different scenarios.

Presentation Layer: The mobile APP maintains persistent connections with the backend via WebSocket, receives pushed data and renders real-time market information; frontend charts integrate TradingView's open-source charting libraries (Lightweight Charts or Charting Library) to achieve high-performance candlestick chart display, complemented by interactive features such as gesture-based zooming and multi-timeframe switching.

Architecture Layer Diagram:

┌─────────────────────────────────────────────────────────────┐
 │                     Presentation Layer                       │
 │   TradingView Chart Rendering │ Real-time Quote Refresh │ Price Alert Push │
 └─────────────────────────────────────────────────────────────┘
                               ↕
 ┌─────────────────────────────────────────────────────────────┐
 │                      Persistence Layer                       │
 │   Redis (Latest Quotes) │ MySQL (Historical Candlesticks) │ TSDB (Tick Data) │
 └─────────────────────────────────────────────────────────────┘
                               ↕
 ┌─────────────────────────────────────────────────────────────┐
 │                   Business Processing Layer                  │
 │   Data Cleansing │ Real-time Candlestick Computation │ Alert Condition Matching Engine │
 └─────────────────────────────────────────────────────────────┘
                               ↕
 ┌─────────────────────────────────────────────────────────────┐
 │                      Data Access Layer                       │
 │   Market Data Gateway │ Multi-Instrument Routing │ Protocol Adaptation │
 └─────────────────────────────────────────────────────────────┘
                               ↕
 ┌─────────────────────────────────────────────────────────────┐
 │                        Data Source Layer                     │
 │   Third-party Financial API (REST + WebSocket)              │
 │   Gold (AU) · Silver (AG) · Crude Oil (CL) · Natural Gas (NG) │
 └─────────────────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

II. Data Source Integration: A Common Financial API Example

This section demonstrates integration methods for both REST and WebSocket protocols using a financial data interface (the following example uses iTick API, which can be replaced with your chosen data provider in actual development). This example serves only to illustrate the technical workflow and does not constitute a recommendation for any specific service provider.

2.1 REST API Integration: Basic Data Retrieval and Historical Candlesticks

REST API employs HTTPS GET requests, with authentication tokens required in the request headers.

Real-time Quote Retrieval: The following code demonstrates retrieving the latest quotes for gold (XAUUSD) and silver (XAGUSD):

import requests

API_TOKEN = "your_token_here"
headers = {"accept": "application/json", "token": API_TOKEN}

# Batch retrieval of precious metals real-time quotes (example endpoint)
url = "https://api.itick.org/forex/quotes?region=GB&codes=XAUUSD,XAGUSD"
resp = requests.get(url, headers=headers, timeout=3)

if resp.status_code == 200:
   data = resp.json()
   gold = data["data"]["XAUUSD"]
   silver = data["data"]["XAGUSD"]
   print(f"Gold: {gold['ld']} @ {gold['t']}")
   print(f"Silver: {silver['ld']} @ {silver['t']}")
Enter fullscreen mode Exit fullscreen mode

In the response, the ld field represents the latest price, t is the timestamp (milliseconds), and additional key fields include opening price o, highest price h, and lowest price l.

Historical Candlestick Query: For candlestick data required for chart display, it can be retrieved through the candlestick endpoint:

# Retrieve gold futures candlestick data
url = "https://api.itick.org/forex/kline?region=gb&code=XAUUSD&kType=1&limit=100"
resp = requests.get(url, headers=headers, timeout=3)
kline_data = resp.json()
# kType=1 represents minute candles, adjustable to obtain candlesticks of different periods as needed
Enter fullscreen mode Exit fullscreen mode

2.2 WebSocket Integration: Real-time Market Data Push

For scenarios requiring real-time market monitoring, WebSocket is a more efficient choice than polling. Data providers' WebSocket APIs typically support pushing tick transactions, multi-level order book depth, candlestick updates, and other data types.

Connection and Authentication: First, establish a WebSocket connection and complete authentication:

import websocket
import json

# Carry token in headers for authentication (specific method depends on interface specifications)
ws = websocket.WebSocketApp(
    "wss://api.itick.org/future",
    header={"token": "your_token_here"},
    on_message=on_message
)
Enter fullscreen mode Exit fullscreen mode

Subscribing to Data Channels: After successful authentication, subscribe to required instruments and data types by sending JSON commands:

def on_open(ws):
    # Subscribe to quote data for gold (GC) and silver (SI)
    subscribe_msg = {
        "ac": "subscribe",
        "params": "GC$US,SI$US",
        "types": "quote"  # Options: quote, depth, tick, kline
    }
    ws.send(json.dumps(subscribe_msg))
Enter fullscreen mode Exit fullscreen mode

Processing Pushed Data: Upon successful subscription, each real-time market update will be pushed to the client in a format similar to:

def on_message(ws, message):
    data = json.loads(message)
    if data.get("code") == 1:
        payload = data["data"]
        symbol = payload["s"]
        latest_price = payload["ld"]
        volume = payload["v"]
        timestamp = payload["t"]
        print(f"{symbol}: {latest_price} vol={volume}")
Enter fullscreen mode Exit fullscreen mode

III. Market Data Reception, Parsing, and Storage

3.1 Data Gateway: Multi-Instrument Routing and Cleansing

In actual high-concurrency production environments, upstream systems typically compress data from multiple instruments into a single WebSocket stream for pushing. If asset routing and distribution are not properly handled in the first mile after message arrival, downstream real-time computation, storage, and application presentation will inevitably encounter data cross-contamination issues.

The core of the solution lies in constructing a lightweight in-memory routing table, executing only lock-free dictionary mapping and categorized writing within the on_message callback:

# In-memory routing table
ASSET_MAP = {
    "XAUUSD": "gold",
    "XAGUSD": "silver",
    "XPTUSD": "platinum",
    "GC": "gold",
    "SI": "silver"
}

# In-memory cache bucketed by instrument
price_cache = {"gold": {}, "silver": {}, "others": {}}

def on_message(msg):
    symbol = msg.get("symbol") or msg.get("s")
    price = msg.get("price") or msg.get("ld")
    if not symbol or not price:
        return
    asset_type = ASSET_MAP.get(symbol, "others")
    price_cache[asset_type][symbol] = price
Enter fullscreen mode Exit fullscreen mode

Subsequently, independent asynchronous coroutines batch-write cached data to downstream storage or message queues at fixed intervals (e.g., 50ms).

3.2 Real-time Candlestick Computation

Candlestick charts are one of the core presentation modules in precious metals APPs. Computing candlesticks in real-time from Tick data pushed via WebSocket typically adopts the following strategies:

  • Maintaining In-Memory Candlestick State: Maintain a candlestick buffer object for each instrument-timeframe combination, containing OHLC (Open, High, Low, Close) prices and volume;
  • Time-Slice Updates: Whenever new Tick data is received, determine based on its timestamp whether it belongs to the current candlestick or the next period's candlestick, update the highest price, lowest price, and volume, and determine the closing price;
  • Candlestick Pushing: When a candlestick period ends, push that candlestick data to the client via WebSocket while simultaneously storing it in persistent storage.

For completed candlestick data, the backend can push messages to clients to trigger incremental refreshes; for the latest incomplete candlestick, clients should independently maintain its OHLC changes in real-time.

3.3 Price Alert Engine

The core challenge of the price alert functionality lies in efficiently completing large-scale user condition matching while processing massive amounts of real-time market data.

Engine Design Principles:

  • Condition Indexing: Establish secondary indexes for alert conditions by instrument to avoid iterating through all users during each price update.
  • Hash Dictionary Matching: When data for a new instrument arrives, directly index all alert conditions for that instrument via the instrument code and perform price threshold comparisons.
  • Deduplication: Push notifications only once when the same price point triggers multiple times, preventing users from being disturbed by repeated alerts.

The following is a simplified Golang demonstration of an alert matching engine:

type AlertCondition struct {
    UserID   int
    Symbol   string
    Price    float64
    Operator string  // "above" or "below"
}

var alertsMap = make(map[string][]AlertCondition)

func checkAlerts(symbol string, currentPrice float64) {
    for _, alert := range alertsMap[symbol] {
        triggered := false
        if alert.Operator == "above" && currentPrice >= alert.Price {
            triggered = true
        } else if alert.Operator == "below" && currentPrice <= alert.Price {
            triggered = true
        }
        if triggered {
            sendPushNotification(alert.UserID, symbol, currentPrice)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

IV. TradingView Open-Source Chart Integration

4.1 Solution Selection

TradingView offers two charting solutions:

  • TradingView Charting Library: A fully-featured professional charting library supporting thousands of technical indicators, drawing tools, and multiple timeframes, but requires authorization (commercial use typically involves fees).
  • TradingView Lightweight Charts: Lightweight, completely open-source (Apache 2.0 license), focused on high-performance candlestick/area chart rendering, compact in size (approximately 40kB gzip), highly suitable for mobile and embedded scenarios.

For most initial versions of precious metals investment APPs, Lightweight Charts serves as an ideal starting point. Although it doesn't include complex technical indicator libraries, it provides smooth zooming/panning experiences, controllable footprint, and easy customization, sufficiently meeting core real-time candlestick display requirements.

4.2 Lightweight Charts Basic Integration

The following example demonstrates how to render real-time candlesticks in WebView or HTML pages embedded in mobile applications.

Step 1: Import Library Files

<!DOCTYPE html>
<html>
<head>
    <script src="https://unpkg.com/lightweight-charts/dist/lightweight-charts.standalone.js"></script>
</head>
<body>
    <div id="chart" style="width: 100%; height: 500px;"></div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Step 2: Create and Configure Chart

const chart = LightweightCharts.createChart(document.getElementById('chart'), {
    width: window.innerWidth,
    height: 500,
    layout: {
        backgroundColor: '#1c1c2e',
        textColor: '#d1d4dc',
    },
    grid: {
        vertLines: { color: '#2a2e39' },
        horzLines: { color: '#2a2e39' },
    },
    crosshair: {
        mode: LightweightCharts.CrosshairMode.Normal,
    },
    rightPriceScale: {
        borderColor: '#2a2e39',
    },
    timeScale: {
        borderColor: '#2a2e39',
        timeVisible: true,
        secondsVisible: false,
    },
});

// Add candlestick series
const candleSeries = chart.addCandlestickSeries({
    upColor: '#26a69a',
    downColor: '#ef5350',
    borderVisible: false,
    wickUpColor: '#26a69a',
    wickDownColor: '#ef5350',
});
Enter fullscreen mode Exit fullscreen mode

Step 3: Load Historical Candlesticks from Backend and Update in Real-time

Assuming the backend provides a REST endpoint /api/kline?symbol=XAUUSD&resolution=1&from=...&to=... returning data in TradingView UDF-compatible format:

async function loadHistoricalData(symbol, resolution, from, to) {
    const url = `/api/kline?symbol=${symbol}&resolution=${resolution}&from=${from}&to=${to}`;
    const response = await fetch(url);
    const data = await response.json();
    // Assuming data contains c (close), o (open), h (high), l (low), t (timestamp), v (volume)
    candleSeries.setData(data.map(item => ({
        time: item.t,
        open: item.o,
        high: item.h,
        low: item.l,
        close: item.c,
    })));
}

// Real-time push: Update the latest candlestick after receiving new Tick or candlestick increments via WebSocket
ws.onmessage = (event) => {
    const update = JSON.parse(event.data);
    if (update.type === 'kline_update') {
        candleSeries.update({
            time: update.t,
            open: update.o,
            high: update.h,
            low: update.l,
            close: update.c,
        });
    }
};
Enter fullscreen mode Exit fullscreen mode

4.3 Mobile Performance Optimization

Running TradingView charts on mobile devices requires special attention to rendering efficiency and memory usage:

  • Data Downsampling: When users pull large amounts of candlestick data on overview charts (e.g., daily candles spanning over a year), implement downsampling on candlestick data at the backend (such as retaining weekly OHLC), ensuring overall trend visualization while significantly reducing rendering pressure on mobile devices.
  • Canvas Reuse: Lightweight Charts itself is Canvas-based; avoid reconstructing the entire chart instance with each data update, instead incrementally refresh via the update() method.
  • Resolution Adaptation: Listen for resize events in WebView and call chart.resize(width, height) to ensure proper display across different screen sizes.

V. Backend Architecture and Performance Considerations

5.1 Microservices and Distributed Design

For high-concurrency precious metals market scenarios, a microservices architecture is recommended. Decompose core functionalities such as market data ingestion, candlestick computation, price alerts, and user management into independent microservice modules, achieving asynchronous decoupling through message queues (such as Kafka or RabbitMQ), enabling horizontal scaling and independent iteration of each module.

5.2 Deployment and Monitoring

To ensure service stability and reliability, the following mechanisms are recommended at the deployment level:

  • Load Balancing: Deploy multiple nodes at the access layer with automatic failover when any node experiences failure, ensuring high availability of WebSocket persistent connections.
  • Connection State Monitoring: Real-time monitoring of key metrics including active WebSocket connection count, heartbeat timeout rate, and data push latency, establishing alert thresholds and notification rules.
  • Logging System: Comprehensively record every market data push and user operation, providing basis for post-incident problem tracing while facilitating data accuracy auditing and verification.

VI. Conclusion

From financial data API integration to multi-instrument routing in market data gateways, real-time candlestick computation and efficient price alert matching, to TradingView open-source chart library integration and mobile performance optimization, the full-stack data development for precious metals investment APPs involves coordinated collaboration across multiple technical layers. Leveraging mature open-source charting solutions (such as Lightweight Charts), developers can rapidly build professional-grade candlestick display modules without relying on commercial licensing.

In practical implementation, it is recommended to prioritize establishing the core data pipeline through a Minimum Viable Product (MVP) approach—ensuring end-to-end low latency from data source to chart rendering—before progressively enriching technical indicators, alert strategies, and trading assistance features after validating stability. Whether building professional quantitative trading tools or developing precious metals market APPs targeting ordinary investors, the aforementioned technical architecture and implementation approaches offer substantial reference value and scalability.

Reference Documentation: https://blog.itick.org/quant-tools/itick-tradingview/kline-realtime-integration
GitHub: https://github.com/itick-org/

Top comments (0)