Агрегация

This commit is contained in:
2025-12-13 12:31:21 +00:00
parent 6a22dc3ef7
commit f96b771fa9
9 changed files with 110 additions and 148 deletions

View File

@@ -1,87 +1,48 @@
#include "aggregation.hpp"
#include <map>
#include <algorithm>
#include <limits>
#include <cmath>
std::vector<DayStats> aggregate_days(const std::vector<Record>& records) {
// Группируем записи по дням
std::map<DayIndex, std::vector<const Record*>> day_records;
// Накопители для каждого дня
struct DayAccumulator {
double avg_sum = 0.0;
double open_min = std::numeric_limits<double>::max();
double open_max = std::numeric_limits<double>::lowest();
double close_min = std::numeric_limits<double>::max();
double close_max = std::numeric_limits<double>::lowest();
int64_t count = 0;
};
std::map<DayIndex, DayAccumulator> days;
for (const auto& r : records) {
DayIndex day = static_cast<DayIndex>(r.timestamp) / 86400;
day_records[day].push_back(&r);
auto& acc = days[day];
double avg = (r.low + r.high) / 2.0;
acc.avg_sum += avg;
acc.open_min = std::min(acc.open_min, r.open);
acc.open_max = std::max(acc.open_max, r.open);
acc.close_min = std::min(acc.close_min, r.close);
acc.close_max = std::max(acc.close_max, r.close);
acc.count++;
}
std::vector<DayStats> result;
result.reserve(day_records.size());
result.reserve(days.size());
for (auto& [day, recs] : day_records) {
// Сортируем по timestamp для определения first/last
std::sort(recs.begin(), recs.end(),
[](const Record* a, const Record* b) {
return a->timestamp < b->timestamp;
});
for (const auto& [day, acc] : days) {
DayStats stats;
stats.day = day;
stats.low = std::numeric_limits<double>::max();
stats.high = std::numeric_limits<double>::lowest();
stats.open = recs.front()->open;
stats.close = recs.back()->close;
stats.first_ts = recs.front()->timestamp;
stats.last_ts = recs.back()->timestamp;
for (const auto* r : recs) {
stats.low = std::min(stats.low, r->low);
stats.high = std::max(stats.high, r->high);
}
stats.avg = (stats.low + stats.high) / 2.0;
stats.avg = acc.avg_sum / static_cast<double>(acc.count);
stats.open_min = acc.open_min;
stats.open_max = acc.open_max;
stats.close_min = acc.close_min;
stats.close_max = acc.close_max;
stats.count = acc.count;
result.push_back(stats);
}
return result;
}
std::vector<DayStats> merge_day_stats(const std::vector<DayStats>& all_stats) {
// Объединяем статистику по одинаковым дням (если такие есть)
std::map<DayIndex, DayStats> merged;
for (const auto& s : all_stats) {
auto it = merged.find(s.day);
if (it == merged.end()) {
merged[s.day] = s;
} else {
// Объединяем данные за один день
auto& m = it->second;
m.low = std::min(m.low, s.low);
m.high = std::max(m.high, s.high);
// open берём от записи с меньшим timestamp
if (s.first_ts < m.first_ts) {
m.open = s.open;
m.first_ts = s.first_ts;
}
// close берём от записи с большим timestamp
if (s.last_ts > m.last_ts) {
m.close = s.close;
m.last_ts = s.last_ts;
}
m.avg = (m.low + m.high) / 2.0;
}
}
// Преобразуем в отсортированный вектор
std::vector<DayStats> result;
result.reserve(merged.size());
for (auto& [day, stats] : merged) {
result.push_back(stats);
}
return result;
}