Depth Chart
The "DepthChart" component provides a visual aid comparing the buy and sell pressure in an orderbook.
Features
- Automatically fetches current information and populates the chart.
- Fetches updated data in intervals for live data and interactions.
- Provides a visual representation of buy and sell pressure.
Additional Resources
Chartjs is a popular library for creating interactive and responsive charts. The library provides a wide range of options for customizing the appearance and behavior of the charts.
Review the Chartjs documentation below
C#
Install the PakanaRazorSDEX NuGet package via the NuGet Package Manager Console.
.Net8.0 or greater is required.
dotnet add package PakanaRazorSDEX --version 0.0.4
??
Stellar Horizon Dependency will install automatically
NuGet Package Implementation
<PakanaRazorSDEX.Component.DepthChart/>
C#
@page "/DepthChart"
@rendermode InteractiveAuto
@using Microsoft.JSInterop
<div class="container">
<canvas id="depthChart" height="400"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stellar-sdk/13.0.0/stellar-sdk.min.js"></script>
<script src="./_content/PakanaRazorSDEX/js/depthChart.js"></script>
<script src="./_content/PakanaRazorSDEX/js/global.js"></script>
Javascript
We've provided simple HTML and JavaScript that can be used in your project as partial-components or be customized and integrated into your existing codebase.
Stellar CDN
*Current Version as of 2024-24-12*
<script src="https://cdnjs.cloudflare.com/ajax/libs/stellar-sdk/13.0.0/stellar-sdk.min.js"></script>
JavaScript
<script>
const { Asset, Server, Keypair, TransactionBuilder, Operation, BASE_FEE, Horizon } = StellarSdk;
let chart;
async function fetchOrderBook() {
try {
// Fetch Stellar's order book for XLM/USDC pair
const orderBook = await server.orderbook(usdcAsset, xlmAsset).call();
// Process Bids and Asks
const bids = processOrders(orderBook.bids, true); // Bids are buying XLM with USDC
const asks = processOrders(orderBook.asks, false); // Asks are selling XLM for USDC
// Render the depth chart using the fetched bids and asks
renderDepthChart(bids, asks);
} catch (error) {
console.error('Error fetching order book:', error);
}
}
function processOrders(orders, isBid) {
return orders.map(order => {
const price = parseFloat(order.price);
const volume = parseFloat(order.amount);
// Invert the price to display USD/USDC per XLM
const invertedPrice = 1 / price;
return { price: invertedPrice, volume };
});
}
function renderDepthChart(bids, asks) {
const ctx = document.getElementById('depthChart').getContext('2d');
// Sort bids in descending order (higher prices are on top for buyers)
const sortedBids = bids.sort((a, b) => b.price - a.price);
// Sort asks in ascending order (lower prices are on top for sellers)
const sortedAsks = asks.sort((a, b) => a.price - b.price);
// Cumulative volumes for bids and asks
const cumulativeBids = getCumulativeVolumes(sortedBids);
const cumulativeAsks = getCumulativeVolumes(sortedAsks);
// Extend bids and asks with dummy points to anchor the chart
const extendedBids = [
{ x: sortedBids[0].price, y: 0 }, // Start of bids
...cumulativeBids.map(b => ({ x: b.price, y: b.volume })),
{ x: sortedBids[sortedBids.length - 1].price, y: cumulativeBids[cumulativeBids.length - 1].volume }, // Last point for smooth curve
];
const extendedAsks = [
{ x: sortedAsks[0].price, y: 0 }, // Start of asks
...cumulativeAsks.map(a => ({ x: a.price, y: a.volume })),
{ x: sortedAsks[sortedAsks.length - 1].price, y: cumulativeAsks[cumulativeAsks.length - 1].volume }, // Last point for smooth curve
];
// Create gradient effects for bids and asks
const bidGradient = ctx.createLinearGradient(0, 0, 0, ctx.canvas.height);
bidGradient.addColorStop(0, 'rgba(0, 255, 0, 0.5)');
bidGradient.addColorStop(1, 'rgba(0, 255, 0, 0)');
const askGradient = ctx.createLinearGradient(0, 0, 0, ctx.canvas.height);
askGradient.addColorStop(0, 'rgba(255, 0, 0, 0.5)');
askGradient.addColorStop(1, 'rgba(255, 0, 0, 0)');
// Configure chart with proper axes and gradient effects
const config = {
type: 'line',
data: {
datasets: [
{
label: 'Bids',
data: extendedBids,
borderColor: 'green',
backgroundColor: bidGradient,
borderWidth: 2,
pointRadius: 0,
tension: 0.2, // Reduced tension to smooth the curve
fill: true,
},
{
label: 'Asks',
data: extendedAsks,
borderColor: 'red',
backgroundColor: askGradient,
borderWidth: 2,
pointRadius: 0,
tension: 0.2, // Reduced tension to smooth the curve
fill: true,
},
],
},
options: {
responsive: true,
animation: false,
plugins: {
legend: { position: 'top' },
tooltip: {
callbacks: {
label: function (tooltipItem) {
return `${tooltipItem.dataset.label}: ${tooltipItem.raw.y} XLM`;
},
},
},
},
scales: {
x: {
type: 'linear',
position: 'bottom',
title: { display: true, text: 'Price (USD/USDC per XLM)' },
ticks: {
callback: function (value) {
return value.toFixed(2); // Format price with 2 decimal places
},
},
// Reverse the bids to display them on the right side
reverse: false,
},
y: {
title: { display: true, text: 'Volume (XLM)' },
beginAtZero: true,
},
},
},
};
// Destroy the previous chart instance if it exists
if (chart) {
chart.destroy();
}
// Create new chart
chart = new Chart(ctx, config);
}
function getCumulativeVolumes(orders) {
let cumulativeVolume = 0;
return orders.map(order => {
cumulativeVolume += order.volume;
return { price: order.price, volume: cumulativeVolume };
});
}
// Initialize and fetch the orderbook every 1 second
function init() {
fetchOrderBook();
setInterval(fetchOrderBook, 1000); // Update the chart every 1 second
}
init();
</script>
HTML
<body>
<div class="container">
<canvas id="depthChart" height="400"></canvas>
</div>
</body>