initial commit

This commit is contained in:
coddard
2026-05-18 00:31:08 +03:00
commit 0096c8819b
26 changed files with 2851 additions and 0 deletions
+93
View File
@@ -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 %}