mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-08-07 01:33:52 +00:00
chore: move internal docs to docs-internal/ and gitignore
- SPEC.md, OWNERSHIP_FEATURE_DESIGN.md, research artifacts → docs-internal/ - gitignore docs-internal/ and research/ to keep strategy private
This commit is contained in:
parent
d457c630c4
commit
8c7c70a57a
7 changed files with 5 additions and 8972 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -3,6 +3,8 @@ target/
|
|||
.direnv/
|
||||
result
|
||||
|
||||
# Large research data files (tracked in Git LFS or kept local-only)
|
||||
research/*.pdf
|
||||
research/*.ndjson
|
||||
# Internal docs (specs, research, business strategy)
|
||||
docs-internal/
|
||||
|
||||
# Large research data files
|
||||
research/
|
||||
|
|
|
|||
431
SPEC.md
431
SPEC.md
|
|
@ -1,431 +0,0 @@
|
|||
# idx-cli — System Design & Project Blueprint
|
||||
|
||||
> CLI tool for Indonesian stock market (IDX) analysis. Built for humans and AI agents.
|
||||
|
||||
## References
|
||||
|
||||
These CLIs informed the design patterns used in this spec:
|
||||
|
||||
- **[Google Workspace CLI (`gws`)](https://github.com/googleworkspace/cli)** — Dynamic command surface from API discovery, strict auth precedence (flag > env > config), encrypted credential store, MCP mode, schema introspection commands. Great model for agent discoverability.
|
||||
- **[Polymarket CLI](https://github.com/Polymarket/polymarket-cli)** — Clean domain-based command hierarchy (`markets`, `events`, `wallet`), `--output table|json` global flag, config file + env overrides + flags precedence, interactive shell mode. Direct template for our command tree and output modes.
|
||||
- **[Obsidian CLI](https://help.obsidian.md/cli)** — `group:subcommand` naming, multi-format output (`json|csv|tsv|md`), TUI/shell mode + one-shot mode, clear docs on execution context and caching behavior. Good reference for help ergonomics.
|
||||
|
||||
---
|
||||
|
||||
## Goals
|
||||
|
||||
1. **Fast, single-binary CLI** — Rust + clap, zero runtime deps
|
||||
2. **Human-first, agent-friendly** — readable tables by default, `--json` for machines
|
||||
3. **Self-documenting** — agents discover capabilities via `--help` alone
|
||||
4. **Composable** — pipe, script, batch — standard Unix CLI philosophy
|
||||
5. **Offline-safe** — graceful degradation, local caching, no crashes on network failure
|
||||
|
||||
---
|
||||
|
||||
## Data Sources
|
||||
|
||||
### Primary: Yahoo Finance (unofficial HTTP API)
|
||||
- Real-time quotes, fundamentals, historical OHLC
|
||||
- No API key required
|
||||
- Endpoint: `https://query1.finance.yahoo.com/v8/finance/chart/{SYMBOL}.JK`
|
||||
- Fundamentals: `https://query1.finance.yahoo.com/v10/finance/quoteSummary/{SYMBOL}.JK`
|
||||
- Rate limits: ~2000 req/hr (undocumented, we should respect ~1 req/s burst)
|
||||
|
||||
### Future (pluggable):
|
||||
- IDX official API (if/when available)
|
||||
- Alpha Vantage, Twelve Data, etc. via `idx config set provider ...`
|
||||
|
||||
---
|
||||
|
||||
## Command Tree
|
||||
|
||||
```
|
||||
idx
|
||||
├── stocks
|
||||
│ ├── quote <SYMBOL...> # Price, change, volume, 52w range
|
||||
│ ├── technical <SYMBOL> # RSI, MACD, signals
|
||||
│ ├── fundamental <SYMBOL> # Composite: growth + valuation + risk
|
||||
│ ├── growth <SYMBOL> # Revenue/earnings growth
|
||||
│ ├── valuation <SYMBOL> # PE, PB, ROE, margins, EV/EBITDA
|
||||
│ ├── risk <SYMBOL> # D/E, current ratio, ROA
|
||||
│ ├── compare <SYM1,SYM2,...> # Side-by-side multi-symbol comparison
|
||||
│ │ [--metrics price,valuation,technical,growth,risk]
|
||||
│ └── history <SYMBOL> # Historical OHLC data
|
||||
│ [--period 1d|5d|1mo|3mo|6mo|1y|2y|5y]
|
||||
│ [--interval 1d|1wk|1mo]
|
||||
│
|
||||
├── market
|
||||
│ ├── summary # IHSG index, market breadth
|
||||
│ ├── movers # Top gainers/losers/volume
|
||||
│ │ [--by gainers|losers|volume] [--top 10]
|
||||
│ └── sectors # Sector performance overview
|
||||
│
|
||||
├── screen
|
||||
│ ├── query "<EXPR>" # Filter stocks by expression
|
||||
│ │ e.g. "pe < 15 and roe > 20 and market_cap > 1T"
|
||||
│ ├── presets # List built-in screen presets
|
||||
│ └── run <PRESET> # Run a named preset
|
||||
│
|
||||
├── watchlist
|
||||
│ ├── list # Show all watchlists
|
||||
│ ├── create <NAME> # Create new watchlist
|
||||
│ ├── delete <NAME> # Delete watchlist
|
||||
│ ├── add <NAME> <SYMBOL...> # Add symbols
|
||||
│ ├── remove <NAME> <SYMBOL...> # Remove symbols
|
||||
│ ├── show <NAME> # Show watchlist with live quotes
|
||||
│ └── watch <NAME> # Live terminal refresh
|
||||
│ [--interval 30s]
|
||||
│
|
||||
├── alerts # (v0.2+)
|
||||
│ ├── list
|
||||
│ ├── add --symbol <SYM> --when "<EXPR>"
|
||||
│ ├── remove <ID>
|
||||
│ └── daemon # Background alert checker
|
||||
│
|
||||
├── cache
|
||||
│ ├── info # Cache stats
|
||||
│ └── clear # Purge cache
|
||||
│
|
||||
├── config
|
||||
│ ├── init # Create default config
|
||||
│ ├── get <KEY>
|
||||
│ ├── set <KEY> <VALUE>
|
||||
│ └── path # Print config file path
|
||||
│
|
||||
├── completions <SHELL> # Generate shell completions
|
||||
│ [bash|zsh|fish|powershell]
|
||||
│
|
||||
└── version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Symbol Resolution
|
||||
|
||||
- Input: `BBCA` → resolved to `BBCA.JK` (IDX suffix)
|
||||
- Input: `BBCA.JK` → used as-is
|
||||
- Default exchange suffix configurable: `idx config set exchange JK`
|
||||
- Multiple symbols: comma-separated `BBCA,BBRI,BMRI` or space-separated where noted
|
||||
|
||||
---
|
||||
|
||||
## Output Strategy
|
||||
|
||||
### Global flags
|
||||
```
|
||||
-o, --output <FORMAT> Output format [default: table]
|
||||
[table, json, csv, tsv]
|
||||
--no-color Disable colored output
|
||||
-q, --quiet Suppress non-essential output
|
||||
-v, --verbose Increase verbosity
|
||||
```
|
||||
|
||||
### Table mode (default, for humans)
|
||||
```
|
||||
$ idx stocks quote BBCA
|
||||
SYMBOL PRICE CHG CHG% VOLUME MKT CAP 52W RANGE SIGNAL
|
||||
BBCA.JK 9,875 +117 +1.20% 12.3M 1,215.2T ████████░░ upper
|
||||
```
|
||||
|
||||
### JSON mode (for agents/scripts)
|
||||
```json
|
||||
$ idx -o json stocks quote BBCA
|
||||
{
|
||||
"symbol": "BBCA.JK",
|
||||
"price": 9875,
|
||||
"change": 117,
|
||||
"change_pct": 1.20,
|
||||
"volume": 12300000,
|
||||
"market_cap": 1215200000000000,
|
||||
"week52_high": 10250,
|
||||
"week52_low": 7800,
|
||||
"week52_position": 0.732,
|
||||
"range_signal": "upper"
|
||||
}
|
||||
```
|
||||
|
||||
### CSV/TSV mode (for batch/spreadsheet)
|
||||
```
|
||||
$ idx -o csv stocks quote BBCA,BBRI
|
||||
symbol,price,change,change_pct,volume,market_cap
|
||||
BBCA.JK,9875,117,1.20,12300000,1215200000000000
|
||||
BBRI.JK,4560,45,1.00,25600000,567800000000000
|
||||
```
|
||||
|
||||
### Error handling
|
||||
- Exit code 0 on success, non-zero on failure
|
||||
- Table mode: human error on stderr
|
||||
- JSON mode: `{"error": true, "code": "SYMBOL_NOT_FOUND", "message": "..."}`
|
||||
|
||||
---
|
||||
|
||||
## Technical Analysis Implementation
|
||||
|
||||
### Indicators (v0.1)
|
||||
- **RSI(14)** — Relative Strength Index, 14-period
|
||||
- **MACD(12,26,9)** — Moving Average Convergence Divergence
|
||||
- **SMA(20,50,200)** — Simple Moving Averages
|
||||
- **Volume analysis** — vs 20-day average
|
||||
|
||||
### Signal interpretation
|
||||
Each indicator produces a signal: `bullish | bearish | neutral`
|
||||
|
||||
Overall technical signal derived from weighted consensus:
|
||||
- RSI: overbought (>70) / oversold (<30) / neutral
|
||||
- MACD: histogram direction + signal line cross
|
||||
- Price vs SMA: above/below 50/200 day
|
||||
|
||||
### Fundamental metrics
|
||||
- **Growth**: revenue growth, earnings growth YoY
|
||||
- **Valuation**: trailing PE, forward PE, PB, EV/EBITDA, ROE, profit margin
|
||||
- **Risk**: D/E ratio, current ratio, ROA
|
||||
|
||||
Each category produces an interpreted signal with the raw numbers.
|
||||
|
||||
---
|
||||
|
||||
## Screening Engine (v0.1)
|
||||
|
||||
Simple expression parser for filtering stocks:
|
||||
|
||||
```
|
||||
idx screen query "pe < 15 and roe > 20"
|
||||
idx screen query "market_cap > 100T and dividend_yield > 3"
|
||||
idx screen query "rsi < 30" # oversold screen
|
||||
```
|
||||
|
||||
### Available fields
|
||||
`price`, `change_pct`, `volume`, `market_cap`, `pe`, `pb`, `roe`, `roa`,
|
||||
`de_ratio`, `current_ratio`, `profit_margin`, `revenue_growth`,
|
||||
`earnings_growth`, `dividend_yield`, `rsi`, `week52_position`
|
||||
|
||||
### Operators
|
||||
`>`, `<`, `>=`, `<=`, `==`, `!=`, `and`, `or`
|
||||
|
||||
### Built-in presets
|
||||
- `value` — PE < 15, PB < 1.5, ROE > 15
|
||||
- `growth` — revenue growth > 20%, earnings growth > 20%
|
||||
- `oversold` — RSI < 30, week52_position < 0.3
|
||||
- `dividend` — dividend yield > 4%, payout sustainable
|
||||
- `blue-chip` — market cap > 100T, ROE > 15
|
||||
|
||||
---
|
||||
|
||||
## Caching
|
||||
|
||||
- **Location**: `~/.cache/idx/`
|
||||
- **Strategy**: file-based, keyed by (symbol, data_type, params)
|
||||
- **Default TTL**: 5 minutes for quotes, 1 hour for fundamentals
|
||||
- **Format**: binary (bincode/msgpack) for speed
|
||||
- Configurable: `idx config set cache.quote_ttl 300`
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### File: `~/.config/idx/config.toml`
|
||||
```toml
|
||||
[general]
|
||||
exchange = "JK"
|
||||
output = "table"
|
||||
color = true
|
||||
|
||||
[cache]
|
||||
quote_ttl = 300 # seconds
|
||||
fundamental_ttl = 3600
|
||||
|
||||
[provider]
|
||||
default = "yahoo"
|
||||
# alpha_vantage_key = "..." # future
|
||||
```
|
||||
|
||||
### Precedence
|
||||
`flags > env vars > config file > defaults`
|
||||
|
||||
### Environment variables
|
||||
```
|
||||
IDX_OUTPUT=json
|
||||
IDX_EXCHANGE=JK
|
||||
IDX_CACHE_QUOTE_TTL=300
|
||||
IDX_NO_COLOR=1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
idx-cli/
|
||||
├── Cargo.toml
|
||||
├── SPEC.md # This file
|
||||
├── README.md
|
||||
├── LICENSE # MIT
|
||||
├── src/
|
||||
│ ├── main.rs # Entry point, clap app setup
|
||||
│ ├── cli/
|
||||
│ │ ├── mod.rs
|
||||
│ │ ├── stocks.rs # stocks subcommands
|
||||
│ │ ├── market.rs # market subcommands
|
||||
│ │ ├── screen.rs # screen subcommands
|
||||
│ │ ├── watchlist.rs # watchlist subcommands
|
||||
│ │ ├── alerts.rs # alerts subcommands (v0.2)
|
||||
│ │ ├── cache.rs # cache subcommands
|
||||
│ │ └── config.rs # config subcommands
|
||||
│ ├── api/
|
||||
│ │ ├── mod.rs
|
||||
│ │ ├── yahoo.rs # Yahoo Finance HTTP client
|
||||
│ │ └── types.rs # API response types
|
||||
│ ├── analysis/
|
||||
│ │ ├── mod.rs
|
||||
│ │ ├── technical.rs # RSI, MACD, SMA
|
||||
│ │ ├── fundamental.rs # Growth, valuation, risk
|
||||
│ │ └── signals.rs # Signal interpretation
|
||||
│ ├── screen/
|
||||
│ │ ├── mod.rs
|
||||
│ │ ├── parser.rs # Expression parser
|
||||
│ │ └── presets.rs # Built-in presets
|
||||
│ ├── output/
|
||||
│ │ ├── mod.rs
|
||||
│ │ ├── table.rs # Rich table formatting
|
||||
│ │ ├── json.rs # JSON output
|
||||
│ │ └── csv.rs # CSV/TSV output
|
||||
│ ├── cache.rs # File-based caching
|
||||
│ ├── config.rs # Config loading/merging
|
||||
│ └── error.rs # Error types
|
||||
└── tests/
|
||||
├── integration/
|
||||
└── fixtures/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Crate Dependencies (expected)
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
comfy-table = "7" # table rendering
|
||||
colored = "2" # terminal colors
|
||||
toml = "0.8" # config parsing
|
||||
directories = "5" # XDG paths
|
||||
chrono = "0.4"
|
||||
thiserror = "2"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Milestones
|
||||
|
||||
### v0.1 — Core (MVP)
|
||||
- [ ] Project scaffold + CI
|
||||
- [ ] Yahoo Finance API client (quotes + fundamentals + history)
|
||||
- [ ] `stocks quote`, `stocks technical`, `stocks fundamental`
|
||||
- [ ] `stocks growth`, `stocks valuation`, `stocks risk`
|
||||
- [ ] `stocks compare`, `stocks history`
|
||||
- [ ] Table + JSON output
|
||||
- [ ] Symbol resolution (auto `.JK`)
|
||||
- [ ] File-based caching
|
||||
- [ ] Config system
|
||||
- [ ] Shell completions
|
||||
- [ ] `--help` on every command with examples
|
||||
|
||||
### v0.2 — Market & Screening
|
||||
- [ ] `market summary`, `market movers`, `market sectors`
|
||||
- [ ] Screening engine (expression parser + presets)
|
||||
- [ ] CSV/TSV output
|
||||
- [ ] Watchlists (local file-based)
|
||||
|
||||
### v0.3 — Live & Alerts
|
||||
- [ ] `watchlist watch` (live terminal refresh)
|
||||
- [ ] Alert engine + daemon mode
|
||||
- [ ] Notification hooks (stdout, webhook, etc.)
|
||||
|
||||
### v0.4 — Distribution
|
||||
- [ ] Nix package
|
||||
- [ ] Homebrew formula
|
||||
- [ ] GitHub releases (cross-compiled binaries)
|
||||
- [ ] `cargo install idx-cli`
|
||||
|
||||
---
|
||||
|
||||
## Agent Skills
|
||||
|
||||
Inspired by [Google Workspace CLI's skills system](https://github.com/googleworkspace/cli/tree/main/skills), `idx-cli` ships a `skills/` directory with SKILL.md files that teach AI agents how to use the CLI effectively. No MCP, no JSON schema bloat — just markdown instructions that any agent framework can pick up.
|
||||
|
||||
### Structure
|
||||
|
||||
```
|
||||
skills/
|
||||
├── idx-shared/SKILL.md # Install block, common patterns, output modes
|
||||
├── idx-quote/SKILL.md # Price lookup, multi-symbol quotes
|
||||
├── idx-technical/SKILL.md # Technical analysis workflow
|
||||
├── idx-fundamental/SKILL.md # Fundamental analysis (growth, valuation, risk)
|
||||
├── idx-compare/SKILL.md # Multi-stock comparison
|
||||
├── idx-screen/SKILL.md # Stock screening with expressions & presets
|
||||
├── idx-ownership/SKILL.md # Ownership intelligence queries
|
||||
├── idx-watchlist/SKILL.md # Watchlist management
|
||||
├── idx-workflow-dd/SKILL.md # Due diligence workflow (chains multiple commands)
|
||||
└── idx-workflow-sector/SKILL.md # Sector analysis workflow
|
||||
```
|
||||
|
||||
### Skill anatomy
|
||||
|
||||
Each SKILL.md follows a consistent format:
|
||||
|
||||
```markdown
|
||||
# idx-quote — Stock Price Lookup
|
||||
|
||||
## Install
|
||||
<!-- Auto-install block for agent frameworks -->
|
||||
```bash
|
||||
cargo install idx-cli # or: nix run github:0xrsydn/idx-cli
|
||||
```
|
||||
|
||||
## Commands
|
||||
<!-- Exact commands with examples -->
|
||||
idx stocks quote BBCA
|
||||
idx stocks quote BBCA,BBRI,BMRI -o json
|
||||
|
||||
## Output format
|
||||
<!-- What the agent should expect back -->
|
||||
|
||||
## Patterns
|
||||
<!-- Common usage patterns, gotchas, tips -->
|
||||
|
||||
## See also
|
||||
<!-- Related skills -->
|
||||
```
|
||||
|
||||
### Integration with agent frameworks
|
||||
|
||||
```bash
|
||||
# OpenClaw — symlink all skills
|
||||
ln -s /path/to/idx-cli/skills/idx-* ~/.openclaw/skills/
|
||||
|
||||
# Or install specific skills
|
||||
cp -r skills/idx-quote skills/idx-ownership ~/.openclaw/skills/
|
||||
|
||||
# Claude Code — skills are auto-discovered from repo
|
||||
# Gemini CLI — same pattern as gws
|
||||
```
|
||||
|
||||
### Design principles
|
||||
|
||||
1. **Self-contained** — each skill has everything an agent needs, no cross-references required
|
||||
2. **Example-driven** — real commands with real output, not abstract descriptions
|
||||
3. **Composable** — workflow skills reference atomic skills, agents can chain them
|
||||
4. **Framework-agnostic** — plain markdown works with OpenClaw, Claude, Gemini, Cursor, etc.
|
||||
|
||||
---
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Stock universe for screening** — Yahoo doesn't have a "list all IDX stocks" endpoint. We need a static list of IDX symbols (~800) bundled or fetched from IDX website. How to maintain?
|
||||
2. **Rate limiting strategy** — batch requests vs sequential with delay? Should we parallelize multi-symbol queries?
|
||||
3. **Offline mode** — serve from cache when network unavailable, or fail explicitly?
|
||||
4. **Interactive shell** — worth building `idx shell` REPL in v0.1, or defer?
|
||||
5. **Plugin system** — allow custom analyzers/data sources via dynamic loading, or keep it simple?
|
||||
|
|
@ -1,387 +0,0 @@
|
|||
# IDX Ownership Intelligence Feature Design (KSEI >1% Dataset)
|
||||
|
||||
## 1) What I analyzed
|
||||
|
||||
### Source file
|
||||
- URL: `https://www.idx.co.id/StaticData/NewsAndAnnouncement/ANNOUNCEMENTSTOCK/From_EREP/202603/95f8c4c8bc_848269e900.pdf`
|
||||
- Saved to: `/var/lib/openclaw/projects/idx-cli/research/ownership_202603.pdf`
|
||||
- Download note: direct `curl` got Cloudflare block HTML; download succeeded using browser-like headers via Python `urllib`.
|
||||
|
||||
### Parsing approach
|
||||
- `pdftotext` not available in runtime.
|
||||
- Used Node parser stack:
|
||||
- `pdf-parse` for full-text sanity check
|
||||
- `pdf2json` for coordinate-based extraction (critical for column integrity)
|
||||
- Extracted row-level dataset to:
|
||||
- `/var/lib/openclaw/projects/idx-cli/research/ownership_202603_rows.ndjson`
|
||||
- `/var/lib/openclaw/projects/idx-cli/research/ownership_202603_analysis.json`
|
||||
|
||||
---
|
||||
|
||||
## 2) PDF structure analysis
|
||||
|
||||
### High-level structure
|
||||
- Total pages: **73**
|
||||
- First pages: cover letter/explanatory text from KSEI.
|
||||
- Tabular section (core data): repeated row records with these headers:
|
||||
|
||||
```text
|
||||
DATE
|
||||
SHARE_CODE
|
||||
ISSUER_NAME
|
||||
INVESTOR_NAME
|
||||
INVESTOR_TYPE
|
||||
LOCAL_FOREIGN
|
||||
NATIONALITY
|
||||
DOMICILE
|
||||
HOLDINGS_SCRIPLESS
|
||||
HOLDINGS_SCRIP
|
||||
TOTAL_HOLDING_SHARES
|
||||
PERCENTAGE
|
||||
```
|
||||
|
||||
### Observed dataset size (from parsed rows)
|
||||
- Total ownership rows: **7,257**
|
||||
- Unique tickers (`share_code`): **955**
|
||||
- Unique issuer names: **956** (1 extra due naming variant/noise)
|
||||
- Unique investor names (raw uppercased): **5,195**
|
||||
- As-of date: **27-Feb-2026** for all rows in this release
|
||||
|
||||
### Example extracted rows
|
||||
|
||||
```json
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AADI",
|
||||
"issuer_name": "ADARO ANDALAN INDONESIA Tbk",
|
||||
"investor_name": "ADARO STRATEGIC INVESTMENTS",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "3.200.142.830",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "3.200.142.830",
|
||||
"percentage": "41,10"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AALI",
|
||||
"issuer_name": "ASTRA AGRO LESTARI Tbk",
|
||||
"investor_name": "PT ASTRA INTERNATIONAL TBK",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "0",
|
||||
"holdings_scrip": "1.533.682.440",
|
||||
"total_holding_shares": "1.533.682.440",
|
||||
"percentage": "79,68"
|
||||
}
|
||||
```
|
||||
|
||||
### Data quality notes
|
||||
- Missingness:
|
||||
- `investor_type` missing: 244 rows
|
||||
- `local_foreign` missing: 244 rows
|
||||
- `nationality` missing: 4,240 rows
|
||||
- `domicile` missing: 1,053 rows
|
||||
- Investor types observed most: `CP`, `ID`, `IB`, `MF`, `SC`, `OT`, `IS`
|
||||
- Raw entity names have normalization issues (`PT`, punctuation, case, suffix variations).
|
||||
|
||||
---
|
||||
|
||||
## 3) Analytical potential from this release
|
||||
|
||||
### Cross-holder signal (same investor across many tickers)
|
||||
Top examples (raw name grouping):
|
||||
- UOB KAY HIAN PRIVATE LIMITED: **66** tickers
|
||||
- BANK OF SINGAPORE LIMITED: **38**
|
||||
- PT. ASABRI (Persero): **33**
|
||||
- DJS Ketenagakerjaan (JHT): **31**
|
||||
- UBS AG Singapore Branch: **27**
|
||||
|
||||
This already forms a strong bipartite graph: `entity -> owns -> ticker`.
|
||||
|
||||
### Concentration metrics per ticker
|
||||
Examples from parsed results:
|
||||
- Very concentrated:
|
||||
- `IBST`: 1 holder >1%, total captured 99.95%
|
||||
- `SUPR`: largest holder 97.33%
|
||||
- More dispersed among >1% holders:
|
||||
- `BBRI`: total >1% captured 5.86%
|
||||
- `ADHI`: 7.37%
|
||||
- `BBNI`: 7.95%
|
||||
|
||||
### Breadth metric
|
||||
- Tickers with most >1% holders in this snapshot:
|
||||
- `CARS` (28), `INPC` (28), `BOGA` (27), etc.
|
||||
|
||||
---
|
||||
|
||||
## 4) Proposed data model (SQLite-first)
|
||||
|
||||
Use SQLite for local analytics in `idx-cli` (fast, portable, no server dependency).
|
||||
|
||||
### Core tables
|
||||
|
||||
```sql
|
||||
-- One PDF release/event
|
||||
CREATE TABLE ownership_release (
|
||||
id INTEGER PRIMARY KEY,
|
||||
source_url TEXT NOT NULL,
|
||||
source_file_sha256 TEXT NOT NULL UNIQUE,
|
||||
as_of_date TEXT NOT NULL, -- YYYY-MM-DD
|
||||
published_at TEXT,
|
||||
fetched_at TEXT NOT NULL,
|
||||
parser_version TEXT NOT NULL,
|
||||
row_count INTEGER NOT NULL,
|
||||
metadata_json TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE issuer (
|
||||
id INTEGER PRIMARY KEY,
|
||||
ticker TEXT NOT NULL UNIQUE,
|
||||
issuer_name_raw TEXT NOT NULL,
|
||||
issuer_name_norm TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE entity (
|
||||
id INTEGER PRIMARY KEY,
|
||||
canonical_name TEXT NOT NULL,
|
||||
canonical_name_norm TEXT NOT NULL UNIQUE,
|
||||
entity_kind TEXT, -- company/person/fund/gov/unknown
|
||||
country_hint TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Raw name variants resolved to entity
|
||||
CREATE TABLE entity_alias (
|
||||
id INTEGER PRIMARY KEY,
|
||||
entity_id INTEGER NOT NULL REFERENCES entity(id),
|
||||
alias_raw TEXT NOT NULL,
|
||||
alias_norm TEXT NOT NULL,
|
||||
confidence REAL NOT NULL, -- 0..1
|
||||
method TEXT NOT NULL, -- exact/manual/fuzzy/rule
|
||||
UNIQUE(entity_id, alias_norm)
|
||||
);
|
||||
|
||||
CREATE TABLE ownership_fact (
|
||||
id INTEGER PRIMARY KEY,
|
||||
release_id INTEGER NOT NULL REFERENCES ownership_release(id),
|
||||
issuer_id INTEGER NOT NULL REFERENCES issuer(id),
|
||||
entity_id INTEGER NOT NULL REFERENCES entity(id),
|
||||
|
||||
investor_name_raw TEXT NOT NULL,
|
||||
investor_type TEXT,
|
||||
local_foreign TEXT,
|
||||
nationality TEXT,
|
||||
domicile TEXT,
|
||||
|
||||
holdings_scripless INTEGER NOT NULL,
|
||||
holdings_scrip INTEGER NOT NULL,
|
||||
total_holding_shares INTEGER NOT NULL,
|
||||
percentage_bps INTEGER NOT NULL, -- e.g. 41.10% => 4110
|
||||
|
||||
-- one row per entity/ticker/release/rawname (can enforce stronger uniqueness later)
|
||||
UNIQUE(release_id, issuer_id, investor_name_raw)
|
||||
);
|
||||
```
|
||||
|
||||
### Useful indexes
|
||||
|
||||
```sql
|
||||
CREATE INDEX idx_fact_release_issuer ON ownership_fact(release_id, issuer_id);
|
||||
CREATE INDEX idx_fact_release_entity ON ownership_fact(release_id, entity_id);
|
||||
CREATE INDEX idx_fact_pct ON ownership_fact(release_id, percentage_bps DESC);
|
||||
CREATE INDEX idx_alias_norm ON entity_alias(alias_norm);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5) End-to-end pipeline design (PDF → queryable intelligence)
|
||||
|
||||
1. **Fetch**
|
||||
- Download announcement PDF using robust HTTP headers.
|
||||
- Store raw file in data dir + SHA256.
|
||||
|
||||
2. **Parse (bronze)**
|
||||
- Coordinate extraction from PDF (x/y text cells).
|
||||
- Emit raw row JSON with strict schema + parser warnings.
|
||||
|
||||
3. **Normalize (silver)**
|
||||
- Parse numerics:
|
||||
- `1.533.682.440` → integer shares
|
||||
- `79,68` → 7968 bps
|
||||
- Standardize date: `27-Feb-2026` → `2026-02-27`
|
||||
- Normalize text fields (trim, whitespace, uppercase key columns).
|
||||
|
||||
4. **Resolve entities (gold)**
|
||||
- Deterministic normalization rules (`PT.`, commas, suffixes, punctuation).
|
||||
- Alias mapping table + manual overrides.
|
||||
- Fuzzy match only with high threshold + review queue.
|
||||
|
||||
5. **Load SQLite**
|
||||
- UPSERT `issuer`, `entity`, `entity_alias`, `ownership_fact`.
|
||||
- Keep release snapshots immutable for time-series diffs.
|
||||
|
||||
6. **Derive marts/materialized views**
|
||||
- `v_ticker_concentration` (HHI, top1, top3, sum>1)
|
||||
- `v_entity_cross_holdings` (#tickers, total bps)
|
||||
- `v_pair_coownership` (entity pairs co-appearing across tickers)
|
||||
|
||||
---
|
||||
|
||||
## 6) Entity graph design
|
||||
|
||||
### Graph model
|
||||
- **Node types**:
|
||||
- `Entity` (investor)
|
||||
- `Ticker` (issuer)
|
||||
- **Edge**: `OWNS` with attributes
|
||||
- `release_id`, `percentage_bps`, `shares_total`, `investor_type`, `local_foreign`
|
||||
|
||||
### Derived graph analytics
|
||||
1. **Cross-holders**: entities with high ticker degree.
|
||||
2. **Co-ownership network**:
|
||||
- Build `Entity --co_owns--> Entity` weighted by number of shared tickers and summed min(%).
|
||||
3. **Cluster detection**:
|
||||
- Louvain / connected components on co-ownership graph.
|
||||
4. **Concentration**:
|
||||
- per ticker `top1`, `top3`, `sum_pct_gt1`, `HHI`.
|
||||
5. **Temporal graph** (when monthly releases accumulate):
|
||||
- edge delta (`+/- bps`), entry/exit events, emerging cluster shifts.
|
||||
|
||||
---
|
||||
|
||||
## 7) CLI command proposals
|
||||
|
||||
Integrate as a new top-level group in `SPEC.md` style:
|
||||
|
||||
```text
|
||||
idx ownership
|
||||
├── ticker <SYMBOL> # holders >1% for ticker
|
||||
├── entity <NAME_OR_ID> # what this entity owns
|
||||
├── cross-holders # entities with widest cross-ownership
|
||||
│ [--top 20] [--min-tickers 5]
|
||||
├── concentration # ranking by concentration metrics
|
||||
│ [--by top1|top3|sum|hhi] [--top 20] [--least]
|
||||
├── clusters # co-ownership clusters
|
||||
│ [--min-shared 2]
|
||||
├── changes # compare two releases
|
||||
│ --from <YYYY-MM-DD> --to <YYYY-MM-DD>
|
||||
├── releases # available snapshots
|
||||
├── import # parse & load latest PDF(s)
|
||||
│ [--url <PDF_URL>] [--file <PATH>] [--as-of <DATE>] [--force]
|
||||
└── resolve # alias/entity management
|
||||
├── list-unresolved
|
||||
├── map <ALIAS> <ENTITY>
|
||||
└── merge <ENTITY_A> <ENTITY_B>
|
||||
```
|
||||
|
||||
### Example UX
|
||||
|
||||
```bash
|
||||
$ idx ownership ticker BBCA
|
||||
AS OF: 2026-02-27 | TICKER: BBCA
|
||||
RANK INVESTOR TYPE L/F SHARES %
|
||||
1 PT ... CP L 12,345,678,900 54.32
|
||||
2 ...
|
||||
```
|
||||
|
||||
```bash
|
||||
$ idx -o json ownership entity "UOB KAY HIAN PRIVATE LIMITED"
|
||||
{
|
||||
"entity": "UOB KAY HIAN PRIVATE LIMITED",
|
||||
"as_of": "2026-02-27",
|
||||
"ticker_count": 66,
|
||||
"holdings": [ ... ]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8) Architecture recommendations
|
||||
|
||||
### Local-first (recommended MVP)
|
||||
- DB path: `~/.local/share/idx/ownership.db` (or XDG equivalent)
|
||||
- Raw files cache: `~/.cache/idx/ownership/raw/`
|
||||
- Parsed snapshots: `~/.cache/idx/ownership/parsed/`
|
||||
|
||||
Pros: offline-capable, instant query, aligns with existing CLI/caching philosophy in `SPEC.md`.
|
||||
|
||||
### Update model
|
||||
- `idx ownership import` checks known URL(s) or accepts explicit URL/file.
|
||||
- De-duplicate by SHA256 + as_of_date.
|
||||
- Keep all snapshots to unlock `changes` and trend analytics.
|
||||
|
||||
### Optional future API mode
|
||||
- If multi-user/team usage needed, same schema can back a lightweight API service.
|
||||
- Keep CLI query layer repository-backed so data source can be local SQLite or remote API.
|
||||
|
||||
---
|
||||
|
||||
## 9) Entity resolution challenges (critical)
|
||||
|
||||
1. **Name variants**: `PT X`, `PT. X`, `X PT`, punctuation/case.
|
||||
2. **Corporate suffix permutations**: `TBK`, `Tbk`, `(PERSERO)`, etc.
|
||||
3. **Custodian omnibus names** may mask underlying beneficial owners.
|
||||
4. **Person name ambiguity** (same personal names).
|
||||
5. **Cross-language spelling** and abbreviations.
|
||||
6. **Corporate group mapping** (subsidiary vs parent): separate from exact legal entity identity.
|
||||
|
||||
### Practical strategy
|
||||
- Phase 1: conservative exact+rule normalization (high precision).
|
||||
- Phase 2: human-reviewed alias map.
|
||||
- Phase 3: optional fuzzy suggestions with confidence score, never auto-merge below threshold.
|
||||
|
||||
---
|
||||
|
||||
## 10) Integration with current `idx-cli` SPEC
|
||||
|
||||
Current `SPEC.md` is quote/fundamental/technical-centric. Ownership feature fits as a differentiated analytics vertical:
|
||||
|
||||
- Add new top-level command group: `ownership`
|
||||
- Reuse global output modes: `table|json|csv|tsv`
|
||||
- Reuse config precedence (flags > env > config)
|
||||
- Extend config:
|
||||
|
||||
```toml
|
||||
[ownership]
|
||||
db_path = "~/.local/share/idx/ownership.db"
|
||||
raw_cache_dir = "~/.cache/idx/ownership/raw"
|
||||
parsed_cache_dir = "~/.cache/idx/ownership/parsed"
|
||||
entity_resolution_mode = "conservative"
|
||||
auto_import = false
|
||||
```
|
||||
|
||||
- Add milestone slice (proposed):
|
||||
- **v0.2.5**: `ownership import`, `ownership ticker`, `ownership entity`
|
||||
- **v0.3**: concentration/cross-holder rankings, releases/changes
|
||||
- **v0.4+**: clustering/graph exports and manual resolution workflow
|
||||
|
||||
---
|
||||
|
||||
## 11) Open questions before implementation
|
||||
|
||||
1. Official stable source URL pattern for future monthly releases?
|
||||
2. Will data always be PDF only, or also XLS/CSV endpoint?
|
||||
3. Canonical meaning of investor type codes (`CP`, `ID`, `IB`, etc.) — need official codebook.
|
||||
4. Should ADR/dual-listing/suspended symbols be filtered in CLI output?
|
||||
5. Entity resolution governance: where to store curated alias mappings in-repo vs user-local?
|
||||
|
||||
---
|
||||
|
||||
## 12) Key files generated in this research
|
||||
|
||||
- `/var/lib/openclaw/projects/idx-cli/research/ownership_202603.pdf`
|
||||
- `/var/lib/openclaw/projects/idx-cli/research/ownership_202603_extracted.txt`
|
||||
- `/var/lib/openclaw/projects/idx-cli/research/ownership_202603_rows.ndjson`
|
||||
- `/var/lib/openclaw/projects/idx-cli/research/ownership_202603_analysis.json`
|
||||
- `/var/lib/openclaw/projects/idx-cli/research/OWNERSHIP_FEATURE_DESIGN.md`
|
||||
|
||||
These provide a concrete parsed sample and can be used directly to bootstrap implementation + tests.
|
||||
|
|
@ -1,609 +0,0 @@
|
|||
{
|
||||
"page_count": 73,
|
||||
"row_count": 7257,
|
||||
"unique_tickers": 955,
|
||||
"unique_issuers": 956,
|
||||
"unique_investors": 5195,
|
||||
"columns": [
|
||||
"date",
|
||||
"share_code",
|
||||
"issuer_name",
|
||||
"investor_name",
|
||||
"investor_type",
|
||||
"local_foreign",
|
||||
"nationality",
|
||||
"domicile",
|
||||
"holdings_scripless",
|
||||
"holdings_scrip",
|
||||
"total_holding_shares",
|
||||
"percentage"
|
||||
],
|
||||
"sample_rows": [
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AADI",
|
||||
"issuer_name": "ADARO ANDALAN INDONESIA Tbk",
|
||||
"investor_name": "ADARO STRATEGIC INVESTMENTS",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "3.200.142.830",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "3.200.142.830",
|
||||
"percentage": "41,10"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AADI",
|
||||
"issuer_name": "ADARO ANDALAN INDONESIA Tbk",
|
||||
"investor_name": "ALAMTRI RESOURCES INDONESIA TBK PT",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "1.197.023.942",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "1.197.023.942",
|
||||
"percentage": "15,37"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AADI",
|
||||
"issuer_name": "ADARO ANDALAN INDONESIA Tbk",
|
||||
"investor_name": "GARIBALDI THOHIR",
|
||||
"investor_type": "ID",
|
||||
"local_foreign": "L",
|
||||
"nationality": "INDONESIAN",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "454.011.607",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "454.011.607",
|
||||
"percentage": "5,83"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AADI",
|
||||
"issuer_name": "ADARO ANDALAN INDONESIA Tbk",
|
||||
"investor_name": "SARATOGA INVESTAMA SEDAYA TBK PT",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "340.897.429",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "340.897.429",
|
||||
"percentage": "4,38"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AADI",
|
||||
"issuer_name": "ADARO ANDALAN INDONESIA Tbk",
|
||||
"investor_name": "EDWIN SOERYADJAYA",
|
||||
"investor_type": "ID",
|
||||
"local_foreign": "L",
|
||||
"nationality": "INDONESIAN",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "273.955.636",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "273.955.636",
|
||||
"percentage": "3,52"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AADI",
|
||||
"issuer_name": "ADARO ANDALAN INDONESIA Tbk",
|
||||
"investor_name": "IR. T. PERMADI RACHMAT",
|
||||
"investor_type": "ID",
|
||||
"local_foreign": "L",
|
||||
"nationality": "INDONESIAN",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "254.992.918",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "254.992.918",
|
||||
"percentage": "3,27"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AADI",
|
||||
"issuer_name": "ADARO ANDALAN INDONESIA Tbk",
|
||||
"investor_name": "SANDIAGA SALAHUDDIN UNO",
|
||||
"investor_type": "ID",
|
||||
"local_foreign": "L",
|
||||
"nationality": "INDONESIAN",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "159.027.175",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "159.027.175",
|
||||
"percentage": "2,04"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AADI",
|
||||
"issuer_name": "ADARO ANDALAN INDONESIA Tbk",
|
||||
"investor_name": "PERSADA CAPITAL INVESTAMA",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "119.887.170",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "119.887.170",
|
||||
"percentage": "1,54"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AADI",
|
||||
"issuer_name": "ADARO ANDALAN INDONESIA Tbk",
|
||||
"investor_name": "FTAG INVESTMENT BANK LTD",
|
||||
"investor_type": "IB",
|
||||
"local_foreign": "A",
|
||||
"nationality": "",
|
||||
"domicile": "MALAYSIA",
|
||||
"holdings_scripless": "100.722.000",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "100.722.000",
|
||||
"percentage": "1,29"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AADI",
|
||||
"issuer_name": "ADARO ANDALAN INDONESIA Tbk",
|
||||
"investor_name": "PT TRINUGRAHA THOHIR",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "89.926.520",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "89.926.520",
|
||||
"percentage": "1,15"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AALI",
|
||||
"issuer_name": "ASTRA AGRO LESTARI Tbk",
|
||||
"investor_name": "PT ASTRA INTERNATIONAL TBK",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "0",
|
||||
"holdings_scrip": "1.533.682.440",
|
||||
"total_holding_shares": "1.533.682.440",
|
||||
"percentage": "79,68"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "AALI",
|
||||
"issuer_name": "ASTRA AGRO LESTARI Tbk",
|
||||
"investor_name": "DJS KETENAGAKERJAAN PROGRAM JAMINAN HARI TUA",
|
||||
"investor_type": "IS",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "41.979.300",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "41.979.300",
|
||||
"percentage": "2,18"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "ABBA",
|
||||
"issuer_name": "MAHAKA MEDIA Tbk",
|
||||
"investor_name": "PT. Beyond Media",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "1.592.831.618",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "1.592.831.618",
|
||||
"percentage": "40,47"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "ABBA",
|
||||
"issuer_name": "MAHAKA MEDIA Tbk",
|
||||
"investor_name": "SOLIC KREASI BARU PT",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "542.042.122",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "542.042.122",
|
||||
"percentage": "13,77"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "ABBA",
|
||||
"issuer_name": "MAHAKA MEDIA Tbk",
|
||||
"investor_name": "MEDIAHUIS IRELAND LIMITED",
|
||||
"investor_type": "",
|
||||
"local_foreign": "",
|
||||
"nationality": "",
|
||||
"domicile": "",
|
||||
"holdings_scripless": "0",
|
||||
"holdings_scrip": "282.886.300",
|
||||
"total_holding_shares": "282.886.300",
|
||||
"percentage": "7,19"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "ABBA",
|
||||
"issuer_name": "MAHAKA MEDIA Tbk",
|
||||
"investor_name": "DRS. WINARTO",
|
||||
"investor_type": "ID",
|
||||
"local_foreign": "L",
|
||||
"nationality": "INDONESIAN",
|
||||
"domicile": "",
|
||||
"holdings_scripless": "178.745.400",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "178.745.400",
|
||||
"percentage": "4,54"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "ABBA",
|
||||
"issuer_name": "MAHAKA MEDIA Tbk",
|
||||
"investor_name": "YAYASAN ABDI BANGSA",
|
||||
"investor_type": "",
|
||||
"local_foreign": "",
|
||||
"nationality": "",
|
||||
"domicile": "",
|
||||
"holdings_scripless": "0",
|
||||
"holdings_scrip": "111.372.886",
|
||||
"total_holding_shares": "111.372.886",
|
||||
"percentage": "2,83"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "ABBA",
|
||||
"issuer_name": "MAHAKA MEDIA Tbk",
|
||||
"investor_name": "YAYASAN BINA SEJAHTERA WARGA BULOG",
|
||||
"investor_type": "",
|
||||
"local_foreign": "",
|
||||
"nationality": "",
|
||||
"domicile": "",
|
||||
"holdings_scripless": "0",
|
||||
"holdings_scrip": "52.975.286",
|
||||
"total_holding_shares": "52.975.286",
|
||||
"percentage": "1,35"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "ABBA",
|
||||
"issuer_name": "MAHAKA MEDIA Tbk",
|
||||
"investor_name": "KAIROS EKSPRES INTERNASIONAL PT",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "52.362.500",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "52.362.500",
|
||||
"percentage": "1,33"
|
||||
},
|
||||
{
|
||||
"date": "27-Feb-2026",
|
||||
"share_code": "ABBA",
|
||||
"issuer_name": "MAHAKA MEDIA Tbk",
|
||||
"investor_name": "PT.Grid One Media",
|
||||
"investor_type": "CP",
|
||||
"local_foreign": "L",
|
||||
"nationality": "",
|
||||
"domicile": "INDONESIA",
|
||||
"holdings_scripless": "43.791.628",
|
||||
"holdings_scrip": "0",
|
||||
"total_holding_shares": "43.791.628",
|
||||
"percentage": "1,11"
|
||||
}
|
||||
],
|
||||
"top_cross_holders": [
|
||||
{
|
||||
"investor_name": "UOB KAY HIAN PRIVATE LIMITED",
|
||||
"ticker_count": 66,
|
||||
"row_count": 66,
|
||||
"sum_percentage": 369.59
|
||||
},
|
||||
{
|
||||
"investor_name": "BANK OF SINGAPORE LIMITED",
|
||||
"ticker_count": 38,
|
||||
"row_count": 38,
|
||||
"sum_percentage": 142.42
|
||||
},
|
||||
{
|
||||
"investor_name": "PERUSAHAAN PERSEROAN (PERSERO) PT. ASABRI",
|
||||
"ticker_count": 33,
|
||||
"row_count": 33,
|
||||
"sum_percentage": 224.19
|
||||
},
|
||||
{
|
||||
"investor_name": "DJS KETENAGAKERJAAN PROGRAM JAMINAN HARI TUA",
|
||||
"ticker_count": 31,
|
||||
"row_count": 31,
|
||||
"sum_percentage": 72.96
|
||||
},
|
||||
{
|
||||
"investor_name": "UBS AG SINGAPORE BRANCH",
|
||||
"ticker_count": 27,
|
||||
"row_count": 27,
|
||||
"sum_percentage": 94.61
|
||||
},
|
||||
{
|
||||
"investor_name": "DBS BANK LTD.",
|
||||
"ticker_count": 25,
|
||||
"row_count": 25,
|
||||
"sum_percentage": 84.55
|
||||
},
|
||||
{
|
||||
"investor_name": "CGS INTERNATIONAL SECURITIES SINGAPORE PTE LTD",
|
||||
"ticker_count": 25,
|
||||
"row_count": 25,
|
||||
"sum_percentage": 136.07
|
||||
},
|
||||
{
|
||||
"investor_name": "GOVERNMENT OF NORWAY",
|
||||
"ticker_count": 24,
|
||||
"row_count": 24,
|
||||
"sum_percentage": 38.61
|
||||
},
|
||||
{
|
||||
"investor_name": "MAYBANK SECURITIES PTE. LTD.",
|
||||
"ticker_count": 22,
|
||||
"row_count": 22,
|
||||
"sum_percentage": 62.35
|
||||
},
|
||||
{
|
||||
"investor_name": "EMPLOYEES PROVIDENT FUND BOARD",
|
||||
"ticker_count": 21,
|
||||
"row_count": 21,
|
||||
"sum_percentage": 35.9
|
||||
},
|
||||
{
|
||||
"investor_name": "PANIN SEKURITAS Tbk, PT",
|
||||
"ticker_count": 18,
|
||||
"row_count": 18,
|
||||
"sum_percentage": 48.8
|
||||
},
|
||||
{
|
||||
"investor_name": "FIDELITY FUNDS",
|
||||
"ticker_count": 18,
|
||||
"row_count": 18,
|
||||
"sum_percentage": 57.73
|
||||
},
|
||||
{
|
||||
"investor_name": "DRS SURONO SUBEKTI",
|
||||
"ticker_count": 17,
|
||||
"row_count": 17,
|
||||
"sum_percentage": 50.71
|
||||
},
|
||||
{
|
||||
"investor_name": "JAKSA AGUNG MUDA BIDANG TINDAK PIDANA KHUSUS KEJAKSAAN REPUBLIK INDONESIA KEJAKSAAN REPUBLIK INDONESIA",
|
||||
"ticker_count": 17,
|
||||
"row_count": 17,
|
||||
"sum_percentage": 312.31
|
||||
},
|
||||
{
|
||||
"investor_name": "PT TRIMEGAH SEKURITAS INDONESIA TBK",
|
||||
"ticker_count": 15,
|
||||
"row_count": 15,
|
||||
"sum_percentage": 76.52
|
||||
}
|
||||
],
|
||||
"most_concentrated_tickers": [
|
||||
{
|
||||
"share_code": "IBST",
|
||||
"issuer_name": "INTI BANGUN SEJAHTERA Tbk",
|
||||
"holders_gt1_count": 1,
|
||||
"sum_pct_gt1": 99.95,
|
||||
"largest_holder_pct": 99.95
|
||||
},
|
||||
{
|
||||
"share_code": "PGUN",
|
||||
"issuer_name": "PRADIKSI GUNATAMA Tbk",
|
||||
"holders_gt1_count": 6,
|
||||
"sum_pct_gt1": 99.93,
|
||||
"largest_holder_pct": 38.44
|
||||
},
|
||||
{
|
||||
"share_code": "HITS",
|
||||
"issuer_name": "HUMPUSS INTERMODA TRANSPORTASI Tbk",
|
||||
"holders_gt1_count": 4,
|
||||
"sum_pct_gt1": 99.92,
|
||||
"largest_holder_pct": 50.57
|
||||
},
|
||||
{
|
||||
"share_code": "SUPR",
|
||||
"issuer_name": "SOLUSI TUNAS PRATAMA Tbk",
|
||||
"holders_gt1_count": 2,
|
||||
"sum_pct_gt1": 99.92,
|
||||
"largest_holder_pct": 97.33
|
||||
},
|
||||
{
|
||||
"share_code": "DCII",
|
||||
"issuer_name": "DCI INDONESIA Tbk",
|
||||
"holders_gt1_count": 10,
|
||||
"sum_pct_gt1": 99.85,
|
||||
"largest_holder_pct": 29.9
|
||||
},
|
||||
{
|
||||
"share_code": "POLU",
|
||||
"issuer_name": "GOLDEN FLOWER Tbk",
|
||||
"holders_gt1_count": 5,
|
||||
"sum_pct_gt1": 99.81,
|
||||
"largest_holder_pct": 79.99
|
||||
},
|
||||
{
|
||||
"share_code": "ROCK",
|
||||
"issuer_name": "ROCKFIELDS PROPERTI INDONESIA Tbk",
|
||||
"holders_gt1_count": 8,
|
||||
"sum_pct_gt1": 99.8,
|
||||
"largest_holder_pct": 27
|
||||
},
|
||||
{
|
||||
"share_code": "FASW",
|
||||
"issuer_name": "FAJAR SURYA WISESA Tbk",
|
||||
"holders_gt1_count": 2,
|
||||
"sum_pct_gt1": 99.78,
|
||||
"largest_holder_pct": 59.85
|
||||
},
|
||||
{
|
||||
"share_code": "BPII",
|
||||
"issuer_name": "BATAVIA PROSPERINDO INTERNASIONAL Tbk",
|
||||
"holders_gt1_count": 3,
|
||||
"sum_pct_gt1": 99.74,
|
||||
"largest_holder_pct": 89.86
|
||||
},
|
||||
{
|
||||
"share_code": "MORA",
|
||||
"issuer_name": "MORA TELEMATIKA INDONESIA Tbk",
|
||||
"holders_gt1_count": 10,
|
||||
"sum_pct_gt1": 99.73,
|
||||
"largest_holder_pct": 35.99
|
||||
},
|
||||
{
|
||||
"share_code": "POLI",
|
||||
"issuer_name": "POLLUX HOTELS GROUP Tbk",
|
||||
"holders_gt1_count": 7,
|
||||
"sum_pct_gt1": 99.72,
|
||||
"largest_holder_pct": 56.95
|
||||
},
|
||||
{
|
||||
"share_code": "BNLI",
|
||||
"issuer_name": "BANK PERMATA Tbk",
|
||||
"holders_gt1_count": 4,
|
||||
"sum_pct_gt1": 99.71,
|
||||
"largest_holder_pct": 89.12
|
||||
},
|
||||
{
|
||||
"share_code": "ABDA",
|
||||
"issuer_name": "ASURANSI BINA DANA ARTA Tbk",
|
||||
"holders_gt1_count": 4,
|
||||
"sum_pct_gt1": 99.67,
|
||||
"largest_holder_pct": 86.75
|
||||
},
|
||||
{
|
||||
"share_code": "SOHO",
|
||||
"issuer_name": "SOHO GLOBAL HEALTH Tbk",
|
||||
"holders_gt1_count": 7,
|
||||
"sum_pct_gt1": 99.67,
|
||||
"largest_holder_pct": 40.03
|
||||
},
|
||||
{
|
||||
"share_code": "TIFA",
|
||||
"issuer_name": "KDB TIFA FINANCE Tbk",
|
||||
"holders_gt1_count": 4,
|
||||
"sum_pct_gt1": 99.61,
|
||||
"largest_holder_pct": 77.5
|
||||
}
|
||||
],
|
||||
"least_concentrated_tickers": [
|
||||
{
|
||||
"share_code": "DEAL",
|
||||
"issuer_name": "DEWATA FREIGHTINTERNATIONAL Tbk",
|
||||
"holders_gt1_count": 11,
|
||||
"sum_pct_gt1": 35.8,
|
||||
"largest_holder_pct": 10.25
|
||||
},
|
||||
{
|
||||
"share_code": "ELTY",
|
||||
"issuer_name": "BAKRIELAND DEVELOPMENT Tbk",
|
||||
"holders_gt1_count": 13,
|
||||
"sum_pct_gt1": 30.72,
|
||||
"largest_holder_pct": 5.35
|
||||
},
|
||||
{
|
||||
"share_code": "LMAS",
|
||||
"issuer_name": "LIMAS INDONESIA MAKMUR Tbk",
|
||||
"holders_gt1_count": 9,
|
||||
"sum_pct_gt1": 30.14,
|
||||
"largest_holder_pct": 7.46
|
||||
},
|
||||
{
|
||||
"share_code": "IKAI",
|
||||
"issuer_name": "INTIKERAMIK ALAMASRI INDUSTRI Tbk",
|
||||
"holders_gt1_count": 6,
|
||||
"sum_pct_gt1": 29.68,
|
||||
"largest_holder_pct": 19.34
|
||||
},
|
||||
{
|
||||
"share_code": "DADA",
|
||||
"issuer_name": "DIAMOND CITRA PROPERTINDO Tbk",
|
||||
"holders_gt1_count": 5,
|
||||
"sum_pct_gt1": 26.24,
|
||||
"largest_holder_pct": 21.53
|
||||
},
|
||||
{
|
||||
"share_code": "ENVY",
|
||||
"issuer_name": "ENVY TECHNOLOGIES INDONESIA Tbk",
|
||||
"holders_gt1_count": 8,
|
||||
"sum_pct_gt1": 26.21,
|
||||
"largest_holder_pct": 7.24
|
||||
},
|
||||
{
|
||||
"share_code": "TAXI",
|
||||
"issuer_name": "EXPRESS TRANSINDO UTAMA Tbk",
|
||||
"holders_gt1_count": 12,
|
||||
"sum_pct_gt1": 25.53,
|
||||
"largest_holder_pct": 4.89
|
||||
},
|
||||
{
|
||||
"share_code": "WIRG",
|
||||
"issuer_name": "WIR ASIA Tbk",
|
||||
"holders_gt1_count": 12,
|
||||
"sum_pct_gt1": 22.28,
|
||||
"largest_holder_pct": 4.8
|
||||
},
|
||||
{
|
||||
"share_code": "PADI",
|
||||
"issuer_name": "MINNA PADI INVESTAMA SEKURITAS Tbk",
|
||||
"holders_gt1_count": 7,
|
||||
"sum_pct_gt1": 17.91,
|
||||
"largest_holder_pct": 5.75
|
||||
},
|
||||
{
|
||||
"share_code": "RMKO",
|
||||
"issuer_name": "ROYALTAMA MULIA KONTRAKTORINDO Tbk",
|
||||
"holders_gt1_count": 2,
|
||||
"sum_pct_gt1": 17.8,
|
||||
"largest_holder_pct": 15.4
|
||||
},
|
||||
{
|
||||
"share_code": "NCKL",
|
||||
"issuer_name": "TRIMEGAH BANGUN PERSADA Tbk",
|
||||
"holders_gt1_count": 3,
|
||||
"sum_pct_gt1": 12.03,
|
||||
"largest_holder_pct": 6.5
|
||||
},
|
||||
{
|
||||
"share_code": "BBTN",
|
||||
"issuer_name": "BANK TABUNGAN NEGARA (PERSERO) Tbk",
|
||||
"holders_gt1_count": 4,
|
||||
"sum_pct_gt1": 9.98,
|
||||
"largest_holder_pct": 4.95
|
||||
},
|
||||
{
|
||||
"share_code": "BBNI",
|
||||
"issuer_name": "BANK NEGARA INDONESIA Tbk",
|
||||
"holders_gt1_count": 4,
|
||||
"sum_pct_gt1": 7.95,
|
||||
"largest_holder_pct": 3.51
|
||||
},
|
||||
{
|
||||
"share_code": "ADHI",
|
||||
"issuer_name": "ADHI KARYA (PERSERO) Tbk",
|
||||
"holders_gt1_count": 4,
|
||||
"sum_pct_gt1": 7.37,
|
||||
"largest_holder_pct": 2.68
|
||||
},
|
||||
{
|
||||
"share_code": "BBRI",
|
||||
"issuer_name": "BANK RAKYAT INDONESIA (PERSERO) Tbk",
|
||||
"holders_gt1_count": 3,
|
||||
"sum_pct_gt1": 5.86,
|
||||
"largest_holder_pct": 3.63
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
63
research/package-lock.json
generated
63
research/package-lock.json
generated
|
|
@ -1,63 +0,0 @@
|
|||
{
|
||||
"name": "research",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "research",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"pdf-parse": "^1.1.1",
|
||||
"pdf2json": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-ensure": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz",
|
||||
"integrity": "sha512-DRI60hzo2oKN1ma0ckc6nQWlHU69RH6xN0sjQTjMpChPfTYvKZdcQFfdYK2RWbJcKyUizSIy/l8OTGxMAM1QDw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pdf-parse": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/pdf-parse/-/pdf-parse-1.1.1.tgz",
|
||||
"integrity": "sha512-v6ZJ/efsBpGrGGknjtq9J/oC8tZWq0KWL5vQrk2GlzLEQPUDB1ex+13Rmidl1neNN358Jn9EHZw5y07FFtaC7A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^3.1.0",
|
||||
"node-ensure": "^0.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pdf2json": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pdf2json/-/pdf2json-4.0.2.tgz",
|
||||
"integrity": "sha512-iiRSuRmLihoEJ4YGkoqSq3/r4MR0OmkMTYDda0Pq7DAWqJwMylTilXu46T16gfS3DUp3fhiVuz7NtRMbk3uBhw==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"pdf2json": "bin/pdf2json.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.18.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"name": "research",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"pdf-parse": "^1.1.1",
|
||||
"pdf2json": "^4.0.2"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue