Get OHLC Data
Endpoint: GET /api/v1/coin/ohlc
Description
This endpoint retrieves candlestick (OHLC) data for a specific token within an optional time range. The data is useful for creating price charts and analyzing token price movements over time.
Authentication
Required: No
Type: None
Request
Headers
Content-Type: application/json
Query Parameters
token
string
Yes
The mint address of the token
from
number
No
Start timestamp in Unix seconds
to
number
No
End timestamp in Unix seconds
Example Requests:
GET /api/v1/coin/ohlc?token=ABC // All data for token
GET /api/v1/coin/ohlc?token=ABC&from=1234567890 // Data from timestamp
GET /api/v1/coin/ohlc?token=ABC&from=1234567890&to=1234567899 // Data in range
Response
Success Response
Status Code: 200 OK
Content-Type: application/json
type OHLCResponse = Array<{
id: number;
coinId: string;
timestamp: Date;
unixTimestamp: string;
open: string;
high: string;
low: string;
close: string;
volume: string;
}>
Example Response:
[
{
"id": 1,
"coinId": "TokenMintAddress123",
"timestamp": "2024-02-20T12:00:00.000Z",
"unixTimestamp": "1708428000",
"open": "1.5",
"high": "1.8",
"low": "1.4",
"close": "1.6",
"volume": "1000000"
},
// ... more candles
]
Error Response
Status Code: 500 Internal Server Error
{
"error": "An internal error occurred. Please try again later."
}
Example Usage
interface OHLCData {
id: number;
coinId: string;
timestamp: string;
unixTimestamp: string;
open: string;
high: string;
low: string;
close: string;
volume: string;
}
// Function to fetch OHLC data
async function getOHLCData(
tokenMintAddress: string,
fromTimestamp?: number,
toTimestamp?: number
) {
try {
let url = `https://api.heyhal.xyz/api/v1/coin/ohlc?token=${tokenMintAddress}`;
if (fromTimestamp) {
url += `&from=${fromTimestamp}`;
}
if (toTimestamp) {
url += `&to=${toTimestamp}`;
}
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const candles: OHLCData[] = await response.json();
return candles;
} catch (error) {
console.error('Error fetching OHLC data:', error);
throw error;
}
}
// Example usage with TradingView Lightweight Charts
import { createChart } from 'lightweight-charts';
async function createPriceChart(
containerId: string,
tokenMintAddress: string
) {
const chart = createChart(containerId, {
width: 800,
height: 400
});
const candlestickSeries = chart.addCandlestickSeries();
// Get last 7 days of data
const toTimestamp = Math.floor(Date.now() / 1000);
const fromTimestamp = toTimestamp - (7 * 24 * 60 * 60);
try {
const ohlcData = await getOHLCData(
tokenMintAddress,
fromTimestamp,
toTimestamp
);
const formattedData = ohlcData.map(candle => ({
time: parseInt(candle.unixTimestamp),
open: parseFloat(candle.open),
high: parseFloat(candle.high),
low: parseFloat(candle.low),
close: parseFloat(candle.close)
}));
candlestickSeries.setData(formattedData);
} catch (error) {
console.error('Error creating chart:', error);
}
}
Implementation Notes
Time Range Handling
If no time range is specified, returns all available data
Timestamps should be in Unix seconds format
Data is ordered by timestamp in descending order (newest first)
Data Format
All price values are returned as strings to preserve precision
Volume is denominated in the smallest token unit
Timestamps are provided in both ISO 8601 (timestamp) and Unix seconds (unixTimestamp) formats
3. Performance Considerations
// Example of paginated data fetching
async function fetchAllOHLCData(tokenMintAddress: string) {
const CHUNK_SIZE = 7 * 24 * 60 * 60; // 7 days in seconds
const now = Math.floor(Date.now() / 1000);
let currentTo = now;
let allData: OHLCData[] = [];
while (true) {
const from = currentTo - CHUNK_SIZE;
const chunk = await getOHLCData(
tokenMintAddress,
from,
currentTo
);
if (chunk.length === 0) break;
allData = [...allData, ...chunk];
currentTo = from;
}
return allData;
}
Data Analysis Utilities
// Calculate moving average
function calculateMA(candles: OHLCData[], period: number) {
return candles.map((candle, index) => {
if (index < period - 1) return null;
const sum = candles
.slice(index - period + 1, index + 1)
.reduce((acc, curr) => acc + parseFloat(curr.close), 0);
return sum / period;
});
}
// Calculate daily returns
function calculateDailyReturns(candles: OHLCData[]) {
return candles.map((candle, index) => {
if (index === 0) return 0;
const previousClose = parseFloat(candles[index - 1].close);
const currentClose = parseFloat(candle.close);
return ((currentClose - previousClose) / previousClose) * 100;
});
}
Best Practices
Data Caching
const CACHE_DURATION = 60000; // 1 minute
const cache = new Map<string, {
timestamp: number;
data: OHLCData[];
}>();
async function getCachedOHLCData(
tokenMintAddress: string,
fromTimestamp?: number,
toTimestamp?: number
) {
const cacheKey = `${tokenMintAddress}-${fromTimestamp}-${toTimestamp}`;
const now = Date.now();
const cached = cache.get(cacheKey);
if (cached && now - cached.timestamp < CACHE_DURATION) {
return cached.data;
}
const data = await getOHLCData(tokenMintAddress, fromTimestamp, toTimestamp);
cache.set(cacheKey, { timestamp: now, data });
return data;
}
Error Handling
function validateTimestamps(from?: number, to?: number) {
if (from && to && from > to) {
throw new Error('From timestamp must be less than to timestamp');
}
if (from && from > Date.now() / 1000) {
throw new Error('From timestamp cannot be in the future');
}
}
Last updated