Setup Trading View Charting Library JS for crypto
Learn how to setup a Trading View candle chart with crypto real time price updates, and historical candle chart.
Mobula pair data API allows you to fetch real-time and historical price data for any on-chain pair. You can use this data to feed Trading View charting library.
What you’ll need
- Access to trading view codebase repo (need manual approval from Trading View)
- An API key from the Dashboard (only for production use, you can use the API without an API key in development mode)
- A react app (or any other framework) to display the chart
Walkthrough
Identify your asset
Pick your asset symbol, name or address. If it is a symbol/name, make sure to check case sensitivity and to respect the asset name as listed on Mobula curated token list (explorable here). If it is an address, make sure to check the blockchain supported (check here for the full list) and to respect the blockchain ID format.
You can also use pair address directly (if using asset, we will route to the largest liquidity pool for this asset).
Setup Chart Component
Let’s first setup the main chart component - you must host the trading view lib files inside the public folder of your app, in our example, we host them at static/charting_library.
const ChartBox = ({
baseAsset,
mobile = false,
custom_css_url = "../themed.css",
extraCss,
}: ChartBoxProps) => {
const ref = useRef<HTMLDivElement>(null);
const { resolvedTheme } = useTheme();
const isWhiteMode = resolvedTheme === "light";
useEffect(() => {
if (!baseAsset) return () => {};
let freshWidget: IChartingLibraryWidget | null = null;
import("../../../../../../../../public/static/charting_library").then(
({ widget: Widget }) => {
if (!ref.current) return;
freshWidget = new Widget({
// Datafeed
datafeed: Datafeed(baseAsset),
symbol: baseAsset?.symbol + "/USD",
interval: "60" as ResolutionString,
// Settings
container: ref.current,
container_id: ref.current.id,
library_path: "/static/charting_library/",
// UI & Behavior
locale: "en",
fullscreen: false,
disabled_features: [
"header_saveload",
"header_symbol_search",
...(mobile ? ["left_toolbar"] : []),
],
timezone: Intl.DateTimeFormat().resolvedOptions()
.timeZone as Timezone,
autosize: true,
// Theme
theme: isWhiteMode ? "Light" : "Dark",
// TO DO: Overrites don't work rn.
overrides: overrides(isWhiteMode),
custom_css_url,
});
}
);
return () => {
freshWidget?.remove();
};
}, [baseAsset, custom_css_url, mobile]);
return (
<div ref={ref}></div>
); };
Fetch Mobula Historical Data API
We can then implement the fetching logic to get the historical data from Mobula API. We will use the market/history/pair
endpoint to fetch the historical data for the last 300 datapoints of our resolution.
export const supportedResolutions = [
"1",
"5",
"15",
"30",
"60",
"120",
"240",
"24H",
"7D",
"30D",
];
const lastBarsCache = new Map();
export const Datafeed = (baseAsset: Asset) => ({
onReady: (callback: Function) => {
callback({ supported_resolutions: supportedResolutions });
},
resolveSymbol: (symbolName: string, onResolve: Function) => {
const params = {
name: symbolName,
description: "",
type: "crypto",
session: "24x7",
ticker: symbolName,
minmov: 1,
pricescale: Math.min(
10 ** String(Math.round(10000 / baseAsset.price)).length,
10000000000000000
),
has_intraday: true,
intraday_multipliers: ["1", "15", "30", "60"],
supported_resolution: supportedResolutions,
volume_precision: 8,
data_status: "streaming",
};
onResolve(params);
},
getBars: async (
symbolInfo,
resolution: string,
periodParams,
onResult: Function
) => {
const response = await GET(
"/api/1/market/history/pair",
{
asset: baseAsset.contracts[0],
blockchain: baseAsset.blockchains[0],
from: periodParams.from * 1000,
to: periodParams.to * 1000,
amount: periodParams.countBack,
usd: true,
period: resolution,
},
false,
{
headers: { Authorization: "YOUR-API-KEY" },
}
);
const data = await response.json();
onResult(data.data, {
noData: data.data.length !== periodParams.countBack,
});
if (periodParams.firstDataRequest) {
lastBarsCache.set(baseAsset.name, data.data[data.data.length - 1]);
}
},
searchSymbols: () => {},
subscribeBars: () => {},
unsubscribeBars: () => {},
getMarks: () => ({}),
getTimeScaleMarks: () => ({}),
getServerTime: () => ({}),
});
Fetch Mobula Real Time Data API
We can then implement the fetching logic to get the real time data from Mobula API. We will use the pair
WSS endpoint to fetch the real time updates & trades for our pair.
subscribeBars: (
symbolInfo,
resolution,
onRealtimeCallback,
subscriberUID,
onResetCacheNeededCallback
) => {
console.log("Subscribinnnng");
const socket = new WebSocket(
process.env.NEXT_PUBLIC_PRICE_WSS_ENDPOINT as string
);
socket.addEventListener("open", () => {
socket.send(
JSON.stringify({
type: "pair",
authorization: process.env.NEXT_PUBLIC_PRICE_KEY,
payload: {
address: "0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc", // baseAsset.contracts[0],
blockchain: baseAsset.blockchains[0],
interval: 5,
},
})
);
});
socket.addEventListener("message", (event) => {
const {data} = JSON.parse(event.data);
const { priceUSD: price, date: timestamp } = data;
const lastDailyBar = lastBarsCache.get(baseAsset.name);
const nextDailyBarTime = getNextBarTime(resolution, lastDailyBar.time);
let bar: Bar;
if (timestamp >= nextDailyBarTime) {
bar = {
time: nextDailyBarTime,
open: price,
high: price,
low: price,
close: price,
};
} else {
bar = {
...lastDailyBar,
high: Math.max(lastDailyBar.high, price),
low: Math.min(lastDailyBar.low, price),
close: price,
};
}
console.log("BAR", bar, data);
onRealtimeCallback(bar);
});
sockets.set(baseAsset.name, socket);
},
unsubscribeBars: (subscriberUID) => {
sockets.get(baseAsset.name).close();
}
We also have to implement the getNextBarTime
function to get the next bar time for our resolution.
export const getNextBarTime = (resolution: string, time: number) => {
const date = new Date(time * 1000);
const utcDate = new Date(
Date.UTC(
date.getFullYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes()
)
);
switch (resolution) {
case "1":
case "3":
case "5":
case "15":
case "30":
utcDate.setMinutes(utcDate.getMinutes() + 1);
break;
case "60":
case "120":
case "240":
case "360":
case "720":
case "D":
utcDate.setHours(utcDate.getHours() + 1);
break;
case "W":
utcDate.setDate(utcDate.getDate() + 7);
break;
case "M":
utcDate.setMonth(utcDate.getMonth() + 1);
break;
}
return Math.floor(utcDate.getTime() / 1000);
};
Need help?
Can’t find what you’re looking for? Reach out to us, response times < 1h.