From 0a27d01f129081670dac5a5201ad0290b342d70d Mon Sep 17 00:00:00 2001 From: Per Magnus Petersen Date: Tue, 3 Nov 2026 10:32:23 +0100 Subject: [PATCH] Show 30-minute candles on the last-24-hours chart --- README.md | 4 ++++ app/main.py | 9 +++++++-- tests/test_health.py | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d87c24b..ff84d40 100644 --- a/README.md +++ b/README.md @@ -127,3 +127,7 @@ color-coded (green up, red down). Reconnection is handled by HTMX. Python · FastAPI · Uvicorn · websockets · HTMX · Tailwind CSS v4 The Clojure implementation this replaced is on the `clojure` branch. + +The 24-hour chart uses 48 half-hour candles from rustbtcdata’s +`/api/kraken-half-hour` endpoint, aggregated from minute OHLC data. It refreshes +every five minutes and includes the current partial half-hour candle. diff --git a/app/main.py b/app/main.py index 84919b2..6278ed2 100644 --- a/app/main.py +++ b/app/main.py @@ -73,7 +73,7 @@ HOME_HTML = """\
-

24h Candles (1h)

+

24h Candles (30m)

@@ -170,7 +170,7 @@ HOME_HTML = """\ } initChart('chart-minute', '/api/kraken-minute', 60 * 1000); - initChart('chart-hour', '/api/kraken-hour', 5 * 60 * 1000, updateMidnightPrice); + initChart('chart-hour', '/api/kraken-half-hour', 5 * 60 * 1000, updateMidnightPrice); })(); @@ -233,6 +233,11 @@ async def _proxy_btcdata_json(path: str) -> JSONResponse: ) +@app.get("/api/kraken-half-hour") +async def kraken_half_hour(): + return await _proxy_btcdata_json("/api/kraken-half-hour") + + @app.get("/api/kraken-hour") async def kraken_hour(): return await _proxy_btcdata_json("/api/kraken-hour") diff --git a/tests/test_health.py b/tests/test_health.py index 6c68a3c..67ee1b4 100644 --- a/tests/test_health.py +++ b/tests/test_health.py @@ -107,3 +107,22 @@ def test_version_endpoint(monkeypatch): assert response.status_code == 200 assert response.json() == {"version": "abc1234"} + + +def test_24_hour_chart_uses_half_hour_candles(): + response = TestClient(main.app).get("/") + assert "24h Candles (30m)" in response.text + assert "initChart('chart-hour', '/api/kraken-half-hour', 5 * 60 * 1000, updateMidnightPrice)" in response.text + assert "initChart('chart-minute', '/api/kraken-minute', 60 * 1000)" in response.text + + +def test_half_hour_proxy_preserves_candles_and_upstream_errors(monkeypatch): + for status, payload in [(200, [{"ts": 1800, "open": "10", "high": "12", "low": "9", "close": "11"}]), (503, {"error": "database unavailable"})]: + request = httpx.Request("GET", "http://btcdata.test/api/kraken-half-hour") + client = StubAsyncClient(response=httpx.Response(status, json=payload, request=request)) + monkeypatch.setattr(main, "BTCDATA_URL", "http://btcdata.test") + monkeypatch.setattr(main.httpx, "AsyncClient", lambda: client) + response = TestClient(main.app).get("/api/kraken-half-hour") + assert response.status_code == status + assert response.json() == payload + assert client.requested_url == "http://btcdata.test/api/kraken-half-hour" -- 2.54.0