fix(intraday): mark a chart from before the latest session

stocks intraday never set quote.behind_session, so on a holiday or when
Stockbit lags, a past session's chart read as current. Mark it as quotes
do and print the same note under the header.

Claude-Session: https://claude.ai/code/session_01RqPPVeVDrnLoP7NUZmLRxY
This commit is contained in:
Rasyidan Akbar F. 2026-11-04 17:24:42 +07:00
commit 6f8d3c071a
10 changed files with 20 additions and 9 deletions

View file

@ -223,6 +223,9 @@ pub fn print_intraday(day: &Intraday, no_color: bool) -> Result<(), IdxError> {
if let Some(note) = &q.session_note { if let Some(note) = &q.session_note {
println!("Note: {}", terminal_safe(note)); println!("Note: {}", terminal_safe(note));
} }
for note in stale_quote_notes(std::slice::from_ref(q), chrono::Utc::now()) {
println!("{}", terminal_safe(&note));
}
let prices: Vec<f64> = day.points.iter().map(|p| p.price).collect(); let prices: Vec<f64> = day.points.iter().map(|p| p.price).collect();
if let (Some(first), Some(last)) = (day.points.first(), day.points.last()) { if let (Some(first), Some(last)) = (day.points.first(), day.points.last()) {

View file

@ -2,6 +2,7 @@ exit: 0
--- stdout --- stdout
^JKSE.JK 5,388 +60 (+1.12%) ^JKSE.JK 5,388 +60 (+1.12%)
prev close 5,328 · volume 36,446,806,700 · market close · last trade 2026-10-22 16:14 WIB prev close 5,328 · volume 36,446,806,700 · market close · last trade 2026-10-22 16:14 WIB
Note: ^JKSE.JK last traded on 2026-10-22; this price is not current.
▃▄▄▆▆▆▆▆▆▇▇▇▇▇████▇▇▇▇███▇▇▇▇███▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ ▃▄▄▆▆▆▆▆▆▇▇▇▇▇████▇▇▇▇███▇▇▇▇███▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇
08:58 to 16:14 WIB · low 5,192.41 · high 5,419.34 · 335 minutes 08:58 to 16:14 WIB · low 5,192.41 · high 5,419.34 · 335 minutes

File diff suppressed because one or more lines are too long

View file

@ -2,6 +2,7 @@ exit: 0
--- stdout --- stdout
BBCA.JK 5,175 -100 (-1.90%) BBCA.JK 5,175 -100 (-1.90%)
prev close 5,275 · volume 286,928,500 · market close · last trade 2026-10-22 16:14 WIB prev close 5,275 · volume 286,928,500 · market close · last trade 2026-10-22 16:14 WIB
Note: BBCA.JK last traded on 2026-10-22; this price is not current.
▄▅▇█▅▇▇▇▅▇▇▇▇▇▇██▇▅▇▅▅███▇▅▇▅▇▇▇▅▇▅▅▄▅▄▅▄▄▅▅▅▅▅▇▅▄▄▄▄▄▄▂▄▄▄▄ ▄▅▇█▅▇▇▇▅▇▇▇▇▇▇██▇▅▇▅▅███▇▅▇▅▇▇▇▅▇▅▅▄▅▄▅▄▄▅▅▅▅▅▇▅▄▄▄▄▄▄▂▄▄▄▄
08:58 to 16:14 WIB · low 5,125 · high 5,250 · 335 minutes 08:58 to 16:14 WIB · low 5,125 · high 5,250 · 335 minutes

View file

@ -75,7 +75,7 @@ impl Market<'_> {
let idx = self.idx; let idx = self.idx;
let resolved = idx.resolve(symbol)?; let resolved = idx.resolve(symbol)?;
let provider = intraday_provider(); let provider = intraday_provider();
cached_fetch( let mut day = cached_fetch(
&idx.cache, &idx.cache,
CacheSpec { CacheSpec {
bucket: "stockbit-intraday", bucket: "stockbit-intraday",
@ -87,7 +87,11 @@ impl Market<'_> {
policy, policy,
|| provider.intraday(&resolved), || provider.intraday(&resolved),
Ok, Ok,
) )?;
// Stockbit's page keeps the last session's chart up after the close,
// so a cached or lagging day reads as current unless it is marked.
mark_behind_session(&mut day.data.quote, latest_session(Utc::now()));
Ok(day)
} }
/// Resolves the history source for an optional `--history-provider` /// Resolves the history source for an optional `--history-provider`

View file

@ -143,8 +143,9 @@ minutes."
`market_status`, `bid`/`offer` only while the market is open, `session_note`) and \ `market_status`, `bid`/`offer` only while the market is open, `session_note`) and \
`points`, the price per minute in WIB, oldest first. Delayed at least 10 minutes; no \ `points`, the price per minute in WIB, oldest first. Delayed at least 10 minutes; no \
per-minute volume. Empty `points` means the stock did not trade this session (see \ per-minute volume. Empty `points` means the stock did not trade this session (see \
`session_note`), not an error. UPSTREAMBLOCKED means stockbit.com refused this machine \ `session_note`), not an error. `quote.behind_session` is true when the chart is from \
(HTTP 403): do not retry at once." before the latest IDX session (a holiday, or Stockbit lagging), as in get_quotes. \
UPSTREAMBLOCKED means stockbit.com refused this machine (HTTP 403): do not retry at once."
)] )]
async fn get_intraday(&self, params: Parameters<IntradayParams>) -> ToolResult { async fn get_intraday(&self, params: Parameters<IntradayParams>) -> ToolResult {
let IntradayParams { symbol, tail } = params.0; let IntradayParams { symbol, tail } = params.0;

View file

@ -288,7 +288,7 @@
"name": "get_foreign_flow" "name": "get_foreign_flow"
}, },
{ {
"description": "Today's session of one IDX stock or index from Stockbit's public page (no login), whichever provider the server uses: `quote` (price, change, volume, `market_status`, `bid`/`offer` only while the market is open, `session_note`) and `points`, the price per minute in WIB, oldest first. Delayed at least 10 minutes; no per-minute volume. Empty `points` means the stock did not trade this session (see `session_note`), not an error. UPSTREAMBLOCKED means stockbit.com refused this machine (HTTP 403): do not retry at once.", "description": "Today's session of one IDX stock or index from Stockbit's public page (no login), whichever provider the server uses: `quote` (price, change, volume, `market_status`, `bid`/`offer` only while the market is open, `session_note`) and `points`, the price per minute in WIB, oldest first. Delayed at least 10 minutes; no per-minute volume. Empty `points` means the stock did not trade this session (see `session_note`), not an error. `quote.behind_session` is true when the chart is from before the latest IDX session (a holiday, or Stockbit lagging), as in get_quotes. UPSTREAMBLOCKED means stockbit.com refused this machine (HTTP 403): do not retry at once.",
"inputSchema": { "inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema", "$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": { "properties": {

View file

@ -82,7 +82,7 @@ WIB as the fallback.
`behind_session` when `as_of` is before the latest weekday whose session has `behind_session` when `as_of` is before the latest weekday whose session has
ended (16:15 WIB). It is computed on return, not cached; MSN can lag the close ended (16:15 WIB). It is computed on return, not cached; MSN can lag the close
by hours, and on an exchange holiday every quote reads as behind. Only `.JK` by hours, and on an exchange holiday every quote reads as behind. Only `.JK`
quotes and `--region id` screens are marked; other exchanges keep other hours. quotes, `--region id` screens and `stocks intraday` are marked; other exchanges keep other hours.
Table output notes behind quotes, and calls those over seven days old not Table output notes behind quotes, and calls those over seven days old not
current. current.
- `change`, `change_pct`, and `volume` are nullable when the provider omits them; - `change`, `change_pct`, and `volume` are nullable when the provider omits them;

View file

@ -30,7 +30,8 @@ idx -o json stocks intraday BBCA | jq '.points[-1]'
`intraday` shows today's session from Stockbit's public page, without a `intraday` shows today's session from Stockbit's public page, without a
login: the quote, the best bid and offer while the market is open, a login: the quote, the best bid and offer while the market is open, a
sparkline and the last five minutes. JSON gives every minute in `points`. It sparkline and the last five minutes. JSON gives every minute in `points`. It
is delayed at least 10 minutes. See [Stockbit](/cli/stockbit/) for what it is delayed at least 10 minutes. A chart from before the latest session is
noted under the header and sets `quote.behind_session`, as with quotes. See [Stockbit](/cli/stockbit/) for what it
covers and the terms it comes with. covers and the terms it comes with.
## Company data ## Company data

View file

@ -77,7 +77,7 @@ Foreign investors' buying and selling of one IDX ticker, session by session (old
## `get_intraday` ## `get_intraday`
Today's session of one IDX stock or index from Stockbit's public page (no login), whichever provider the server uses: `quote` (price, change, volume, `market_status`, `bid`/`offer` only while the market is open, `session_note`) and `points`, the price per minute in WIB, oldest first. Delayed at least 10 minutes; no per-minute volume. Empty `points` means the stock did not trade this session (see `session_note`), not an error. UPSTREAMBLOCKED means stockbit.com refused this machine (HTTP 403): do not retry at once. Today's session of one IDX stock or index from Stockbit's public page (no login), whichever provider the server uses: `quote` (price, change, volume, `market_status`, `bid`/`offer` only while the market is open, `session_note`) and `points`, the price per minute in WIB, oldest first. Delayed at least 10 minutes; no per-minute volume. Empty `points` means the stock did not trade this session (see `session_note`), not an error. `quote.behind_session` is true when the chart is from before the latest IDX session (a holiday, or Stockbit lagging), as in get_quotes. UPSTREAMBLOCKED means stockbit.com refused this machine (HTTP 403): do not retry at once.
| Input | Type | Required | Description | | Input | Type | Required | Description |
| --- | --- | --- | --- | | --- | --- | --- | --- |