mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 09:45:36 +00:00
fix: mark only IDX quotes behind the session; test the wiring
Review findings on #71: - The IDX session rule flagged non-IDX data: US screen rows on Monday evening WIB, and JP/HK/SG rows on their own holidays. Only `.JK` quotes and `--region id` screens are marked now. - Nothing tested the marking call sites. A screen test checks IDX rows online and offline, and US rows unmarked. A quote test reads a cache entry in 0.3.3's format (no field) offline. - The get_quotes description now says the flag also means the stock did not trade, or an exchange holiday; screen_stocks mentions the field. - latest_session is pub(crate). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
This commit is contained in:
parent
a0a2cac7cf
commit
834e47b336
7 changed files with 85 additions and 20 deletions
|
|
@ -51,8 +51,9 @@ pub struct Quote {
|
|||
#[serde(default)]
|
||||
pub as_of: Option<DateTime<FixedOffset>>,
|
||||
/// True when `as_of` is before the latest IDX session that has ended: the
|
||||
/// provider has not caught up yet (MSN can lag hours after the close), or
|
||||
/// the stock did not trade. False when `as_of` is unknown. Set when the
|
||||
/// provider has not caught up yet (MSN can lag hours after the close), the
|
||||
/// stock did not trade, or the day was an exchange holiday. False when
|
||||
/// `as_of` is unknown and for non-IDX symbols and regions. Set when the
|
||||
/// quote is returned, not when it is cached.
|
||||
#[serde(default)]
|
||||
pub behind_session: bool,
|
||||
|
|
|
|||
|
|
@ -34,10 +34,11 @@ impl Market<'_> {
|
|||
) -> Result<Vec<Fetched<Quote>>, IdxError> {
|
||||
let idx = self.idx;
|
||||
let bucket = idx.bucket("quote");
|
||||
let session = latest_session(Utc::now());
|
||||
let mut quotes = Vec::with_capacity(symbols.len());
|
||||
for symbol in symbols {
|
||||
let resolved = idx.resolve(symbol.as_ref())?;
|
||||
quotes.push(cached_fetch(
|
||||
let mut quote = cached_fetch(
|
||||
&idx.cache,
|
||||
CacheSpec {
|
||||
bucket: &bucket,
|
||||
|
|
@ -49,11 +50,12 @@ impl Market<'_> {
|
|||
policy,
|
||||
|| idx.provider.market().quote(&resolved),
|
||||
Ok,
|
||||
)?);
|
||||
}
|
||||
let session = latest_session(Utc::now());
|
||||
for quote in &mut quotes {
|
||||
mark_behind_session(&mut quote.data, session);
|
||||
)?;
|
||||
// The session rule is IDX's; other exchanges keep other hours.
|
||||
if resolved.ends_with(".JK") {
|
||||
mark_behind_session(&mut quote.data, session);
|
||||
}
|
||||
quotes.push(quote);
|
||||
}
|
||||
Ok(quotes)
|
||||
}
|
||||
|
|
@ -137,9 +139,11 @@ impl Market<'_> {
|
|||
)?;
|
||||
sort_screener_quotes(&mut fetched.data, filter);
|
||||
fetched.data.truncate(limit);
|
||||
let session = latest_session(Utc::now());
|
||||
for quote in &mut fetched.data {
|
||||
mark_behind_session(quote, session);
|
||||
if region == ScreenRegion::Id {
|
||||
let session = latest_session(Utc::now());
|
||||
for quote in &mut fetched.data {
|
||||
mark_behind_session(quote, session);
|
||||
}
|
||||
}
|
||||
Ok(fetched)
|
||||
}
|
||||
|
|
@ -151,7 +155,7 @@ const SESSION_END: NaiveTime = NaiveTime::from_hms_opt(16, 15, 0).expect("valid
|
|||
|
||||
/// The latest weekday whose IDX session has ended by `now`. Exchange holidays
|
||||
/// are not known offline, so on a weekday holiday this is the holiday itself.
|
||||
pub fn latest_session(now: DateTime<Utc>) -> NaiveDate {
|
||||
pub(crate) fn latest_session(now: DateTime<Utc>) -> NaiveDate {
|
||||
let now = now.with_timezone(&idx_offset());
|
||||
let mut day = now.date_naive();
|
||||
if now.time() < SESSION_END {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue