Lowcap Chart
Lowcap markets are not listed on a reference exchange, so there are no venue candles to fetch — the SDK’s Binance CandleSource has nothing to serve for them. The price has to come from the liquidity pool the token actually trades in, and you pick the rendering approach that fits your UI budget and DX preferences.
Charting a major? Use the Majors Chart guide instead — the SDK fetches and streams real OHLCV for
those. source.getSymbol(marketName) returning undefined is how a source tells you a market belongs on this page
rather than that one.
Two common options:
- Option A — DexScreener iframe. Fastest to ship. One
<iframe>, zero data plumbing, styling limited to DexScreener’s query flags. - Option B — Own chart with OHLC + charting library. Fetch OHLCV candles from Moralis, CoinGecko / GeckoTerminal, or any pool-indexer of your choice, and render them with TradingView Lightweight Charts (or ECharts, Recharts, etc.). Full control over look and feel; you own the data pipeline.
Whichever you pick, prices, mark, and lifecycle data still come from the Enigma price service. The chart is display-only — do not read prices from the iframe or the OHLC feed for trade math.
Both options key off the market’s pair address and chain slug, which come from a single call to useEnigmaPriceServiceMetadata using the market’s base-token address.
| Field | Source | Used for |
|---|---|---|
pair_address | metadata response | pool identifier for both options |
chain_id | metadata response | network slug ("solana", "base", "bsc", …) — lowercase |
base_token.address | metadata response | key for the metadata lookup |
Option A — DexScreener iframe
Point an <iframe> at dexscreener.com/{chainSlug}/{pairAddress} with embed=1 and a set of look-and-feel flags.
Minimal component
import { useEnigmaPriceServiceMetadata } from "@symmio/trading-react";
interface Props {
/** Base-token address for the market you want the chart of. */
tokenAddress: string;
}
export function LowcapDexScreenerChart(props: Props) {
const { data, isLoading } = useEnigmaPriceServiceMetadata({
addresses: [props.tokenAddress],
});
if (isLoading) return <ChartSkeleton />;
const meta = data?.[props.tokenAddress];
if (!meta?.pair_address || !meta?.chain_id) return <ChartUnavailable />;
const url = buildDexScreenerEmbedUrl({
chainSlug: meta.chain_id.toLowerCase(),
pairAddress: meta.pair_address,
});
return <iframe title="DexScreener Chart" src={url} width="100%" height="100%" style={{ border: 0 }} />;
}Building the embed URL
Keep this in a helper so the flags are consistent across every chart surface:
interface BuildDexScreenerEmbedUrlOptions {
chainSlug: string;
pairAddress: string;
/** Override any of the default query params. */
overrides?: Record<string, string>;
}
export function buildDexScreenerEmbedUrl(options: BuildDexScreenerEmbedUrlOptions) {
const params = new URLSearchParams({
embed: "1",
loadChartSettings: "0",
trades: "0",
info: "0",
chartLeftToolbar: "0",
chartTheme: "dark",
theme: "dark",
chartStyle: "1",
interval: "15",
chartType: "price",
...options.overrides,
});
return `https://dexscreener.com/${options.chainSlug}/${options.pairAddress}?${params.toString()}`;
}Query-param reference
| Param | Value | Effect |
|---|---|---|
embed | 1 | Strip the DexScreener chrome — required for iframe embedding. |
loadChartSettings | 0 | Ignore the visitor’s saved DexScreener chart preferences. |
trades | 0 | Hide the trades panel. |
info | 0 | Hide the info / socials panel. |
chartLeftToolbar | 0 | Hide the left toolbar. |
chartTheme | dark | Chart theme. |
theme | dark | Page theme. |
chartStyle | 1 | 1 = candles, 0 = bars, 2 = line, 3 = area. |
interval | 15 | Default candle interval in minutes. |
chartType | price | price or marketCap. |
Override any of them per surface — e.g. interval: "60" for a wider-timeframe view — via overrides.
Loading & fallback states
Metadata may be missing while the request is in-flight, or the market may not have a resolvable pair. Render three states:
- Loading —
isLoadingtrue. Show a chart-shaped skeleton so the layout doesn’t jump. - Unavailable — metadata resolved but
pair_address/chain_idmissing. Show a small “chart not available for this market” placeholder. Do not silently render an iframe pointed at a broken URL. - Ready — build the URL and mount the iframe.
The iframe itself has no error event you can hook — DexScreener renders its own inline error inside the frame. Trust the metadata gate rather than trying to detect iframe failures.
Option B — Own chart with OHLC + charting library
Fetch OHLCV candles from a public data provider, feed them into a charting library, own the render. More work, but the chart matches your product’s design system and you can layer overlays (positions, TP/SL lines, mark price) on top.
OHLC data providers
Pick one — both cover EVM chains and Solana, both give candles keyed by pool / pair address:
| Provider | Endpoint shape | Notes |
|---|---|---|
| Moralis Price API — OHLCV | GET /erc20/{tokenAddress}/ohlcv (EVM) / matching Solana route | OHLCV candles for tokens across EVM chains and Solana. API key required, has a free tier. |
| CoinGecko / GeckoTerminal DEX — pool OHLCV | GET /networks/{network}/pools/{pool_address}/ohlcv/{timeframe} | DEX-native, keyed by pool address (== pair_address). Public GeckoTerminal API is free; CoinGecko Pro is required for higher rate limits. |
CoinGecko coin OHLC — /coins/{id}/ohlc | GET /coins/{id}/ohlc | Keyed by CoinGecko id, not contract address — worse fit for lowcap since many lowcap tokens are not indexed there. |
For lowcap, GeckoTerminal’s pools/{pool_address}/ohlcv route is usually the best fit — the pool address is exactly what the metadata endpoint already returns (pair_address), the API is public, and it covers the DEXes lowcap tokens actually trade on.
Sketch — GeckoTerminal + TradingView Lightweight Charts
import { useQuery } from "@tanstack/react-query";
import { useEnigmaPriceServiceMetadata } from "@symmio/trading-react";
import { CandlestickSeries, createChart, type UTCTimestamp } from "lightweight-charts";
import { useEffect, useRef } from "react";
interface Props {
tokenAddress: string;
/** Candle timeframe accepted by GeckoTerminal: "minute" | "hour" | "day". */
timeframe?: "minute" | "hour" | "day";
}
export function LowcapOhlcChart(props: Props) {
const timeframe = props.timeframe ?? "minute";
const { data: metadata } = useEnigmaPriceServiceMetadata({
addresses: [props.tokenAddress],
});
const meta = metadata?.[props.tokenAddress];
const candles = useQuery({
queryKey: ["gt-ohlcv", meta?.chain_id, meta?.pair_address, timeframe],
queryFn: () => fetchGeckoTerminalOhlcv(meta!.chain_id, meta!.pair_address, timeframe),
enabled: Boolean(meta?.chain_id && meta?.pair_address),
staleTime: 30_000,
});
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!containerRef.current || !candles.data) return;
const chart = createChart(containerRef.current, { autoSize: true });
// Lightweight Charts v5. On v4 this is `chart.addCandlestickSeries()`.
const series = chart.addSeries(CandlestickSeries);
series.setData(candles.data);
return () => chart.remove();
}, [candles.data]);
return <div ref={containerRef} style={{ width: "100%", height: "100%" }} />;
}
async function fetchGeckoTerminalOhlcv(chainSlug: string, poolAddress: string, timeframe: string) {
const url = `https://api.geckoterminal.com/api/v2/networks/${chainSlug.toLowerCase()}/pools/${poolAddress}/ohlcv/${timeframe}`;
const res = await fetch(url);
if (!res.ok) throw new Error(`GeckoTerminal OHLCV ${res.status}`);
const json = await res.json();
// ohlcv_list: [[unixSeconds, open, high, low, close, volume], …]
return (json.data.attributes.ohlcv_list as number[][]).map(([t, open, high, low, close]) => ({
time: t as UTCTimestamp,
open,
high,
low,
close,
}));
}Confirm each provider’s rate limits, terms of service, and attribution requirements before shipping. Public tiers are fine for demos and low-traffic apps; production usually needs a paid key.
Charting library choices
- TradingView Lightweight Charts — free, small footprint (~40 KB gzipped), candlestick / line / area, no attribution required for the OSS build. Default recommendation.
- TradingView Advanced Charts — full TradingView terminal experience (indicators, drawing tools). License required; you host their bundle.
- ECharts / Recharts / visx — general-purpose; pick if your app already ships one of them and you want visual consistency.
Which option to pick
| Concern | Option A (DexScreener) | Option B (Own OHLC) |
|---|---|---|
| Time to ship | Minutes | Hours to days |
| Look & feel control | Query flags only | Full |
| Overlay positions / TP-SL / mark on the chart | Not possible | Yes |
| Data pipeline you own | None | Full — provider, cache, rate limit |
| Cost | Free | Free tier → paid at scale |
| Best for | MVPs, embedded pages | Product surfaces, trade panels |
Start with A. Move to B once the product needs on-chart overlays or a bespoke look.
Related
- Majors Chart — the other half: markets that are listed on a reference exchange, where the SDK fetches and streams the bars for you.
useEnigmaPriceServiceMetadata— the metadata hook both options depend on.- Price Service — core-level reference for the metadata endpoint, including the full
MetadataResponseshape. - Instant Open — the lowcap open flow this chart typically sits next to.