diff --git a/src/app.h b/src/app.h index 683e3c6..14de6f1 100644 --- a/src/app.h +++ b/src/app.h @@ -687,6 +687,14 @@ private: std::string exchange_chart_key_; // ":/" of the loaded series ("" = none) bool exchange_chart_fetch_in_flight_ = false; std::chrono::steady_clock::time_point exchange_chart_last_fetch_{}; + // Per-pair candle cache: switching back to a recently-viewed venue loads instantly (no re-fetch) + // instead of overwriting the single active buffer. Keyed like exchange_chart_key_. + struct ExchangeChartCache { + std::vector> closeIntraday, closeDaily; + std::vector ohlcIntraday, ohlcDaily; + std::chrono::steady_clock::time_point fetchedAt{}; + }; + std::unordered_map exchange_chart_cache_; util::AsyncTaskManager async_tasks_; bool pending_antivirus_dialog_ = false; // Show Windows Defender help dialog diff --git a/src/app_network.cpp b/src/app_network.cpp index 9643bf1..56a4fba 100644 --- a/src/app_network.cpp +++ b/src/app_network.cpp @@ -1806,6 +1806,19 @@ void App::refreshExchangeChart() if (key == exchange_chart_key_ && state_.market.exchange_chart_active && std::chrono::steady_clock::now() - exchange_chart_last_fetch_ < std::chrono::minutes(30)) return; + // Cached from a recent view of this pair -> load instantly, no re-fetch (switching back is snappy). + if (auto it = exchange_chart_cache_.find(key); + it != exchange_chart_cache_.end() && + std::chrono::steady_clock::now() - it->second.fetchedAt < std::chrono::minutes(30)) { + state_.market.exchange_chart_intraday = it->second.closeIntraday; + state_.market.exchange_chart_daily = it->second.closeDaily; + state_.market.exchange_ohlc_intraday = it->second.ohlcIntraday; + state_.market.exchange_ohlc_daily = it->second.ohlcDaily; + state_.market.exchange_chart_active = true; + exchange_chart_key_ = key; + exchange_chart_last_fetch_ = it->second.fetchedAt; + return; + } // Switching pairs: fall back to the aggregate until the new venue's candles arrive. if (key != exchange_chart_key_) state_.market.exchange_chart_active = false; @@ -1824,18 +1837,25 @@ void App::refreshExchangeChart() return [this, key, ohlcIntra = std::move(ohlcIntra), ohlcDaily = std::move(ohlcDaily)]() mutable { exchange_chart_fetch_in_flight_ = false; if (!ohlcDaily.empty() || !ohlcIntra.empty()) { - // Derive close series (line + change%) from the OHLC (candles). - std::vector> closeIntra, closeDaily; - closeIntra.reserve(ohlcIntra.size()); closeDaily.reserve(ohlcDaily.size()); - for (const auto& c : ohlcIntra) closeIntra.emplace_back(c.time, c.close); - for (const auto& c : ohlcDaily) closeDaily.emplace_back(c.time, c.close); - state_.market.exchange_chart_intraday = std::move(closeIntra); - state_.market.exchange_chart_daily = std::move(closeDaily); - state_.market.exchange_ohlc_intraday = std::move(ohlcIntra); - state_.market.exchange_ohlc_daily = std::move(ohlcDaily); + // Build a cache entry (OHLC + derived close series for the line/change%), publish it to + // the active buffer, and keep it so switching back to this pair later is instant. + ExchangeChartCache e; + e.ohlcIntraday = std::move(ohlcIntra); + e.ohlcDaily = std::move(ohlcDaily); + e.closeIntraday.reserve(e.ohlcIntraday.size()); + e.closeDaily.reserve(e.ohlcDaily.size()); + for (const auto& c : e.ohlcIntraday) e.closeIntraday.emplace_back(c.time, c.close); + for (const auto& c : e.ohlcDaily) e.closeDaily.emplace_back(c.time, c.close); + e.fetchedAt = std::chrono::steady_clock::now(); + state_.market.exchange_chart_intraday = e.closeIntraday; + state_.market.exchange_chart_daily = e.closeDaily; + state_.market.exchange_ohlc_intraday = e.ohlcIntraday; + state_.market.exchange_ohlc_daily = e.ohlcDaily; state_.market.exchange_chart_active = true; exchange_chart_key_ = key; - exchange_chart_last_fetch_ = std::chrono::steady_clock::now(); + exchange_chart_last_fetch_ = e.fetchedAt; + if (exchange_chart_cache_.size() >= 16) exchange_chart_cache_.clear(); // bound it (many venues) + exchange_chart_cache_[key] = std::move(e); } else { // Both ranges empty -> the venue's API failed/changed; keep the aggregate. state_.market.exchange_chart_active = false;