Bar Chart
The "BarChart" component provides a candle chart for XLM with candle information.
Features
- Automatically fetches previous 12 hours of orders and current information and populates the chart.
- Automatically Updates live.
- Hover over the candles to see the price of XLM, high, low, open, close, and volume.
- Candles are set to 15 minute intervals.
- Provides a visual representation of the price of XLM over the last 12 hours and currently.
Additional Resources
Plotly provides opensource graphing libraries for making interactive, publication-quality graphs online. The Plotly library is available in Python, R, and JavaScript.
Review the documentation on Plotly graphs 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.BarChart/>
C#
@page "/RemoveSigner"
@rendermode InteractiveAuto
@using Microsoft.JSInterop
<div class="loading-container" id="loadingContainer">
<div class="spinner" id="spinner"></div> Loading...
</div>
<div class="chart-container">
<div id="tradingChart"></div>
</div>
@code {
[Inject] IJSRuntime JS { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// Call the initializeChart function in the external JavaScript file
await JS.InvokeVoidAsync("initializeChart");
}
}
}
<script src="https://cdn.jsdelivr.net/npm/plotly.js-dist@2.19.0/plotly.min.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/barChart.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 CHART_INTERVAL = 30 * 60 * 1000; // 30-minute candles
const REALTIME_INTERVAL = 5 * 1000; // 5 seconds update interval
const MAX_TIMEFRAME = 12 * 60 * 60 * 1000; // Last 12 hours
let historicalData = [];
async function fetchHistoricalTrades() {
let trades = [];
let cursor = 'now';
let keepFetching = true;
const now = Date.now();
while (keepFetching) {
const response = await server.trades()
.forAssetPair(xlmAsset, usdcAsset)
.order("desc")
.limit(200)
.cursor(cursor)
.call();
if (response.records.length === 0) break;
for (const trade of response.records) {
const tradeTime = new Date(trade.ledger_close_time).getTime();
if (now - tradeTime > MAX_TIMEFRAME) {
keepFetching = false;
break;
}
trades.push(trade);
}
cursor = response.records[response.records.length - 1].paging_token;
await new Promise(resolve => setTimeout(resolve, 200)); // Prevent API rate limiting
}
return processTradeData(trades);
}
function processTradeData(trades) {
const groupedData = [];
trades.forEach(trade => {
const time = new Date(trade.ledger_close_time);
const price = parseFloat(trade.price.n) / parseFloat(trade.price.d);
const amount = parseFloat(trade.base_amount);
const timeIndex = Math.floor(time.getTime() / CHART_INTERVAL) * CHART_INTERVAL;
let candle = groupedData.find(c => c.x === timeIndex);
if (!candle) {
candle = { x: timeIndex, o: price, h: price, l: price, c: price, volume: amount };
groupedData.push(candle);
} else {
candle.h = Math.max(candle.h, price);
candle.l = Math.min(candle.l, price);
candle.c = price;
candle.volume += amount;
}
});
return groupedData.sort((a, b) => a.x - b.x);
}
function renderChart(data) {
const ohlcData = data.map(d => ({
x: new Date(d.x),
open: d.o,
high: d.h,
low: d.l,
close: d.c
}));
const layout = {
title: 'XLM-USD Trading Chart [12-Hour History]',
xaxis: { type: 'date', title: 'Time', rangeslider: { visible: false } },
yaxis: { title: 'Price (USD)' },
paper_bgcolor: '#1a1a1a',
plot_bgcolor: '#1a1a1a',
font: { color: '#fff' }
};
Plotly.newPlot('tradingChart', [{
x: ohlcData.map(d => d.x),
open: ohlcData.map(d => d.open),
high: ohlcData.map(d => d.high),
low: ohlcData.map(d => d.low),
close: ohlcData.map(d => d.close),
type: 'candlestick',
increasing: {
line: { color: 'green' },
fillcolor: 'green' // Green fill matching the outline
},
decreasing: {
line: { color: 'red' },
fillcolor: 'red' // Red fill matching the outline
},
}], layout);
}
async function updateLastCandle() {
try {
const response = await server.trades()
.forAssetPair(xlmAsset, usdcAsset)
.order("desc")
.limit(1)
.call();
const trade = response.records[0];
const tradeTime = new Date(trade.ledger_close_time).getTime();
const price = parseFloat(trade.price.n) / parseFloat(trade.price.d);
const amount = parseFloat(trade.base_amount);
const timeIndex = Math.floor(tradeTime / CHART_INTERVAL) * CHART_INTERVAL;
let lastCandle = historicalData.find(c => c.x === timeIndex);
if (!lastCandle) {
lastCandle = { x: timeIndex, o: price, h: price, l: price, c: price, volume: amount };
historicalData.push(lastCandle);
} else {
lastCandle.h = Math.max(lastCandle.h, price);
lastCandle.l = Math.min(lastCandle.l, price);
lastCandle.c = price;
lastCandle.volume += amount;
}
historicalData.sort((a, b) => a.x - b.x);
renderChart(historicalData);
} catch (error) {
console.error("Error updating the last candle:", error);
}
}
// Rotate spinner with JavaScript
function rotateSpinner() {
const spinner = document.getElementById('spinner');
let angle = 0;
setInterval(() => {
angle += 6;
spinner.style.transform = `rotate(${angle}deg)`;
}, 50); // Rotate 6 degrees every 50ms
}
async function initializeChart() {
// Fetch historical data and render the chart
historicalData = await fetchHistoricalTrades();
renderChart(historicalData);
// Set up real-time updates every 5 seconds
setInterval(updateLastCandle, REALTIME_INTERVAL);
}
initializeChart();
</script>
HTML
<body>
<div class="chart-container">
<div id="tradingChart"></div>
</div>
</body>