curl --request POST \
--url https://demo-api.mobula.io/api/2/perp/chart \
--header 'Content-Type: application/json' \
--data '
{
"candles": [
{
"t": 1780860000000,
"o": 1.0615964,
"h": 1.0656162,
"l": 1.0506006,
"c": 1.0605862
},
{
"t": 1780861800000,
"o": 1.0605862,
"h": 1.0655736,
"l": 1.0525683,
"c": 1.0630746
},
{
"t": 1780863600000,
"o": 1.0630746,
"h": 1.0695774,
"l": 1.0630746,
"c": 1.0655949
}
],
"width": 1024,
"height": 850,
"name": "FLUID/USD",
"lines": {
"stopLoss": 1.2876838333333334,
"takeProfit": 0.7358193333333334,
"liquidation": 1.4231453021582852
},
"headerData": {
"pair": "FLUID/USD",
"leverage": 3,
"currentPrice": 1.103729,
"priceChange": -6.305772495755514,
"openInterestL": {
"value": 0,
"total": 250000
},
"openInterestS": {
"value": 30.000026,
"total": 249969.999974
},
"holdingL": 0.00251711712,
"holdingS": 0.00251711712
},
"footerData": {
"high24h": 1.2151002,
"low24h": 1.0799406,
"volume24h": 2001.2866550754236
}
}
'import requests
url = "https://demo-api.mobula.io/api/2/perp/chart"
payload = {
"candles": [
{
"t": 1780860000000,
"o": 1.0615964,
"h": 1.0656162,
"l": 1.0506006,
"c": 1.0605862
},
{
"t": 1780861800000,
"o": 1.0605862,
"h": 1.0655736,
"l": 1.0525683,
"c": 1.0630746
},
{
"t": 1780863600000,
"o": 1.0630746,
"h": 1.0695774,
"l": 1.0630746,
"c": 1.0655949
}
],
"width": 1024,
"height": 850,
"name": "FLUID/USD",
"lines": {
"stopLoss": 1.2876838333333334,
"takeProfit": 0.7358193333333334,
"liquidation": 1.4231453021582852
},
"headerData": {
"pair": "FLUID/USD",
"leverage": 3,
"currentPrice": 1.103729,
"priceChange": -6.305772495755514,
"openInterestL": {
"value": 0,
"total": 250000
},
"openInterestS": {
"value": 30.000026,
"total": 249969.999974
},
"holdingL": 0.00251711712,
"holdingS": 0.00251711712
},
"footerData": {
"high24h": 1.2151002,
"low24h": 1.0799406,
"volume24h": 2001.2866550754236
}
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
candles: [
{t: 1780860000000, o: 1.0615964, h: 1.0656162, l: 1.0506006, c: 1.0605862},
{t: 1780861800000, o: 1.0605862, h: 1.0655736, l: 1.0525683, c: 1.0630746},
{t: 1780863600000, o: 1.0630746, h: 1.0695774, l: 1.0630746, c: 1.0655949}
],
width: 1024,
height: 850,
name: 'FLUID/USD',
lines: {
stopLoss: 1.2876838333333334,
takeProfit: 0.7358193333333334,
liquidation: 1.4231453021582852
},
headerData: {
pair: 'FLUID/USD',
leverage: 3,
currentPrice: 1.103729,
priceChange: -6.305772495755514,
openInterestL: {value: 0, total: 250000},
openInterestS: {value: 30.000026, total: 249969.999974},
holdingL: 0.00251711712,
holdingS: 0.00251711712
},
footerData: {high24h: 1.2151002, low24h: 1.0799406, volume24h: 2001.2866550754236}
})
};
fetch('https://demo-api.mobula.io/api/2/perp/chart', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://demo-api.mobula.io/api/2/perp/chart",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'candles' => [
[
't' => 1780860000000,
'o' => 1.0615964,
'h' => 1.0656162,
'l' => 1.0506006,
'c' => 1.0605862
],
[
't' => 1780861800000,
'o' => 1.0605862,
'h' => 1.0655736,
'l' => 1.0525683,
'c' => 1.0630746
],
[
't' => 1780863600000,
'o' => 1.0630746,
'h' => 1.0695774,
'l' => 1.0630746,
'c' => 1.0655949
]
],
'width' => 1024,
'height' => 850,
'name' => 'FLUID/USD',
'lines' => [
'stopLoss' => 1.2876838333333334,
'takeProfit' => 0.7358193333333334,
'liquidation' => 1.4231453021582852
],
'headerData' => [
'pair' => 'FLUID/USD',
'leverage' => 3,
'currentPrice' => 1.103729,
'priceChange' => -6.305772495755514,
'openInterestL' => [
'value' => 0,
'total' => 250000
],
'openInterestS' => [
'value' => 30.000026,
'total' => 249969.999974
],
'holdingL' => 0.00251711712,
'holdingS' => 0.00251711712
],
'footerData' => [
'high24h' => 1.2151002,
'low24h' => 1.0799406,
'volume24h' => 2001.2866550754236
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://demo-api.mobula.io/api/2/perp/chart"
payload := strings.NewReader("{\n \"candles\": [\n {\n \"t\": 1780860000000,\n \"o\": 1.0615964,\n \"h\": 1.0656162,\n \"l\": 1.0506006,\n \"c\": 1.0605862\n },\n {\n \"t\": 1780861800000,\n \"o\": 1.0605862,\n \"h\": 1.0655736,\n \"l\": 1.0525683,\n \"c\": 1.0630746\n },\n {\n \"t\": 1780863600000,\n \"o\": 1.0630746,\n \"h\": 1.0695774,\n \"l\": 1.0630746,\n \"c\": 1.0655949\n }\n ],\n \"width\": 1024,\n \"height\": 850,\n \"name\": \"FLUID/USD\",\n \"lines\": {\n \"stopLoss\": 1.2876838333333334,\n \"takeProfit\": 0.7358193333333334,\n \"liquidation\": 1.4231453021582852\n },\n \"headerData\": {\n \"pair\": \"FLUID/USD\",\n \"leverage\": 3,\n \"currentPrice\": 1.103729,\n \"priceChange\": -6.305772495755514,\n \"openInterestL\": {\n \"value\": 0,\n \"total\": 250000\n },\n \"openInterestS\": {\n \"value\": 30.000026,\n \"total\": 249969.999974\n },\n \"holdingL\": 0.00251711712,\n \"holdingS\": 0.00251711712\n },\n \"footerData\": {\n \"high24h\": 1.2151002,\n \"low24h\": 1.0799406,\n \"volume24h\": 2001.2866550754236\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://demo-api.mobula.io/api/2/perp/chart")
.header("Content-Type", "application/json")
.body("{\n \"candles\": [\n {\n \"t\": 1780860000000,\n \"o\": 1.0615964,\n \"h\": 1.0656162,\n \"l\": 1.0506006,\n \"c\": 1.0605862\n },\n {\n \"t\": 1780861800000,\n \"o\": 1.0605862,\n \"h\": 1.0655736,\n \"l\": 1.0525683,\n \"c\": 1.0630746\n },\n {\n \"t\": 1780863600000,\n \"o\": 1.0630746,\n \"h\": 1.0695774,\n \"l\": 1.0630746,\n \"c\": 1.0655949\n }\n ],\n \"width\": 1024,\n \"height\": 850,\n \"name\": \"FLUID/USD\",\n \"lines\": {\n \"stopLoss\": 1.2876838333333334,\n \"takeProfit\": 0.7358193333333334,\n \"liquidation\": 1.4231453021582852\n },\n \"headerData\": {\n \"pair\": \"FLUID/USD\",\n \"leverage\": 3,\n \"currentPrice\": 1.103729,\n \"priceChange\": -6.305772495755514,\n \"openInterestL\": {\n \"value\": 0,\n \"total\": 250000\n },\n \"openInterestS\": {\n \"value\": 30.000026,\n \"total\": 249969.999974\n },\n \"holdingL\": 0.00251711712,\n \"holdingS\": 0.00251711712\n },\n \"footerData\": {\n \"high24h\": 1.2151002,\n \"low24h\": 1.0799406,\n \"volume24h\": 2001.2866550754236\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://demo-api.mobula.io/api/2/perp/chart")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"candles\": [\n {\n \"t\": 1780860000000,\n \"o\": 1.0615964,\n \"h\": 1.0656162,\n \"l\": 1.0506006,\n \"c\": 1.0605862\n },\n {\n \"t\": 1780861800000,\n \"o\": 1.0605862,\n \"h\": 1.0655736,\n \"l\": 1.0525683,\n \"c\": 1.0630746\n },\n {\n \"t\": 1780863600000,\n \"o\": 1.0630746,\n \"h\": 1.0695774,\n \"l\": 1.0630746,\n \"c\": 1.0655949\n }\n ],\n \"width\": 1024,\n \"height\": 850,\n \"name\": \"FLUID/USD\",\n \"lines\": {\n \"stopLoss\": 1.2876838333333334,\n \"takeProfit\": 0.7358193333333334,\n \"liquidation\": 1.4231453021582852\n },\n \"headerData\": {\n \"pair\": \"FLUID/USD\",\n \"leverage\": 3,\n \"currentPrice\": 1.103729,\n \"priceChange\": -6.305772495755514,\n \"openInterestL\": {\n \"value\": 0,\n \"total\": 250000\n },\n \"openInterestS\": {\n \"value\": 30.000026,\n \"total\": 249969.999974\n },\n \"holdingL\": 0.00251711712,\n \"holdingS\": 0.00251711712\n },\n \"footerData\": {\n \"high24h\": 1.2151002,\n \"low24h\": 1.0799406,\n \"volume24h\": 2001.2866550754236\n }\n}"
response = http.request(request)
puts response.read_body{
"data": "<string>"
}Generate Perp Chart Image
Render a candlestick chart image for a perpetual market from OHLC candles plus header/footer metadata and optional overlay lines (stop-loss, take-profit, liquidation). The candle shape is identical to the /2/perp/ohlcv-history response, so its output can be passed straight in.
curl --request POST \
--url https://demo-api.mobula.io/api/2/perp/chart \
--header 'Content-Type: application/json' \
--data '
{
"candles": [
{
"t": 1780860000000,
"o": 1.0615964,
"h": 1.0656162,
"l": 1.0506006,
"c": 1.0605862
},
{
"t": 1780861800000,
"o": 1.0605862,
"h": 1.0655736,
"l": 1.0525683,
"c": 1.0630746
},
{
"t": 1780863600000,
"o": 1.0630746,
"h": 1.0695774,
"l": 1.0630746,
"c": 1.0655949
}
],
"width": 1024,
"height": 850,
"name": "FLUID/USD",
"lines": {
"stopLoss": 1.2876838333333334,
"takeProfit": 0.7358193333333334,
"liquidation": 1.4231453021582852
},
"headerData": {
"pair": "FLUID/USD",
"leverage": 3,
"currentPrice": 1.103729,
"priceChange": -6.305772495755514,
"openInterestL": {
"value": 0,
"total": 250000
},
"openInterestS": {
"value": 30.000026,
"total": 249969.999974
},
"holdingL": 0.00251711712,
"holdingS": 0.00251711712
},
"footerData": {
"high24h": 1.2151002,
"low24h": 1.0799406,
"volume24h": 2001.2866550754236
}
}
'import requests
url = "https://demo-api.mobula.io/api/2/perp/chart"
payload = {
"candles": [
{
"t": 1780860000000,
"o": 1.0615964,
"h": 1.0656162,
"l": 1.0506006,
"c": 1.0605862
},
{
"t": 1780861800000,
"o": 1.0605862,
"h": 1.0655736,
"l": 1.0525683,
"c": 1.0630746
},
{
"t": 1780863600000,
"o": 1.0630746,
"h": 1.0695774,
"l": 1.0630746,
"c": 1.0655949
}
],
"width": 1024,
"height": 850,
"name": "FLUID/USD",
"lines": {
"stopLoss": 1.2876838333333334,
"takeProfit": 0.7358193333333334,
"liquidation": 1.4231453021582852
},
"headerData": {
"pair": "FLUID/USD",
"leverage": 3,
"currentPrice": 1.103729,
"priceChange": -6.305772495755514,
"openInterestL": {
"value": 0,
"total": 250000
},
"openInterestS": {
"value": 30.000026,
"total": 249969.999974
},
"holdingL": 0.00251711712,
"holdingS": 0.00251711712
},
"footerData": {
"high24h": 1.2151002,
"low24h": 1.0799406,
"volume24h": 2001.2866550754236
}
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
candles: [
{t: 1780860000000, o: 1.0615964, h: 1.0656162, l: 1.0506006, c: 1.0605862},
{t: 1780861800000, o: 1.0605862, h: 1.0655736, l: 1.0525683, c: 1.0630746},
{t: 1780863600000, o: 1.0630746, h: 1.0695774, l: 1.0630746, c: 1.0655949}
],
width: 1024,
height: 850,
name: 'FLUID/USD',
lines: {
stopLoss: 1.2876838333333334,
takeProfit: 0.7358193333333334,
liquidation: 1.4231453021582852
},
headerData: {
pair: 'FLUID/USD',
leverage: 3,
currentPrice: 1.103729,
priceChange: -6.305772495755514,
openInterestL: {value: 0, total: 250000},
openInterestS: {value: 30.000026, total: 249969.999974},
holdingL: 0.00251711712,
holdingS: 0.00251711712
},
footerData: {high24h: 1.2151002, low24h: 1.0799406, volume24h: 2001.2866550754236}
})
};
fetch('https://demo-api.mobula.io/api/2/perp/chart', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://demo-api.mobula.io/api/2/perp/chart",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'candles' => [
[
't' => 1780860000000,
'o' => 1.0615964,
'h' => 1.0656162,
'l' => 1.0506006,
'c' => 1.0605862
],
[
't' => 1780861800000,
'o' => 1.0605862,
'h' => 1.0655736,
'l' => 1.0525683,
'c' => 1.0630746
],
[
't' => 1780863600000,
'o' => 1.0630746,
'h' => 1.0695774,
'l' => 1.0630746,
'c' => 1.0655949
]
],
'width' => 1024,
'height' => 850,
'name' => 'FLUID/USD',
'lines' => [
'stopLoss' => 1.2876838333333334,
'takeProfit' => 0.7358193333333334,
'liquidation' => 1.4231453021582852
],
'headerData' => [
'pair' => 'FLUID/USD',
'leverage' => 3,
'currentPrice' => 1.103729,
'priceChange' => -6.305772495755514,
'openInterestL' => [
'value' => 0,
'total' => 250000
],
'openInterestS' => [
'value' => 30.000026,
'total' => 249969.999974
],
'holdingL' => 0.00251711712,
'holdingS' => 0.00251711712
],
'footerData' => [
'high24h' => 1.2151002,
'low24h' => 1.0799406,
'volume24h' => 2001.2866550754236
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://demo-api.mobula.io/api/2/perp/chart"
payload := strings.NewReader("{\n \"candles\": [\n {\n \"t\": 1780860000000,\n \"o\": 1.0615964,\n \"h\": 1.0656162,\n \"l\": 1.0506006,\n \"c\": 1.0605862\n },\n {\n \"t\": 1780861800000,\n \"o\": 1.0605862,\n \"h\": 1.0655736,\n \"l\": 1.0525683,\n \"c\": 1.0630746\n },\n {\n \"t\": 1780863600000,\n \"o\": 1.0630746,\n \"h\": 1.0695774,\n \"l\": 1.0630746,\n \"c\": 1.0655949\n }\n ],\n \"width\": 1024,\n \"height\": 850,\n \"name\": \"FLUID/USD\",\n \"lines\": {\n \"stopLoss\": 1.2876838333333334,\n \"takeProfit\": 0.7358193333333334,\n \"liquidation\": 1.4231453021582852\n },\n \"headerData\": {\n \"pair\": \"FLUID/USD\",\n \"leverage\": 3,\n \"currentPrice\": 1.103729,\n \"priceChange\": -6.305772495755514,\n \"openInterestL\": {\n \"value\": 0,\n \"total\": 250000\n },\n \"openInterestS\": {\n \"value\": 30.000026,\n \"total\": 249969.999974\n },\n \"holdingL\": 0.00251711712,\n \"holdingS\": 0.00251711712\n },\n \"footerData\": {\n \"high24h\": 1.2151002,\n \"low24h\": 1.0799406,\n \"volume24h\": 2001.2866550754236\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://demo-api.mobula.io/api/2/perp/chart")
.header("Content-Type", "application/json")
.body("{\n \"candles\": [\n {\n \"t\": 1780860000000,\n \"o\": 1.0615964,\n \"h\": 1.0656162,\n \"l\": 1.0506006,\n \"c\": 1.0605862\n },\n {\n \"t\": 1780861800000,\n \"o\": 1.0605862,\n \"h\": 1.0655736,\n \"l\": 1.0525683,\n \"c\": 1.0630746\n },\n {\n \"t\": 1780863600000,\n \"o\": 1.0630746,\n \"h\": 1.0695774,\n \"l\": 1.0630746,\n \"c\": 1.0655949\n }\n ],\n \"width\": 1024,\n \"height\": 850,\n \"name\": \"FLUID/USD\",\n \"lines\": {\n \"stopLoss\": 1.2876838333333334,\n \"takeProfit\": 0.7358193333333334,\n \"liquidation\": 1.4231453021582852\n },\n \"headerData\": {\n \"pair\": \"FLUID/USD\",\n \"leverage\": 3,\n \"currentPrice\": 1.103729,\n \"priceChange\": -6.305772495755514,\n \"openInterestL\": {\n \"value\": 0,\n \"total\": 250000\n },\n \"openInterestS\": {\n \"value\": 30.000026,\n \"total\": 249969.999974\n },\n \"holdingL\": 0.00251711712,\n \"holdingS\": 0.00251711712\n },\n \"footerData\": {\n \"high24h\": 1.2151002,\n \"low24h\": 1.0799406,\n \"volume24h\": 2001.2866550754236\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://demo-api.mobula.io/api/2/perp/chart")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"candles\": [\n {\n \"t\": 1780860000000,\n \"o\": 1.0615964,\n \"h\": 1.0656162,\n \"l\": 1.0506006,\n \"c\": 1.0605862\n },\n {\n \"t\": 1780861800000,\n \"o\": 1.0605862,\n \"h\": 1.0655736,\n \"l\": 1.0525683,\n \"c\": 1.0630746\n },\n {\n \"t\": 1780863600000,\n \"o\": 1.0630746,\n \"h\": 1.0695774,\n \"l\": 1.0630746,\n \"c\": 1.0655949\n }\n ],\n \"width\": 1024,\n \"height\": 850,\n \"name\": \"FLUID/USD\",\n \"lines\": {\n \"stopLoss\": 1.2876838333333334,\n \"takeProfit\": 0.7358193333333334,\n \"liquidation\": 1.4231453021582852\n },\n \"headerData\": {\n \"pair\": \"FLUID/USD\",\n \"leverage\": 3,\n \"currentPrice\": 1.103729,\n \"priceChange\": -6.305772495755514,\n \"openInterestL\": {\n \"value\": 0,\n \"total\": 250000\n },\n \"openInterestS\": {\n \"value\": 30.000026,\n \"total\": 249969.999974\n },\n \"holdingL\": 0.00251711712,\n \"holdingS\": 0.00251711712\n },\n \"footerData\": {\n \"high24h\": 1.2151002,\n \"low24h\": 1.0799406,\n \"volume24h\": 2001.2866550754236\n }\n}"
response = http.request(request)
puts response.read_body{
"data": "<string>"
}data. This is a synchronous proxy: one request in, one rendered chart out — nothing is stored.
t / o / h / l / c shape as GET /2/perp/ohlcv-history — feed that endpoint’s output directly. t is UNIX milliseconds, and priceChange is a percentage (e.g. -6.31 means -6.31%).Body
OHLC series, oldest-to-newest by t. Same shape as the /2/perp/ohlcv-history response, so its output can be passed in directly. Must contain at least one candle.
1Show child attributes
Show child attributes
Output image width in pixels. Positive integer.
Output image height in pixels. Positive integer.
Chart title / pair label shown on the chart (e.g. FLUID/USD).
Header block shown above the chart.
Show child attributes
Show child attributes
Footer block shown below the chart.
Show child attributes
Show child attributes
Optional horizontal overlay lines. Each level is independently optional — send only the ones you have.
Show child attributes
Show child attributes
Response
Rendered chart
The rendered chart returned by the renderer, passed through verbatim. Treat as an opaque string payload.