updated
All checks were successful
Deployment / deploy-docker (push) Successful in 9s

This commit is contained in:
Melchior Reimers
2026-01-25 17:46:47 +01:00
parent eb9c822cff
commit 64ffd9aa32
2 changed files with 56 additions and 11 deletions

View File

@@ -547,10 +547,11 @@
async function fetchData() { async function fetchData() {
try { try {
// Verwende limit für trades um Performance zu verbessern
const [t, m, s] = await Promise.all([ const [t, m, s] = await Promise.all([
fetch(`${API}/trades?days=7`).then(r => r.json()), fetch(`${API}/trades?days=7&limit=1000`).then(r => r.json()),
fetch(`${API}/metadata`).then(r => r.json()), fetch(`${API}/metadata`).then(r => r.json()),
fetch(`${API}/summary`).then(r => r.json()) fetch(`${API}/summary?days=7`).then(r => r.json())
]); ]);
store = { ...store, trades: t.dataset || [], metadata: m.dataset || [], summary: s.dataset || [] }; store = { ...store, trades: t.dataset || [], metadata: m.dataset || [], summary: s.dataset || [] };
updateDashboard(); updateDashboard();

View File

@@ -28,11 +28,15 @@ DB_AUTH = (DB_USER, DB_PASSWORD) if DB_USER and DB_PASSWORD else None
DB_HOST = os.getenv("DB_HOST", "questdb") DB_HOST = os.getenv("DB_HOST", "questdb")
@app.get("/api/trades") @app.get("/api/trades")
async def get_trades(isin: str = None, days: int = 7): async def get_trades(isin: str = None, days: int = 7, limit: int = 1000):
"""
Gibt Trades zurück. Standardmäßig limitiert auf 1000 für Performance.
Für Dashboard-Übersicht werden nur die neuesten Trades benötigt.
"""
query = f"select * from trades where timestamp > dateadd('d', -{days}, now())" query = f"select * from trades where timestamp > dateadd('d', -{days}, now())"
if isin: if isin:
query += f" and isin = '{isin}'" query += f" and isin = '{isin}'"
query += " order by timestamp asc" query += f" order by timestamp desc limit {limit}"
try: try:
response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH) response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH)
@@ -54,19 +58,56 @@ async def get_metadata():
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/summary") @app.get("/api/summary")
async def get_summary(): async def get_summary(days: int = 7):
# Coalesce null values to 'Unknown' and group properly """
query = """ Gibt Zusammenfassung zurück. Optimiert für schnelle Abfrage.
Falls vorberechnete Daten verfügbar sind, verwende diese.
"""
# Versuche zuerst, aus analytics_exchange_daily zu aggregieren (schneller)
# Falls das nicht funktioniert, falle auf die ursprüngliche Query zurück
try:
# Aggregiere aus analytics_exchange_daily für die letzten N Tage
# Dies ist schneller als eine JOIN-Query auf alle Trades
query = f"""
select
'All' as continent,
sum(trade_count) as trade_count,
sum(volume) as total_volume
from analytics_exchange_daily
where timestamp >= dateadd('d', -{days}, now())
"""
response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH, timeout=5)
if response.status_code == 200:
data = response.json()
# Wenn Daten vorhanden, verwende diese
if data.get('dataset') and len(data['dataset']) > 0:
# Formatiere für Kompatibilität mit dem Frontend
result = {
'columns': [
{'name': 'continent'},
{'name': 'trade_count'},
{'name': 'total_volume'}
],
'dataset': [[row[0], row[1], row[2]] for row in data['dataset']]
}
return result
except Exception:
# Fallback auf ursprüngliche Query
pass
# Fallback: Original Query mit Limit für Performance
query = f"""
select select
coalesce(m.continent, 'Unknown') as continent, coalesce(m.continent, 'Unknown') as continent,
count(*) as trade_count, count(*) as trade_count,
sum(t.price * t.quantity) as total_volume sum(t.price * t.quantity) as total_volume
from trades t from trades t
left join metadata m on t.isin = m.isin left join metadata m on t.isin = m.isin
where t.timestamp > dateadd('d', -{days}, now())
group by continent group by continent
""" """
try: try:
response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH) response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH, timeout=10)
if response.status_code == 200: if response.status_code == 200:
return response.json() return response.json()
throw_http_error(response) throw_http_error(response)
@@ -175,6 +216,7 @@ async def get_moving_average(days: int = 7, exchange: str = None):
""" """
Gibt Moving Average Daten für Tradezahlen und Volumen je Exchange zurück. Gibt Moving Average Daten für Tradezahlen und Volumen je Exchange zurück.
Unterstützte Zeiträume: 7, 30, 42, 69, 180, 365 Tage Unterstützte Zeiträume: 7, 30, 42, 69, 180, 365 Tage
Verwendet vorberechnete Daten aus analytics_exchange_daily für schnelle Antwortzeiten.
""" """
if days not in [7, 30, 42, 69, 180, 365]: if days not in [7, 30, 42, 69, 180, 365]:
raise HTTPException(status_code=400, detail="Invalid days parameter. Must be one of: 7, 30, 42, 69, 180, 365") raise HTTPException(status_code=400, detail="Invalid days parameter. Must be one of: 7, 30, 42, 69, 180, 365")
@@ -198,7 +240,7 @@ async def get_moving_average(days: int = 7, exchange: str = None):
query += " order by date asc, exchange asc" query += " order by date asc, exchange asc"
try: try:
response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH) response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH, timeout=5)
if response.status_code == 200: if response.status_code == 200:
return response.json() return response.json()
throw_http_error(response) throw_http_error(response)
@@ -210,6 +252,7 @@ async def get_volume_changes(days: int = 7):
""" """
Gibt Änderungen in Volumen und Anzahl je Exchange zurück. Gibt Änderungen in Volumen und Anzahl je Exchange zurück.
Unterstützte Zeiträume: 7, 30, 42, 69, 180, 365 Tage Unterstützte Zeiträume: 7, 30, 42, 69, 180, 365 Tage
Verwendet vorberechnete Daten aus analytics_volume_changes für schnelle Antwortzeiten.
""" """
if days not in [7, 30, 42, 69, 180, 365]: if days not in [7, 30, 42, 69, 180, 365]:
raise HTTPException(status_code=400, detail="Invalid days parameter. Must be one of: 7, 30, 42, 69, 180, 365") raise HTTPException(status_code=400, detail="Invalid days parameter. Must be one of: 7, 30, 42, 69, 180, 365")
@@ -229,7 +272,7 @@ async def get_volume_changes(days: int = 7):
""" """
try: try:
response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH) response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH, timeout=5)
if response.status_code == 200: if response.status_code == 200:
return response.json() return response.json()
throw_http_error(response) throw_http_error(response)
@@ -241,6 +284,7 @@ async def get_stock_trends(days: int = 7, limit: int = 20):
""" """
Gibt Trendanalyse für häufig gehandelte Aktien zurück. Gibt Trendanalyse für häufig gehandelte Aktien zurück.
Unterstützte Zeiträume: 7, 30, 42, 69, 180, 365 Tage Unterstützte Zeiträume: 7, 30, 42, 69, 180, 365 Tage
Verwendet vorberechnete Daten aus analytics_stock_trends für schnelle Antwortzeiten.
""" """
if days not in [7, 30, 42, 69, 180, 365]: if days not in [7, 30, 42, 69, 180, 365]:
raise HTTPException(status_code=400, detail="Invalid days parameter. Must be one of: 7, 30, 42, 69, 180, 365") raise HTTPException(status_code=400, detail="Invalid days parameter. Must be one of: 7, 30, 42, 69, 180, 365")
@@ -261,7 +305,7 @@ async def get_stock_trends(days: int = 7, limit: int = 20):
""" """
try: try:
response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH) response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH, timeout=5)
if response.status_code == 200: if response.status_code == 200:
return response.json() return response.json()
throw_http_error(response) throw_http_error(response)