performance improvements by pre-defining queries
All checks were successful
Deployment / deploy-docker (push) Successful in 17s

This commit is contained in:
Melchior Reimers
2026-01-25 17:11:05 +01:00
parent 9772d81f7d
commit 786fef2e71
4 changed files with 329 additions and 42 deletions

View File

@@ -268,6 +268,10 @@
<option value="1">Today</option>
<option value="7">Last 7 Days</option>
<option value="30">Last 30 Days</option>
<option value="42">Last 42 Days</option>
<option value="69">Last 69 Days</option>
<option value="180">Last 6 Months (180d)</option>
<option value="365">Last Year (365d)</option>
<option value="ytd">Year to Date (YTD)</option>
<option value="year">Full Year 2026</option>
<option value="custom">Custom Range...</option>
@@ -585,18 +589,36 @@
if (y === 'all') {
// Dual axis for breakdown
// Volume Dataset
const volData = labels.map(l => {
const row = data.find(r => r[0] === l && r[1] === name);
return row ? row[3] : 0; // value_volume is index 3
});
datasets.push({
label: `${name} (Vol)`,
data: labels.map(l => {
const row = data.find(r => r[0] === l && r[1] === name);
return row ? row[3] : 0; // value_volume is index 3
}),
data: volData,
backgroundColor: `hsla(${hue}, 75%, 50%, 0.7)`,
borderColor: `hsla(${hue}, 75%, 50%, 1)`,
borderWidth: 2,
yAxisID: 'y',
type: 'bar'
});
// Add MA7 for Volume if enough data points
if (volData.length > 7) {
const ma7 = calculateMA(volData, 7);
datasets.push({
label: `${name} (Vol MA7)`,
data: ma7,
borderColor: `hsla(${hue}, 90%, 80%, 0.8)`,
borderWidth: 1.5,
borderDash: [5, 5],
pointRadius: 0,
yAxisID: 'y',
type: 'line',
tension: 0.4
});
}
// Count Dataset
datasets.push({
label: `${name} (Cnt)`,
@@ -864,6 +886,22 @@
updateUrlParams();
}
function calculateMA(data, period) {
let ma = [];
for (let i = 0; i < data.length; i++) {
if (i < period - 1) {
ma.push(null);
continue;
}
let sum = 0;
for (let j = 0; j < period; j++) {
sum += data[i - j] || 0;
}
ma.push(sum / period);
}
return ma;
}
function fillMetadataTable() {
const tbody = document.getElementById('metadataRows');
tbody.innerHTML = store.metadata.map(r => `

View File

@@ -114,41 +114,118 @@ async def get_analytics(
"exchange_sector": f"concat({t_prefix}exchange, ' - ', coalesce({m_prefix}sector, 'Unknown'))" if needs_metadata else "'Unknown'"
}
selected_metric = metrics_map.get(metric, metrics_map["volume"])
selected_group = groups_map.get(group_by, groups_map["day"])
# Determine table based on granularity and needs
# For day/month aggregation without ISIN specific filtering, use analytics_daily
# But analytics_daily doesn't have individual ISINs (except via another table)
# So if ISIN filter is off, use analytics_daily
query = f"select {selected_group} as label"
use_analytics_table = False
if sub_group_by and sub_group_by in groups_map:
query += f", {groups_map[sub_group_by]} as sub_label"
if metric == 'all':
query += f", count(*) as value_count, sum({t_prefix}price * {t_prefix}quantity) as value_volume from trades"
else:
query += f", {selected_metric} as value from trades"
if needs_metadata:
query += " t left join metadata m on t.isin = m.isin"
# Check if we can use the pre-aggregated table
if not isins and not sub_group_by == "isin" and group_by != "isin" and group_by != "name":
use_analytics_table = True
query += " where 1=1"
table_name = "analytics_daily" if use_analytics_table else "trades"
if date_from:
query += f" and {t_prefix}timestamp >= '{date_from}'"
if date_to:
query += f" and {t_prefix}timestamp <= '{date_to}'"
if isins:
isins_list = ",".join([f"'{i.strip()}'" for i in isins.split(",")])
query += f" and {t_prefix}isin in ({isins_list})"
# If using analytics table, columns might be named differently?
# analytics_daily: timestamp, exchange, sector, continent, volume, trade_count, avg_price
# We need to map our generic query builder to this table
# This might be tricky if column names don't align exactly or if we need dynamic mapping.
# To keep it safe for now, let's just stick to 'trades' but hint towards optimization.
# Actually, let's implement IT for the main view (Exchange/Continent breakdown)
if use_analytics_table:
# Simplified query for analytics table
# Note: timestamps are day-aligned in analytics table
# Adjust metric mapping for analytics table
metrics_map_opt = {
"volume": "sum(volume)",
"count": "sum(trade_count)",
"avg_price": "avg(avg_price)", # Not mathematically perfect but close for display
"all": "count(*) as value_count, sum(volume) as value_volume" # Wait, 'all' needs specific handling
}
if metric == 'all':
metric_expr = "sum(trade_count) as value_count, sum(volume) as value_volume"
else:
metric_expr = f"{metrics_map_opt.get(metric, 'sum(volume)')} as value"
if continents and needs_metadata:
cont_list = ",".join([f"'{c.strip()}'" for c in continents.split(",")])
query += f" and {m_prefix}continent in ({cont_list})"
# Group mapping logic
# analytics_daily has: timestamp, exchange, sector, continent
groups_map_opt = {
"day": "timestamp",
"month": "date_trunc('month', timestamp)",
"exchange": "exchange",
"continent": "continent",
"sector": "sector",
"exchange_continent": "concat(exchange, ' - ', continent)",
"exchange_sector": "concat(exchange, ' - ', sector)"
}
sel_group_expr = groups_map_opt.get(group_by, "timestamp")
query = f"select {sel_group_expr} as label"
if sub_group_by and sub_group_by in groups_map_opt:
query += f", {groups_map_opt[sub_group_by]} as sub_label"
query += f", {metric_expr} from analytics_daily where 1=1"
if date_from: query += f" and timestamp >= '{date_from}'"
if date_to: query += f" and timestamp <= '{date_to}'"
# Filters
if continents:
cont_list = ",".join([f"'{c.strip()}'" for c in continents.split(",")])
query += f" and continent in ({cont_list})"
query += f" group by {sel_group_expr}"
if sub_group_by: query += f", {groups_map_opt[sub_group_by]}"
query += " order by label asc"
else:
# Fallback to RAW TRADES query (existing logic)
# ... (keep existing logic but indented/wrapped)
selected_metric = metrics_map.get(metric, metrics_map["volume"])
selected_group = groups_map.get(group_by, groups_map["day"])
query += f" group by {selected_group}"
if sub_group_by and sub_group_by in groups_map:
query += f", {groups_map[sub_group_by]}"
query += " order by label asc"
query = f"select {selected_group} as label"
if sub_group_by and sub_group_by in groups_map:
query += f", {groups_map[sub_group_by]} as sub_label"
if metric == 'all':
query += f", count(*) as value_count, sum({t_prefix}price * {t_prefix}quantity) as value_volume from trades"
else:
query += f", {selected_metric} as value from trades"
if needs_metadata:
query += " t left join metadata m on t.isin = m.isin"
query += " where 1=1"
if date_from:
query += f" and {t_prefix}timestamp >= '{date_from}'"
if date_to:
query += f" and {t_prefix}timestamp <= '{date_to}'"
if isins:
isins_list = ",".join([f"'{i.strip()}'" for i in isins.split(",")])
query += f" and {t_prefix}isin in ({isins_list})"
if continents and needs_metadata:
cont_list = ",".join([f"'{c.strip()}'" for c in continents.split(",")])
query += f" and {m_prefix}continent in ({cont_list})"
query += f" group by {selected_group}"
if sub_group_by and sub_group_by in groups_map:
query += f", {groups_map[sub_group_by]}"
query += " order by label asc"
try:
response = requests.get(f"http://{DB_HOST}:9000/exec", params={'query': query}, auth=DB_AUTH)