initial commit
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}Real-Time Chart — IBKR Dashboard{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
<script src="https://unpkg.com/lightweight-charts/dist/lightweight-charts.standalone.production.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="chart-section">
|
||||
<div id="controls">
|
||||
<div class="control-group">
|
||||
<input type="text" id="symbolInput" placeholder="Enter symbol (e.g. AAPL)" value="{{ symbol }}">
|
||||
<button onclick="subscribeSymbol()">Load Chart</button>
|
||||
</div>
|
||||
<div class="loading-indicator" id="loadingIndicator">Loading...</div>
|
||||
</div>
|
||||
<div id="chart"></div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script>
|
||||
const chart = LightweightCharts.createChart(document.getElementById('chart'), {
|
||||
width: document.getElementById('chart').clientWidth,
|
||||
height: 600,
|
||||
layout: { background: { color: '#ffffff' }, textColor: '#333' },
|
||||
grid: { vertLines: { color: '#f0f0f0' }, horzLines: { color: '#f0f0f0' } },
|
||||
timeScale: { timeVisible: true, secondsVisible: false }
|
||||
});
|
||||
const series = chart.addCandlestickSeries();
|
||||
|
||||
let eventSource = null;
|
||||
|
||||
function cleanupConnections() {
|
||||
if (eventSource) {
|
||||
console.log('Closing EventSource connection');
|
||||
eventSource.close();
|
||||
eventSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
async function subscribeSymbol() {
|
||||
cleanupConnections();
|
||||
const symbol = document.getElementById("symbolInput").value.toUpperCase();
|
||||
document.getElementById("loadingIndicator").classList.add("show");
|
||||
document.getElementById("chart").classList.add("loading");
|
||||
|
||||
const historyResponse = await fetch(`/history?symbol=${symbol}`);
|
||||
const historicalData = await historyResponse.json();
|
||||
series.setData(historicalData);
|
||||
|
||||
await fetch("/subscribe", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ symbol })
|
||||
});
|
||||
|
||||
eventSource = new EventSource("/stream");
|
||||
|
||||
eventSource.addEventListener("candle", (event) => {
|
||||
const candleData = JSON.parse(event.data);
|
||||
series.update(candleData);
|
||||
});
|
||||
|
||||
eventSource.addEventListener("error", (event) => {
|
||||
console.error('SSE Error:', event);
|
||||
});
|
||||
|
||||
eventSource.addEventListener("open", () => {
|
||||
console.log('SSE Connection Opened');
|
||||
document.getElementById("loadingIndicator").classList.remove("show");
|
||||
document.getElementById("chart").classList.remove("loading");
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const symbol = urlParams.get('symbol');
|
||||
if (symbol) {
|
||||
document.getElementById("symbolInput").value = symbol;
|
||||
subscribeSymbol();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
chart.applyOptions({ width: document.getElementById('chart').clientWidth });
|
||||
});
|
||||
|
||||
window.addEventListener('beforeunload', cleanupConnections);
|
||||
window.addEventListener('pagehide', cleanupConnections);
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user