mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 09:45:36 +00:00
feat: foreign flow from IPOT by default (--source ipot|idx)
`idx stocks flow` now reads IPOT by default, which needs nothing installed: per session, the all-investor broker summary gives the value traded and the foreign one gives foreign buying (its footer), the foreign net and selling (buying less the net), across all boards, through the broker summary cache. IPOT's foreign net matched IDX's estimate within 0.3 B on BBCA 2026-10-12 to 16. `--source idx` (and `source` on get_foreign_flow) keeps IDX's trading summary: exact share counts, close and the non-regular share, behind curl-impersonate and Cloudflare. - ForeignFlowDay gains foreign_buy_value, foreign_sell_value and foreign_share_bps for both sources (estimated at the session average for IDX); ForeignFlow gains source, the value totals and rounded. - The table lays out each source's figures; the live smoke runs both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
This commit is contained in:
parent
b137dbf540
commit
8b507d78e2
37 changed files with 2080 additions and 143 deletions
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
use idx_core::api::types::{Interval, Period};
|
||||
use idx_core::broker::types::{BrokerBoard, BrokerInvestor};
|
||||
use idx_core::flow::types::FlowSource;
|
||||
use idx_core::market::{ScreenFilter, ScreenRegion};
|
||||
use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema};
|
||||
use serde::Deserialize;
|
||||
|
|
@ -170,6 +171,12 @@ pub struct FlowParams {
|
|||
/// Last session of the range, YYYY-MM-DD (default today).
|
||||
#[serde(default)]
|
||||
pub to: Option<String>,
|
||||
/// Where the figures come from (default "ipot"): "ipot" gives foreign buy, sell and net
|
||||
/// value across all boards; "idx" gives exact share counts, the close and the non-regular
|
||||
/// share, but needs curl-impersonate and may be blocked (HTTP 403).
|
||||
#[serde(default)]
|
||||
#[schemars(schema_with = "flow_source_schema")]
|
||||
pub source: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, JsonSchema)]
|
||||
|
|
@ -244,3 +251,7 @@ fn investor_schema(_: &mut SchemaGenerator) -> Schema {
|
|||
fn board_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
string_enum(BrokerBoard::ALL.map(BrokerBoard::as_str).to_vec())
|
||||
}
|
||||
|
||||
fn flow_source_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
string_enum(FlowSource::ALL.map(FlowSource::as_str).to_vec())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,11 +246,12 @@ foreign or domestic, shares are of that side's own buying (`buy_value`) and sell
|
|||
|
||||
#[tool(
|
||||
description = "Foreign investors' buying and selling of one IDX ticker, session by \
|
||||
session (oldest first), from IDX's daily trading summary: foreign buy, sell and net volume in \
|
||||
shares, `foreign_net_value` (net shares at the session's average price, an estimate, IDR), \
|
||||
`change_bps`, and `non_regular_bps` (share of all value traded outside the regular board). \
|
||||
Volume, value and foreign figures are the regular board. Totals cover the whole range; \
|
||||
`foreign_share_bps` is foreign investors' share of regular-board trading. End of day."
|
||||
session (oldest first), with range totals; end of day. With `source` \"ipot\" (default): \
|
||||
`foreign_buy_value`, `foreign_sell_value` and `foreign_net_value` in IDR across all boards, \
|
||||
`value` traded, and `foreign_share_bps` (foreign share of trading); share counts, close and \
|
||||
`non_regular_bps` are null, and `rounded` = true means one decimal of precision. With \
|
||||
\"idx\": exact foreign share counts on the regular board, values estimated at the session's \
|
||||
average price, the close, `change_bps` and `non_regular_bps`."
|
||||
)]
|
||||
async fn get_foreign_flow(&self, params: Parameters<FlowParams>) -> ToolResult {
|
||||
let FlowParams {
|
||||
|
|
@ -258,11 +259,13 @@ Volume, value and foreign figures are the regular board. Totals cover the whole
|
|||
days,
|
||||
from,
|
||||
to,
|
||||
source,
|
||||
} = params.0;
|
||||
self.live(move |idx| {
|
||||
let flow = idx.flow();
|
||||
let range = FlowRange::from_args(days, from.as_deref(), to.as_deref(), flow.today())?;
|
||||
flow.foreign(&symbol, range, CachePolicy::Default)
|
||||
let source = source.as_deref().unwrap_or("ipot").parse()?;
|
||||
flow.foreign(&symbol, range, source, CachePolicy::Default)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue