Skip to content

jiprastyo/skriner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3,095 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Skriner Berita & Teknikal 1D: Dokumentasi Sistem & Panduan Arsitektur Dashboard Saham BEI

Selamat datang di repositori resmi Skriner Berita & Teknikal 1D—sebuah dashboard pemantauan teknikal dan keterbukaan informasi saham Bursa Efek Indonesia (BEI) yang berbasis halaman tunggal (Single-Page Application / SPA).

Dokumentasi ini ditulis dalam Bahasa Indonesia untuk menjadi keterangan resmi repositori GitHub Anda dan mempermudah pemahaman sistem, serta siap diimpor sebagai konteks komprehensif bagi model AI lainnya.


Pembaruan Terkini (Juli 2026)

  • Library Skill .claude/skills/ untuk Kontributor/Sesi AI (Baru): Repositori kini memiliki 10 skill terdokumentasi (onboarding, guardrails, pipeline-debugging, idx-scraping, add-data-source, data-validation, frontend-dev, infra-deploy, design-taste, roadmap) plus aturan baku di CLAUDE.md. Setiap sesi AI atau kontributor baru wajib memulai dari .claude/skills/onboarding/SKILL.md sebelum menyentuh kode atau data apa pun.
  • Perbaikan Kartu IHSG (commit bbaeffd): Parsing tanggal pada kartu IHSG kini di-anchor ke zona waktu WIB, memperbaiki selisih 1 hari yang dilihat pengunjung di zona waktu barat. Hari tanpa data nilai transaksi kini tampil sebagai celah jujur (garis putus-putus) alih-alih hilang diam-diam dari grafik. Kartu juga menampilkan catatan kecil saat data yang tampil berasal dari fallback /data yang basi (bukan CDN langsung).
  • Perbaikan Pipeline & Observabilitas: Bug variable-shadowing pada variabel meta di skriner_sync.py sudah diperbaiki (di-rename menjadi yf_meta), sehingga field kesehatan ihsg_* di data/update_metadata.json kini benar-benar tersimpan alih-alih hanya ditulis oleh script rescue. Field observabilitas baru lapbul_last_attempt_at/_ok/_reason (ditulis oleh scraper/fetch_lapbul_full.py) dan free_float_scrape_last_attempt_at/_ok/_reason + _reports_discovered_count (ditulis oleh scripts/scrape_free_float.py) kini merekam setiap percobaan scrape, termasuk yang gagal senyap.
  • Isu Diketahui (BELUM selesai): Scraping LBRE/Lapbul mati sejak 14 Juni 2026 — tidak ada commit baru dari sync_daily_lapbul.yml walau cron harian tetap berjalan. Analisis akar masalah lengkap dan tindakan yang perlu dilakukan pemilik (menambah langkah instalasi Playwright ke sync_daily_lapbul.yml, memeriksa riwayat run di GitHub Actions) ada di BUGS_AND_FIXES_2026-07-12.md.
  • README Dirapikan: Duplikasi seksi §8–§13 (akibat merge sebelumnya) dihapus sehingga masing-masing seksi kini hanya muncul sekali, dan jadwal workflow di §7 disinkronkan ulang dengan YAML aktual di .github/workflows/.

Pembaruan Terkini (Juni 2026)

  • Deskripsi Perusahaan Berbahasa Indonesia (Baru): Menggantikan ringkasan profil Yahoo Finance berbahasa Inggris dengan deskripsi perusahaan komprehensif asli berbahasa Indonesia yang ditarik dari IDNFinancials. Fitur ini menggunakan integrasi khusus (scraper/fetch_idn_desc.py) yang berjalan secara mingguan otomatis untuk 900+ emiten, sekaligus dirotasi dalam pembaruan harian. Tampilan pada antarmuka kini dilengkapi atribusi sumber (misal: "Sumber: IDNFinancials (Diperbarui: 22 Jun 2026)").
  • Migrasi ke Next.js SPA: Menggantikan berkas HTML tunggal (legacy skriner_v8.html) dengan arsitektur Next.js di dalam folder skriner-light/. Ini memberikan performa rendering yang lebih cepat, navigasi tab yang mulus, dan pengelolaan status yang efisien.
  • Tampilan Pencarian (Search View) Disempurnakan:
    • Pada perangkat seluler, posisi bilah pencarian kini berada di urutan teratas.
    • Hasil pencarian diurutkan dengan cerdas (Prioritas: kecocokan awalan kode saham > kandungan kode saham > nama perusahaan / nama pemilik).
    • Mengeklik hasil pencarian akan langsung membuka kartu saham (StockCard) di tab Pencarian tersebut tanpa harus melompat kembali ke tab Home.
  • Pengalaman Navigasi Seluler: Tombol navigasi bawah (bottom navbar) telah dirapikan. Menu Filter dan Urutkan (Sort) sekarang terbuka sebagai panel slide-out tanpa memindahkan Anda dari tab Home. Tombol Cari ditempatkan di posisi paling kanan agar mudah dijangkau.
  • Integrasi TradingView: Sekarang, mengklik kode saham (ticker) atau logo perusahaan pada kartu akan langsung membuka grafik riwayat saham di TradingView.
  • Perbaikan Tampilan Logo Emiten: Alamat CDN penyedia logo diperbaiki ke assets.stockbit.com sehingga logo dapat dimuat tanpa kendala.
  • Kalkulator Lot Semakin Lengkap: Menambahkan informasi "Ref. Entri Senyap (1% Trx)" di bawah kalkulasi total dana, yang mengacu pada 1% rata-rata nilai transaksi saham harian.
  • Integrasi Broker Research & Market News: Ditambahkan fitur untuk secara otomatis merayapi (scrape) ringkasan pasar dari sekuritas lokal (IndoPremier IPOT News, Phintraco Sekuritas, Samuel Sekuritas, Henan Putihrai/HP Sekuritas) agar investor bisa melihat ringkasan harian langsung di halaman utama. Modul ini sekarang memiliki retensi pintar 30 hari berdasarkan stempel waktu publikasi sebenarnya. Pada kartu IHSG, item IPOT ditampilkan selektif hanya untuk headline ringkasan pasar seperti IHSG, Bursa Pagi, Indonesia Market Summary, Wall Street, dan Bursa Eropa agar feed tidak didominasi trafik IPOT umum.
  • True "Nilai Transaksi" & Konsistensi Kartu IHSG 60 Hari: Grafik volume IHSG ditarik langsung dari API Ringkasan Perdagangan BEI resmi untuk menampilkan transaksi harian aktual dalam Triliun/Miliar Rupiah (T/B). Khusus pada kartu IHSG ini, logika perhitungan volume rata-rata harian dan keterangan di bawah grafik distandarkan ketat menggunakan acuan 60 Hari Terakhir (Avg 60 Days), didukung kapasitas penyimpanan riwayat backend hingga 60 hari bursa.
  • Label Tanggal Jujur Terpisah (Decoupled Date Labels - Baru): Menghilangkan potensi misinformasi dengan memisahkan keterangan tanggal pembaruan di header kartu secara independen: label Harga (data_date Yahoo Finance per saham), label IHSG (ihsgData.date), dan label Sektoral (sektorDate), sehingga setiap elemen mencerminkan tanggal transaksi aktual datanya secara jujur.
  • Perbaikan Riset Broker & PDF Lampiran (Baru): Pemulihan parameter URL IPOTnews (jdl dan group_news) agar tidak mengarah ke halaman kosong, serta penambahan ekstraksi PDF lampiran otomatis (PDF scraping) untuk Phintraco Sekuritas, Samuel Sekuritas, dan Henan Putihrai (HP) Sekuritas yang terintegrasi dengan gaya "Lampiran" di halaman utama.
  • Penyempurnaan Antarmuka Berita & Flex-Clipping (Baru): Memperkecil dan merapikan tombol "Lihat kabar lainnya" agar tidak menggunakan warna mencolok (neon) melainkan warna abu-abu redup solid (muted gray) yang lebih menyatu dengan kartu. Desain kartu diperbarui dengan border-radius lebih tajam (8px dari sebelumnya 12px), dan tinggi kontainer berita ketika kolaps diselaraskan menjadi 310px dengan sistem flex-clipping (overflow: hidden pada .news-items-wrapper). Hal ini memungkinkan area kosong di kartu yang memanjang (seperti DSSA) otomatis terisi dengan berita tambahan (sampai dengan 8 berita) tanpa merusak kerapian grid.
  • Perbaikan Navigasi Tag Syariah (Baru): Menambahkan penanganan preventDefault() pada tombol filter ISSI dan NON-ISSI pada kartu emiten, sehingga menekan tombol tag tersebut kini menyaring daftar emiten sharia secara instan dan tidak lagi memicu navigasi paksa ke halaman TradingView dari tautan kartu induk.
  • Dukungan & Resiliensi Windows Task Scheduler (Terbaru): Memperbaiki masalah eksekusi di latar belakang Windows Task Scheduler dengan memicu perintah penggantian direktori kerja (cd /d) ke direktori utama proyek sebelum menjalankan python melalui skrip batch otomatis (run_yfinance.bat and run_news_hourly.bat). Selain itu, penjadwal dikonfigurasi kokoh dengan opsi StartWhenAvailable = $true via PowerShell untuk memastikan tugas yang terlewat (misalnya saat laptop tertidur/mati) akan langsung dijalankan secara otomatis saat perangkat menyala kembali.

1. Arsitektur Sistem & Aliran Data

Skriner dirancang menggunakan arsitektur modular yang terpisah antara pengambilan data (backend sync) dan penyajian visual (frontend SPA).

Diagram Aliran Data Sistem

graph TD
    %% Scraper Data Collection
    IDX[Official IDX GET API / Pengumuman] -->|Data Keterbukaan Saham| Scraper[skriner_sync.py Scraper]
    IDX -->|Pengumuman Status Pemenuhan Free Float bulk PDF| FFStatusScraper[parse_idx_freefloat_status_pdf.py]
    IDX -->|Laporan Bulanan Registrasi Pemegang Saham| FFScraper[scrape_free_float.py Lapbul fallback]
    IDX -->|Metadata emiten resmi / DES / konstituen indeks| MetadataScraper[scraper/fetch_metadata.py]
    IDX -->|Pemegang Saham di atas 1% KSEI + Lapbul| OwnershipScraper[scraper/fetch_1pct.py + fetch_lapbul_full.py]
    MetadataScraper -->|Staging/cache| MetadataStage[docs/data/ihsg_tags.*]
    MetadataStage -->|Publish dashboard catalog| MetadataDB[data/ownership_ihsg_tags.*]
    MetadataDB -->|Katalog utama ticker: name/sector/board/IPO/tags| Scraper
    FFStatusScraper -->|Snapshot resmi bulk| FFStatus[data/idx_free_float_status.json]
    FFStatus -->|Prioritas utama Free Float resmi IDX| Scraper
    FFScraper -->|Fallback resmi per-emiten| FFTracker[data/free_float_tracker.json]
    FFTracker -->|Fallback Free Float resmi IDX/Lapbul| Scraper
    YF[Yahoo Finance API 2Y Chart] -->|"Harga, RSI, MACD, EMA/SMA/VMA, ATR, ADR, Vol; bukan Free Float"| Scraper
    IDN[IDNFinancials] -->|"Profil Singkat Perusahaan Berbahasa Indonesia"| Scraper
    News[CNBC, Kontan, Bisnis, IDX Channel, Bloomberg Technoz, EmitenNews, Katadata, IDN Financials, SWA] -->|RSS/HTML News Crawling| Scraper
    MarketNews[IPOT News, Phintraco Sekuritas, Samuel Sekuritas, HP Sekuritas] -->|"Market Summaries & Broker Research"| MarketScraper[scripts/fetch_market_news.py]
    Catalog[Unified_Daftar_Saham_IHSG_dan_Indeks.csv] -->|Fallback/supplement shares & old free float only| Scraper

    %% Consolidated compilation
    Scraper -->|Self-Contained Indicator Engine| Compile{JSON Compiler}
    MarketScraper --> Compile
    Compile -->|Ekspor JSON| DisclosuresDB[data/skriner_data.json & market_news.json]
    OwnershipScraper -->|Staging/cache| OwnershipStage[docs/data/latest*.json/csv + governance csv]
    OwnershipStage -->|Publish dashboard layer| OwnershipDB[data/ownership_*]

    %% Web App consumption
    DisclosuresDB -->|Fetch teknikal/news| WebApp["Next.js Frontend SPA (skriner-light)"]
    OwnershipDB -->|Fetch kepemilikan keyed by ticker| WebApp
    
    %% UI Presentation
    WebApp -->|Filtering & Sorting Reaktif| View[Next.js Client Grid View]
    WebApp -->|Kepemilikan block per ticker| OwnershipView[Ownership block inside card]
    WebApp -->|Modal Detail Kabar Efek| Modal[Popup Keterbukaan Emiten]
    %% GitHub Actions - Scheduled Workflows
    GA1[sync_technical.yml] -->|"Tanpa cron; dispatch iPhone ~17:15 WIB + metadata pre-refresh"| MetadataScraper
    GA1 --> Scraper
    GA2[sync_news.yml] -->|"Tanpa cron; dispatch iPhone tiap jam"| Scraper
    GA3[sync_freefloat.yml] -->|"Otomatis mingguan (Senin 01:21 WIB): bulk IDX status PDF; Lapbul manual ticker/limit"| FFStatusScraper
    GA3 -->|"Manual fallback only"| FFScraper
    GA3 --> MetadataScraper
    GA3 --> Scraper
    GA4[sync_ownership.yml] -->|"Bulanan otomatis (tanggal 5, 13:00 WIB): 1% + full Lapbul governance, tanpa input"| OwnershipScraper
    GA5[sync_metadata.yml] -->|"Mingguan (Senin 01:11 WIB)/manual"| MetadataScraper
    GA6[sync_daily_lapbul.yml] -->|"Harian 18:30 WIB"| FFStatusScraper
    GA7[data_sync.yml] -->|"Harian 08:00, 12:00, 17:00 WIB"| Scraper
Loading

Penjelasan Komponen:

  1. Backend Sync Core (scripts/skriner_sync.py): Modul Python mandiri penuh yang berisi engine gabungan untuk indikator teknikal Yahoo Finance, Kabar, dan IDX Keterbukaan Informasi. Entry harian dipisah menjadi scripts/scrape_yahoofinance.py untuk teknikal (bukan Free Float) dan scripts/scrape_kabar_keterbukaan.py untuk Kabar + pengumuman resmi IDX. Free Float dashboard hanya memakai sumber resmi IDX: data/idx_free_float_status.json sebagai prioritas utama dan data/free_float_tracker.json Lapbul sebagai fallback. Katalog ticker dibaca dari snapshot metadata resmi IDX (data/ownership_ihsg_tags.json / docs/data/ihsg_tags.json); CSV lama hanya fallback/supplement untuk field yang belum tersedia seperti shares dan free-float awal.
  2. Free Float Scraper (scripts/scrape_free_float.py): Scraper otomatis bertenaga tinggi yang memindai pengumuman keterbukaan informasi bulanan BEI untuk mengidentifikasi LBRE pemegang saham terverifikasi, mengekstrak data kepatuhan, dan merekam tautan bukti fisik PDF laporan resmi. Menggunakan fungsi discovery Lapbul yang sama dengan scraper/fetch_lapbul_full.py (discover_lapbul_reports), sehingga kedua feed berbagi risiko blokir/fallback yang sama.
  3. Official IDX Metadata & Ownership Scraper (scraper/): Modul mandiri yang sudah terintegrasi ke repo ini. fetch_metadata.py mengambil metadata ticker resmi IDX/DES/index (nama emiten, papan, sektor, IPO, ISSI, LQ45, KOMPAS100) sebagai katalog utama dashboard; fetch_1pct.py mengambil Pemegang Saham di atas 1% dari KSEI. Output staged di docs/data/ lalu dipublikasikan ke layer dashboard data/ownership_*. ⚠️ Pengendali (PG) dan UBO di-drop sementara dari rendering dashboard karena data masih tidak lengkap dan metode Lapbul terlalu intensif resource.
  4. Frontend SPA (skriner-light/): Aplikasi dashboard reaktif berbasis Next.js React SPA yang dikembangkan dalam folder terpisah skriner-light/. Kode produksi dikompilasi secara otomatis oleh Vercel pada saat kode didorong (push) ke GitHub. Data JSON hasil perayapan scraper disimpan langsung di subdirektori publik skriner-light/public/data/ agar situs web dapat menyajikan informasi secara statis dengan kinerja tinggi tanpa membutuhkan database server aktif.
  5. Market News Scraper (scripts/fetch_market_news.py): Script yang merayapi portal investasi publik untuk mendapatkan Market Summary (Bursa Pagi/Siang/Sore) dari IPOT News serta riset harian/lampiran PDF dari Phintraco Sekuritas, Samuel Sekuritas, dan Henan Putihrai (HP) Sekuritas.

2. Model Data & Skema Database Lokal

Repositori ini menggunakan snapshot metadata resmi IDX sebagai katalog ticker utama, ditambah berkas JSON hasil kompilasi teknikal/news/free-float/ownership.

A. Katalog Metadata Resmi IDX (data/ownership_ihsg_tags.*, docs/data/ihsg_tags.*)

Merupakan katalog ticker resmi hasil scraper/fetch_metadata.py, bukan lagi CSV/XLSX statis sebagai sumber utama. Field utama: ticker, name, syariah, papan, sector, kompas100, lq45, ipo_year, ipo_date, tags_updated_at.

data/ownership_ihsg_tags.json dipakai oleh scripts/skriner_sync.py sebagai katalog utama untuk data/skriner_data.json. docs/data/ihsg_tags.* adalah staging/cache native scraper. Jika IDX/GitHub Actions sedang diblokir, scraper mempertahankan snapshot lama agar dashboard tetap self-contained. Untuk pengumuman ISSI mayor berbentuk ZIP/XLSX resmi IDX (contoh No. Peng-00089_BEI.POP_05-2026-ID.zip), parser hanya mengambil tabel konstituen aktif pertama dan memperlakukan tabel kedua setelah marker "Konstituen yang keluar dari penghitungan indeks" sebagai daftar exclusion, sehingga ticker seperti MINA/HUMI/GTSI tidak diberi tag ISSI pada periode efektif 2 Juni 2026.

Unified_Daftar_Saham_IHSG_dan_Indeks.csv masih ada hanya sebagai fallback/supplement untuk shares dan free-float lama; bukan lagi sumber utama nama/sektor/papan/IPO/ISSI/LQ45/KOMPAS100. File XLSX manual lama sudah tidak diperlukan oleh pipeline dan tidak menjadi bagian input GitHub Actions.

B. JSON Data Teknikal (data/skriner_data.json)

Berisi rincian harga terakhir, perubahan persentase harian, indikator RSI, ATR%, ADR%, status Moving Average harian, skor teknikal, dan metrik Vol Pengali terbaru.

{
  "last_updated": "2026-05-29T11:23:00+07:00",
  "stocks": {
    "BBCA": {
      "code": "BBCA",
      "price": 10250,
      "pct": 1.48,
      "rsi": 54.83,
      "atrPct": 1.84,
      "adrPct": 1.72,
      "macdBull": true,
      "vol_mult_1d": 1.45,
      "vol_mult_20d": 2.10,
      "skor": 7.5,
      "maStatus": {
        "ema3": true, "ema5": true, "ema10": true
      }
    }
  }
}

C. JSON Status Free Float Resmi IDX (data/idx_free_float_status.json)

Berisi snapshot bulk resmi dari pengumuman IDX Status Pemenuhan Kewajiban Jumlah Saham Free Float dan Jumlah Pemegang Saham. Field penting: idx_status_free_float_display, period, source_url, dan evidence. Snapshot ini adalah sumber utama free_float di dashboard.

C2. JSON Laporan Free Float Tracker Lapbul (data/free_float_tracker.json)

Berisi basis data penyerahan LBRE/Lapbul dari emiten hasil crawling resmi BEI. Sekarang hanya dipakai sebagai fallback resmi jika ticker belum tersedia pada bulk status Free Float IDX.

D. Layer Kepemilikan Resmi IDX/KSEI (data/ownership_*)

Dashboard juga memuat layer tambahan dari scraper resmi IDX/KSEI yang sudah terintegrasi di repo ini (scraper/):

  • data/ownership_latest.json / .csv: tabel Pemegang Saham di atas 1% per ticker, berisi pemilik, klasifikasi investor, lokal/asing, jumlah saham, dan persentase. Ini adalah sumber utama kepemilikan karena satu dokumen KSEI mencakup hampir seluruh ticker; snapshot 2 Juni 2026 berisi data PDF per 29-May-2026 dan menggantikan snapshot April untuk ticker seperti MINA.
  • data/ownership_pengendali.csv dan data/ownership_ubo.csv: ⚠️ tidak lagi difetch oleh frontend per Juni 2026. Data PG/UBO di-drop sementara karena Lapbul tidak mencakup semua emiten dan metode scraping resource-intensive. File fisik tetap ada di repo untuk keperluan staging.
  • data/ownership_summary.json: metadata tanggal/sumber scrape Pemegang Saham di atas 1%; data/ownership_governance_summary.json disimpan terpisah tapi tidak dikonsumsi frontend saat ini.
  • data/ownership_ihsg_tags.*: metadata ticker resmi tambahan dari IDX/DES/index konstituen.
  • docs/data/latest*, docs/data/ihsg_tags*: staging/cache native output scraper. File ini sengaja ikut disimpan di repo agar workflow tetap self-contained dan bisa mempertahankan snapshot lama jika GitHub Actions sedang diblokir IDX/Cloudflare.

Layer ini dipakai secara terpisah dari data/skriner_data.json agar data teknikal/news tetap bersih. Frontend menggabungkan data berdasarkan code/share_code dan menampilkan seluruh pemilik di atas 1% pada setiap card; pencarian juga bisa menemukan nama investor. Pada markup card, blok Kepemilikan berada di dalam .card-left-col namun di luar .card-mini-tech, sehingga kepemilikan tampil sebagai panel tersendiri, bukan bagian dari indikator teknikal.

E. Inventaris Data Dashboard: Sumber dan Cara Mendapatkannya

Prinsip utama repo ini: dashboard harus self-sufficient. Semua scraper, workflow, snapshot, dan dependensi Python yang diperlukan untuk memperbarui data harus berada di repo ini. GitHub Actions tidak boleh bergantung pada file XLSX/CSV yang harus ditempel manual dari laptop. Jika IDX/Cloudflare memblokir IP GitHub Actions, workflow harus mempertahankan snapshot terakhir yang sudah tersimpan di repo, bukan membuat dashboard kosong.

Kebutuhan dashboard File runtime Field penting Sumber utama Cara mendapatkan / workflow
Katalog ticker, nama, sektor, papan, IPO, ISSI/non-ISSI, LQ45, KOMPAS100 data/skriner_data.json hasil merge dari data/ownership_ihsg_tags.json; staging docs/data/ihsg_tags.* code, name, sector, board, listing_date, ipo_year, tags, metadata_source, metadata_updated_at Resmi IDX: GetCompanyProfiles, DES/syariah resmi IDX, ZIP/announcement konstituen LQ45/KOMPAS100 python scraper/fetch_metadata.py → copy docs/data/ihsg_tags.* ke data/ownership_ihsg_tags.*; otomatis di sync_metadata.yml, sync_technical.yml, sync_freefloat.yml, `sync_owners
Keterbukaan informasi emiten dan berita pasar data/skriner_data.json announcement, announcements[].title/date/url/summary/source/category Utama: IDX GetAnnouncement; tambahan konteks berita: CNBC, Kontan, Bisnis, IDX Channel, IDN Financials, Bloomberg Technoz, EmitenNews, Katadata, SWA. Parser EmitenNews memprioritaskan timestamp publikasi eksplisit halaman artikel (dd/mm/yyyy HH:mm WIB) dan menolak tanggal publikasi masa depan agar tanggal aksi korporasi di judul (mis. cum/cair dividen) tidak salah dipakai sebagai tanggal berita. Guardrail final sebelum JSON output juga memperbaiki/menolak seluruh announcement future-date, termasuk existing record dari sync sebelumnya. python scripts/scrape_kabar_keterbukaan.py; otomatis sync_news.yml tiap jam pada menit 17. Entry ini menjaga indikator Yahoo lama via mode --only-news, sekaligus memicu update portal market news (Phintraco, MNC, IPOT, Samuel).
Pemegang Saham di atas 1% data/ownership_latest.json, data/ownership_latest.csv; staging docs/data/latest.* date, share_code, issuer_name, investor_name, investor_classification, local_foreign, nationality, domicile, holdings_scripless, holdings_scrip, total_holding_shares, percentage Resmi KSEI via IDX announcement: PDF "Pemegang Saham di atas 1%" attachment _lamp1.pdf / _lamp.pdf python scraper/fetch_1pct.py; workflow sync_ownership.yml manual-only agar tidak menghabiskan kuota Actions
Pengendali (PG) data/ownership_pengendali.csv; staging docs/data/latest_pengendali.csv date, share_code, issuer_name, investor_name, investor_type, role Resmi IDX: per-emiten Laporan Bulanan Registrasi Pemegang Efek; semua tabel yang memiliki kolom Nama + Pengendali/Afiliasi Pengendali bertanda X/checkmark, termasuk Direksi/Komisaris dan pemegang saham 5%+ python scraper/fetch_lapbul_full.py --ticker BOLT untuk murah; full all-emiten berjalan otomatis setiap bulan lewat cron sync_ownership.yml (tanggal 5, 13:00 WIB), tanpa input manual
UBO / Pemilik Manfaat Akhir data/ownership_ubo.csv; staging docs/data/latest_ubo.csv date, share_code, investor_name, investor_type, direct_ownership, direct_shareholder_name, percentage, evidence Resmi IDX: per-emiten Laporan Bulanan Registrasi Pemegang Efek; tabel Pemilik Manfaat / Penerima Manfaat Akhir / Pemilik Manfaat Akhir. Jika Nama Pemegang Saham Langsung terisi, nilainya disimpan sebagai evidence perusahaan pengendali langsung python scraper/fetch_lapbul_full.py --ticker BOLT untuk murah; full all-emiten berjalan otomatis setiap bulan lewat cron sync_ownership.yml (tanggal 5, 13:00 WIB), tanpa input manual
Latest Free Float / public ownership ratio data/free_float_tracker.json, lalu merged ke data/skriner_data.json[*].free_float ticker, date, benchmark_ratio, source, method, evidence, pdf_attachments Resmi IDX: per-emiten Laporan Bulanan Registrasi Pemegang Efek, parser mengambil baris eksak % Saham Free Float / % Free Float Share kolom Bulan Ini / This Month; baris Masyarakat/Publik hanya fallback python scripts/scrape_free_float.py --ticker BOLT untuk murah; workflow sync_freefloat.yml manual-only, default skip all-emiten dan mempertahankan snapshot
Timestamp versi data data/update_metadata.json technical_updated, disclosures_updated, official_metadata_updated, official_metadata_rows Generated by sync scripts from run time + metadata scrape report technical_updated ditulis oleh scripts/scrape_yahoofinance.py; disclosures_updated ditulis oleh scripts/scrape_kabar_keterbukaan.py
Snapshot/cache agar CI tahan blokir IDX docs/data/*, data/ownership_*, data/idx_free_float_status.*, data/free_float_tracker.json snapshot terakhir yang valid Repo sendiri Disimpan dalam Git. Workflow memakai fallback snapshot; tidak membutuhkan laptop user.

File lama Unified_Daftar_Saham_IHSG_dan_Indeks.csv tetap ada hanya sebagai fallback sementara untuk shares dan free-float lama jika sumber resmi belum tersedia. File tersebut bukan lagi sumber utama metadata ticker dan tidak boleh menjadi syarat manual untuk menjalankan GitHub Actions. File XLSX sektoral/indeks manual lama dihapus dari repo karena seluruh metadata aktif sekarang diambil oleh scraper resmi IDX di dalam repo.


3. Sistem Scraper & Pembaruan Kepatuhan Free Float

Skriner dilengkapi dengan modul crawler otomatis resmi untuk melacak dan memverifikasi persentase free float kepatuhan bursa secara berkala langsung dari laporan Kustodian Sentral Efek Indonesia (KSEI) dan emiten tercatat (LBRE):

A. Pengambilan Latest Free Float Resmi (scripts/scrape_free_float.py)

Modul ini sekarang self-contained dan GitHub-Actionable: tidak lagi membutuhkan file XLSX lokal LQ45/KOMPAS100. Alurnya:

  • API Target: https://www.idx.co.id/primary/ListedCompany/GetAnnouncement dengan warmup ke halaman keterbukaan informasi IDX.
  • Sumber PDF: per-emiten Laporan Bulanan Registrasi Pemegang Efek terbaru, ditemukan lewat discovery client-side tanpa bergantung pada filter keyword API yang sering tidak konsisten.
  • Ekstraksi Rasio: parser membaca PDF Lapbul dengan pdfplumber dan mengambil target eksplisit dari tabel Informasi Saham Free Float: baris % Saham Free Float, kolom Bulan Ini sebagai nilai terbaru benchmark_ratio. Pencarian Masyarakat/Publik/Public hanya menjadi fallback jika format Lapbul berbeda.
  • Satu PDF untuk Governance: parser Lapbul yang sama juga mengekstrak Pengendali dari setiap baris Nama yang memiliki tanda X/checkmark pada kolom Pengendali atau Afiliasi Pengendali, termasuk tabel Direksi/Komisaris dan tabel pemegang saham 5%+. Section UBO mendukung label Pemilik Manfaat, Penerima Manfaat Akhir, atau Pemilik Manfaat Akhir, dan menyimpan Nama Pemegang Saham Langsung sebagai evidence perusahaan pengendali langsung jika kolom itu terisi.
  • Evidence: setiap output menyimpan source, method, potongan evidence, halaman PDF, dan pdf_attachments sehingga nilai free float/governance bisa ditelusuri kembali ke dokumen resmi IDX.
  • Fallback CI: jika IDX memblokir GitHub Actions dan snapshot data/free_float_tracker.json sudah ada, script exit 0 dan mempertahankan snapshot lama agar dashboard tidak kosong.

B. Hirarki Resolusi Free Float di Dashboard

Free Float dashboard sekarang IDX-only. Yahoo Finance floatShares / sharesOutstanding tidak dipakai karena definisinya berbeda dari Free Float regulatori IDX. Modul sinkronisasi (scripts/skriner_sync.py) menerapkan prioritas:

  1. Laporan LBRE/Lapbul per-emiten (data/free_float_tracker.json): prioritas utama. Jika emiten memiliki data LBRE bulanan di tracker (pada tanggal/bulan berapa pun), dashboard akan menggunakan tanggal, tautan dokumen bukti PDF, dan nilai dari LBRE tersebut.
  2. Bulk IDX Status Free Float (data/idx_free_float_status.json): jika data LBRE per-emiten tidak tersedia di tracker, dashboard akan menggunakan data dari pengumuman bulk IDX status per 31 Maret 2026.
  3. Unavailable: jika kedua sumber resmi di atas belum punya data untuk ticker tersebut, dashboard menampilkan currently not available.

Label UI pada Teknikal Box memiliki ikon peringatan (warning icon) berwarna emas di sebelah nilainya. Jika diklik, ikon ini menampilkan popup alert yang bertuliskan (berdasar Keterbukaan Informasi <tanggal_laporan>) untuk menunjukkan tanggal rilis resmi dari keterbukaan informasi/laporan bulanan (LBRE) dari emiten tersebut. Nilai Free Float di-update dari database crawling LBRE terbaru (seperti free_float_tracker.json).

C. Klasifikasi Liner Saham (Sistem Hysteresis Buffer Zone)

Sistem ini mengkategorikan ukuran dan likuiditas saham secara dinamis namun tetap stabil (anti-flicker) berdasarkan kombinasi keanggotaan indeks dan Kapitalisasi Pasar (Harga × Total Saham), sesuai logika skriner_sync.py (blok "Stock Liner Classification"):

  1. First Liner (Saham Lapis Satu): Otomatis untuk konstituen resmi indeks LQ45 atau IDX30. Saham non-indeks juga bisa naik ke First Liner murni lewat Kapitalisasi Pasar bila melewati ambang histeresis di bawah.
  2. Histeresis First ↔ Second Liner: Saham yang berstatus First Liner (dari indeks maupun kapitalisasi) hanya turun ke Second Liner jika Kapitalisasi Pasar anjlok di bawah Rp 8 Triliun. Saham Second/Third Liner naik ke First Liner begitu Kapitalisasi Pasar melewati Rp 12 Triliun.
  3. Histeresis Second ↔ Third Liner: Saham Second Liner terdegradasi ke Third Liner hanya jika Kapitalisasi Pasar anjlok di bawah Rp 800 Miliar; saham Third Liner naik ke Second Liner begitu Kapitalisasi Pasar melewati Rp 1,2 Triliun.
  4. Inisialisasi (saham tanpa riwayat liner): Kapitalisasi Pasar ≥ Rp 10 Triliun langsung First Liner, ≥ Rp 1 Triliun Second Liner, sisanya Third Liner.
  5. Mekanisme Buffer Zone ini sengaja dibuat asimetris di sekitar ambang ekuilibrium (Rp 10T dan Rp 1T) agar saham tidak bolak-balik mengubah kelas/tag-nya setiap hari akibat volatilitas harga jangka pendek.

4. Definisi Indikator Teknikal & Rumus Matematika

Semua perhitungan teknikal menggunakan data historis 2 tahun (500+ hari bursa) ke belakang untuk menjamin akurasi Moving Average jangka panjang (hingga EMA/SMA 224). Seluruh indikator dihitung mandiri (self-contained) dari data chart Yahoo Finance tanpa dependensi database eksternal.

A. Vol Pengali (Indikator Baru)

Indikator ini dirancang untuk mendeteksi lonjakan volume transaksi tidak wajar (abnormal volume surge) yang mengindikasikan partisipasi institusi besar (Smart Money). Perhitungan indikator ini kebal terhadap akhir pekan dan hari libur nasional karena hanya membandingkan hari-hari perdagangan aktif bursa (hari dengan volume $&gt; 0$):

  1. Vol Pengali 1D (vs Kemarin): Perbandingan volume transaksi hari ini ($Volume_t$) terhadap volume transaksi hari perdagangan aktif terakhir sebelum hari ini ($Volume_{\text{active_t-1}}$), mengabaikan hari libur bursa dan akhir pekan. $$\text{Vol Pengali 1D} = \frac{\text{Volume}t}{Volume{\text{active_t-1}}}$$ Interpretasi: Nilai $&gt; 2.0x$ menunjukkan volume hari ini melonjak lebih dari 2 kali lipat dibandingkan hari aktif sebelumnya (sekalipun terpisah oleh libur panjang).

  2. Vol Pengali 20D (vs Rata-rata 20 Hari Sebelumnya): Perbandingan volume transaksi hari ini ($Volume_t$) terhadap rata-rata volume transaksi selama 20 hari perdagangan aktif bursa sebelumnya (tidak termasuk hari ini, libur nasional, dan akhir pekan). $$\text{Vol Pengali 20D} = \frac{\text{Volume}t}{\frac{1}{20} \sum{i=1}^{20} Volume_{\text{active_prev_i}}}$$ Interpretasi: Mengukur kelipatan volume hari ini terhadap rata-rata partisipasi bulanan struktural emiten tersebut berdasarkan 20 hari aktif perdagangan bursa ke belakang.


B. Skor Teknikal (Skor Kuantitatif Maksimal 10.0)

Sistem penilaian teknikal yang secara otomatis memberikan poin terhadap keunggulan tren, momentum, dan volume emiten:

$$\text{Skor} = \text{Min} \left( \sum \text{Poin_EMA} + \text{Poin_RSI} + \text{Poin_MACD} + \text{Poin_VMA}, 10.0 \right)$$

  1. Poin Exponential Moving Average (Poin_EMA): Maksimal 10.0 poin.
    • Menguji 10 periode EMA harian: $\text{EMA} \in {3, 5, 10, 20, 50, 60, 100, 112, 200, 224}$.
    • Memberikan $+1.0$ poin untuk setiap garis EMA di mana harga penutupan terakhir berada di atas EMA tersebut: $$\text{Harga Terakhir} &gt; \text{EMA}_d \implies +1.0$$
  2. Momentum RSI (Poin_RSI): Maksimal 1.5 poin.
    • Sweet Spot ($50.0 \le \text{RSI} \le 70.0$): Memberikan $+1.5$ poin (momentum bullish yang kuat namun belum jenuh beli).
    • Transition Zone ($40.0 \le \text{RSI} &lt; 50.0$ atau $70.0 &lt; \text{RSI} \le 80.0$): Memberikan $+0.5$ poin.
  3. Tren MACD (Poin_MACD): Maksimal 1.0 poin.
    • Memberikan $+1.0$ poin jika Histogram MACD bernilai positif ($&gt; 0$), menandakan tren kenaikan jangka pendek yang dominan.
  4. Volume VMA20 (Poin_VMA): Jaminan $+0.5$ poin.
    • Memberikan $+0.5$ poin jika volume transaksi hari ini berada di atas Volume Moving Average 20 hari ($\text{Volume}t > \text{VMA}{20}$).

C. Sanitasi Data Saham Suspensi & Tidak Aktif (Self-Healing)

Untuk menjamin integritas data sistem, Skriner menerapkan sistem penyaringan otomatis (self-healing) terhadap saham-saham yang sedang berada dalam status suspensi bursa (seperti emiten BAPA) atau saham tidak aktif/tidur (seperti emiten AKKU).

  • Kriteria Deteksi: Jika sebuah saham terdeteksi memiliki tingkat volatilitas nol ($\text{ADR}% = 0.0%$ atau $\text{ATR}% = 0.0%$) atau tidak memiliki volume transaksi sama sekali ($\text{Volume} = 0$), saham tersebut diklasifikasikan sebagai saham tidak aktif/suspensi.
  • Pembersihan Data Konsisten: Untuk menghindari disinformasi (misal, menampilkan Skor 10.0 atau RSI 100% akibat data stagnan), sistem secara otomatis:
    • Mereset Skor Teknikal menjadi 0.0.
    • Mengosongkan status RSI dan MACD menjadi None (ditampilkan sebagai -).
    • Mengosongkan daftar ceklis Moving Averages (MA) yang aktif.
    • Mengosongkan nilai Vol Pengali (1D dan 20D) menjadi None (ditampilkan sebagai -).

D. Penanganan Hari Libur & Akhir Pekan Bursa

Perhitungan teknikal harian pada Skriner terikat secara ketat dengan Hari Perdagangan Bursa Efek Indonesia (IDX) untuk menghindari distorsi nilai rata-rata dan kehilangan data saat libur bursa:

  • Deteksi Otomatis Hari Libur Bursa Kerja (Weekday Holiday Auto-Detection): Jika sebuah hari libur nasional jatuh pada hari kerja biasa (Senin-Jumat), alur kerja GitHub Actions pada pukul 17:13 WIB tetap akan terpicu. Untuk mencegah penghapusan/pembersihan data teknikal aktif akibat volume pasar nol (0) hari itu, skrip secara pintar memeriksa volume harian emiten acuan BBCA (Bank Central Asia Tbk.) terlebih dahulu. Jika volume BBCA terdeteksi 0, sistem mengenali hari tersebut sebagai hari libur perdagangan resmi. Skrip secara otomatis membatalkan sinkronisasi Yahoo Finance hari itu, sehingga seluruh indikator teknikal, skor, dan rating aktif hari perdagangan bursa sebelumnya tetap terjaga utuh, sementara perayapan berita ringan tetap dilanjutkan.
  • Pengabaian Otomatis Akhir Pekan/Libur: Kueri riwayat bursa memuat akhiran bursa Indonesia (.JK). Pada hari Sabtu, Minggu, dan Hari Libur Nasional di mana bursa BEI tutup, data bursa tidak merekam lilin harga baru.
  • Pembersihan Entri Kosong & Pengisian Metadata: Scraper menyaring barisan data dari Yahoo Finance dan membuang baris non-perdagangan yang kosong. Jika lilin terakhir memuat volume namun harga penutupan (Close) bernilai None (biasa terjadi pada akhir sesi bursa sebelum penyelesaian data harian Yahoo), sistem secara otomatis mengambil harga dari metadata regularMarketPrice sebagai pengisi cadangan agar data lilin hari aktif tidak terbuang.
  • Komputasi Berbasis Hari Bursa Aktif (active_days): Seluruh metrik rata-rata harian (ATR 14, ADR 20, Volume 20, dan Vol Pengali 1D/20D) dihitung secara eksklusif menggunakan barisan hari perdagangan bursa aktif (volume > 0 atau lilin aktif hari ini). Hal ini membuang lilin-lilin kosong hari libur yang sesekali disisipkan Yahoo Finance, sehingga rata-rata pergerakan tidak terseret turun secara salah.

E. Indikator Teknikal Lainnya

1. Relative Strength Index (RSI - 14 Hari)

Mengukur kecepatan dan perubahan momentum pergerakan harga:

$$\text{RSI} = 100 - \left( \frac{100}{1 + \text{RS}} \right)$$

$$\text{RS} = \frac{\text{Rata-rata Eksponensial Kenaikan}}{\text{Rata-rata Eksponensial Penurunan}}$$

2. Average True Range Percent (ATR% - 14 Hari)

Mengukur tingkat volatilitas harian saham secara persentase terhadap harga saham saat ini, sehingga saham berharga Rp100 dan Rp10.000 dapat dibandingkan secara adil:

$$\text{TR}_t = \max \left( \text{High}_t - \text{Low}_t, \left| \text{High}_t - \text{Close}_{t-1} \right|, \left| \text{Low}_t - \text{Close}_{t-1} \right| \right)$$

$$\text{ATR}_{14} = \text{Simple Moving Average dari TR selama 14 hari}$$

$$\text{ATR}% = \left( \frac{\text{ATR}_{14}}{\text{Close}_{\text{hari ini}}} \right) \times 100%$$

3. Average Daily Range Percent (ADR% - 20 Hari)

Mengukur tingkat keaktifan (aktivitas intraday) murni tanpa dipengaruhi oleh celah harga buka (gaps):

$$\text{ADR}% = \frac{1}{20} \sum_{i=0}^{19} \left( \frac{\text{High}_{t-i} - \text{Low}_{t-i}}{\text{Low}_{t-i}} \right) \times 100%$$

4. Transaksi 1% (1% Daily Transaction Value)

Metrik likuiditas yang menghitung jumlah nilai transaksi Rupiah yang dibutuhkan untuk menggerakkan harga saham sebesar 1% di pasar:

$$\text{Transaksi 1% (Rp)} = \text{Close} \times 0.01 \times \text{Volume}$$

  • pct1today: Nilai transaksi 1% pada hari penutupan terakhir.
  • pct120d: Rata-rata 20 hari dari nilai transaksi 1% untuk mengukur likuiditas struktural.

4. Fitur UI Interaktif & Fitur Tersembunyi (Hidden UI)

Dashboard premium Skriner memuat komponen interaktif yang dirancang untuk menjaga kesederhanaan tampilan luar sekaligus menyajikan detail mendalam secara instan:

  1. Tooltip Sumber Data Terintegrasi: Mengarahkan kursor (hover) atau mengetuk status "Data versi" atau "Kabar versi" di header akan menampilkan rincian data satelit: status sambungan database, waktu pembaruan IDX GET API, riwayat crawler media, dan seluruh atribusi dependensi visual.
  2. Slide-Out Laci Indikator Saham: Setiap kartu emiten memiliki ikon panah detail. Ketika diketuk, kartu akan meluas ke bawah dan memunculkan status neon-green ceklis indikator EMA, SMA, dan VMA yang sedang aktif untuk emiten tersebut.
  3. Popup Modal Riwayat Kabar Efek: Jika emiten memiliki lebih dari 1 pengumuman, mengeklik tautan + Lihat x Kabar Lainnya akan memicu modal blur latar belakang (backdrop glassmorphism) berisi daftar seluruh kabar korporat harian lengkap dengan ringkasan isi pengumuman dan tautan PDF aslinya.
  4. Respon Cepat Filter Summary Bar: Setiap kali filter aktif, barisan pil filter akan meluncur di bawah kontrol utama. Pengguna dapat menghapus filter tertentu dengan mengeklik tombol silang (X) pada pil tersebut atau mereset seluruh filter sekaligus lewat tombol "Reset All".
  5. Kalkulator Lot (Money Management Simulator): Setiap kartu saham memiliki tombol "Kalkulator Lot". Jika diklik, ia akan menampilkan modal simulator kalkulator lot yang default ke Stop Loss Manual (dengan pilihan ATR sebagai alternatif). Slider persentase Stop Loss manual dapat diatur dalam kelipatan bulat 1% (bukan desimal) untuk kenyamanan perhitungan posisi lot maksimal, dana bersih (termasuk fee beli/jual), dan level target profit 1R hingga 6R.
  6. Mode Aksesibilitas Khusus (Accessibility Toggle): Melalui tombol ikon mata di header, pengguna dapat mengaktifkan Mode Aksesibilitas. Mode ini mengaktifkan style kontras tinggi dan border solid pada kartu grid saham. Secara khusus, semua garis pembatas horizontal (border) di dalam kartu grid saham secara default disembunyikan dan hanya akan muncul saat Mode Aksesibilitas ini diaktifkan.
  7. Default Tema Light Mode: Dashboard sekarang secara default di-load menggunakan Light Mode (default theme light, dark mode nonaktif secara bawaan) demi kenyamanan pembacaan retro archive ala koran warm paper. Pengguna tetap dapat mengganti ke tema gelap secara manual lewat tombol ikon lingkaran/bulan di header.
  8. Visualisasi Jaring Gurita UBO (Force Graph): Tombol "Relasi" pada bagian Kepemilikan akan membuka modal visualisasi interaktif (D3 Force Graph). Grafik ini murni berfokus pada ekosistem UBO (Ultimate Beneficial Owner), di mana ia hanya akan menarik saham-saham lain ke dalam grafik jika saham tersebut memiliki UBO yang sama (ditandai dengan ikon mahkota kuning).
  9. Logo Emiten Terintegrasi: Dashboard secara otomatis menarik dan menampilkan logo resolusi tinggi dari masing-masing emiten (bersumber dari Stockbit) di sebelah nama ticker pada Stock Card untuk mempermudah identifikasi visual dengan cepat.

5. Sistem Klasifikasi Kategori Pengumuman Emiten

A. Dasar & Sumber Acuan Framework Kategori

Sistem Skriner mengklasifikasikan setiap pengumuman keterbukaan informasi emiten ke dalam 10 Kategori Terintegrasi yang dirancang dengan menggabungkan dua pendekatan:

  1. Pendekatan Formal (Regulasi OJK/BEI): Berdasarkan klasifikasi resmi Peraturan Otoritas Jasa Keuangan (OJK) dan Peraturan Bursa Efek Indonesia (BEI), termasuk POJK No. 31/POJK.04/2015 tentang Keterbukaan Informasi Fakta Material, POJK No. 29/POJK.04/2016 tentang Laporan Keuangan Berkala, dan Peraturan Pencatatan BEI I-A serta II-A.
  2. Pendekatan Praktis (Klasifikasi Scraper): Menyesuaikan kategori formal dengan kebutuhan skrining dan penyaringan visual pada dashboard, mengeliminasi tumpang tindih (overlap) antar-kategori agar setiap pengumuman hanya masuk ke satu kategori tunggal.

Analisis lengkap mengenai resolusi tumpang tindih, sinergi antar-kategori, serta landasan hukum untuk setiap kategori didokumentasikan pada berkas riset internal studi_keterbukaan_informasi.md.

B. Daftar 10 Kategori Terintegrasi

No. Kategori Label Sistem Deskripsi Ringkas Landasan Regulasi
1 Kinerja Keuangan & Laporan Berkala Kinerja Keuangan & Laporan Berkala Laporan keuangan tahunan/kuartalan, laba/rugi bersih POJK No. 29/POJK.04/2016
2 Aksi Korporasi & Dividen Aksi Korporasi & Dividen RUPS, dividen, stock split, rights issue, waran Ketentuan RUPS OJK & Peraturan Aksi Korporasi BEI
3 Insider Activity & Buyback Insider Activity & Buyback Transaksi saham direksi/komisaris, share buyback POJK No. 11/POJK.04/2017
4 Ekspansi & Kontrak Bisnis Ekspansi & Kontrak Bisnis Tender, akuisisi, MoU, joint venture, investasi baru POJK No. 31/POJK.04/2015 (Fakta Material - Operasional)
5 Peringatan Regulasi & Suspensi Peringatan Regulasi & Suspensi Suspensi, UMA, sanksi, notasi khusus (E/L/M/X) Peraturan Perdagangan BEI II-A
6 Status Listing & Papan Pencatatan Status Listing & Papan Pencatatan IPO, delisting, perpindahan papan, registrasi pemegang efek (LBRE) Peraturan Pencatatan BEI I-A
7 Penerbitan Utang & Pembiayaan Penerbitan Utang & Pembiayaan Obligasi, sukuk, credit rating, pembayaran kupon Peraturan BEI EBUS
8 Sengketa Hukum & Kepailitan Sengketa Hukum & Kepailitan Gugatan, PKPU, pailit, investigasi hukum POJK No. 31/POJK.04/2015 (Fakta Material - Hukum)
9 Laporan Sektoral & Eksplorasi Laporan Sektoral & Eksplorasi Eksplorasi tambang/migas bulanan, DMO batubara Ketentuan Pelaporan Khusus Sektoral BEI
10 Keberlanjutan & ESG Keberlanjutan & ESG Sustainability report, CSR, emisi karbon, SRI-KEHATI POJK No. 51/POJK.03/2017

Pengumuman yang tidak cocok dengan kata kunci kategori manapun akan diklasifikasikan sebagai Lain-lain / Umum.

C. Logika Pencocokan Kata Kunci (Keyword Matching)

Klasifikasi dilakukan secara otomatis oleh fungsi classify_announcement_category(title, summary) di skriner_sync.py menggunakan metode pencocokan kata kunci (keyword matching) terhadap gabungan teks judul dan ringkasan pengumuman:

# Contoh: Kategori "Aksi Korporasi & Dividen" cocok jika teks mengandung salah satu kata kunci:
keywords = ["dividen", "rups", "rupslb", "aksi korporasi", "stock split",
            "right issue", "rights issue", "saham bonus", "waran", "mesop", "esop"]

Urutan Prioritas Pencocokan: Kategori dievaluasi secara berurutan (1-10) dengan short-circuit—pengumuman yang cocok pada kategori lebih awal tidak akan dievaluasi ulang untuk kategori berikutnya. Kategori Keberlanjutan & ESG sengaja dievaluasi paling awal untuk menghindari false positive terhadap kata kunci yang sering muncul di kategori lain (misal, "lingkungan" yang bisa bermakna "lingkungan bisnis").

Penanganan Khusus: Pengumuman yang mengandung kata "registrasi pemegang" pada aturan Insider Activity secara eksplisit dialihkan ke kategori Status Listing & Papan Pencatatan, karena laporan "registrasi pemegang efek" (LBRE) bersifat kepatuhan regulasi pencatatan, bukan transaksi orang dalam.


6. Visualisasi Volatilitas ATR/ADR & Klasifikasi Label

A. Konsep Dasar & Studi Perancangan

Widget visualisasi volatilitas (Price Volatility Range Bar) pada setiap kartu emiten dirancang berdasarkan studi teknis mendalam tentang relasi fungsional antara Average True Range (ATR%) dan Average Daily Range (ADR%). Studi lengkap meliputi pemodelan matematika, perbandingan karakteristik, konsep Gap Risk, dan implementasi fraksi harga BEI didokumentasikan pada berkas riset internal studi_atr_adr.md.

Perbedaan Fundamental:

  • ATR% (14 hari) — mengukur volatilitas total termasuk gap pembukaan pasar (celah harga antara penutupan kemarin dan pembukaan hari ini). Sensitif terhadap berita global overnight.
  • ADR% (20 hari) — mengukur rentang pergerakan intraday murni (high - low) tanpa memperhitungkan gap. Mengukur aktivitas jam perdagangan aktif.
  • Gap Risk = ATR% − ADR% — selisih keduanya mengukur risiko celah harga pembukaan.

B. Ambang Batas Klasifikasi Volatilitas

Sistem Skriner mengklasifikasikan volatilitas saham menjadi tiga tingkat berdasarkan nilai ATR% dengan ambang batas berikut:

Label Visual Rentang ATR% Warna Justifikasi
Rendah < 2.0% 🟢 Hijau (--color-accent-green) Saham blue chip berkapitalisasi besar dengan pergerakan harga stabil dan terprediksi. Cocok untuk investor konservatif. Contoh tipikal: BBCA (~1.8%), BBRI (~1.9%).
Sedang 2.0% – 5.0% 🟡 Emas (--color-accent-gold) Mayoritas saham lapis kedua dan menengah. Menawarkan keseimbangan antara potensi keuntungan dan risiko yang terkelola.
Tinggi > 5.0% 🔴 Merah (--color-accent-red) Saham bervolatilitas ekstrem—sering kali saham lapis ketiga, saham spekulatif, atau emiten dengan kapitalisasi kecil. Memerlukan manajemen risiko ketat. Contoh tipikal: GOTO (~6.5%).

Alasan Pemilihan Ambang Batas:

  • 2.0% sebagai batas bawah "Sedang" dipilih karena saham-saham indeks acuan utama Indonesia (LQ45, KOMPAS100) umumnya memiliki ATR% di bawah 2%, menjadikannya tolok ukur pasar yang stabil.
  • 5.0% sebagai batas bawah "Tinggi" dipilih karena saham dengan pergerakan harian rata-rata lebih dari 5% dari harga penutupan menunjukkan fluktuasi yang signifikan secara statistik—potensi pergerakan Rp500 per Rp10.000 saham per hari, yang mengindikasikan risiko tinggi bagi investor ritel.

C. Struktur Visual Widget (Price Volatility Range Bar)

Widget ditampilkan langsung di bawah informasi harga pada setiap kartu emiten dengan struktur horizontal:

[ Price - ATR ] <===( [ Price - ADR ] <=== [ Price ] ===> [ Price + ADR ] )====> [ Price + ATR ]
  |<--- ATR- --->|      |<--- ADR- --->|   (Tengah)    |<--- ADR+ --->|      |<--- ATR+ --->|
  1. Pita Luar Merah (ATR Band): Rentang volatilitas total—batas ekstrem pergerakan harga harian.
  2. Pita Dalam Cyan (ADR Band): Rentang intraday normal—area pergerakan harga aktif jam bursa.
  3. Pin Titik Tengah: Posisi harga penutupan terakhir sebagai jangkar visual.

Semua harga proyeksi nominal Rupiah di ujung pita dibulatkan secara otomatis menggunakan fungsi roundToIdxFraction() sesuai Fraksi Harga Resmi BEI (tick size: Rp1/2/5/10/25 tergantung rentang harga), sehingga angka yang ditampilkan selalu merupakan harga yang sah untuk diinput sebagai order beli/jual di sistem perdagangan bursa.

D. Penanganan Saham Suspensi/Tidak Aktif

Jika sebuah saham tidak memiliki data ATR% atau ADR% yang valid (bernilai 0, null, atau saham dalam status suspensi), widget menampilkan status abu-abu bertuliskan "Suspensi/Stagnan" dengan opacity rendah dan label "Data tidak tersedia", mencegah pengguna membuat keputusan trading berdasarkan data volatilitas yang tidak representatif.


7. Jadwal Eksekusi Otomatisasi GitHub Actions (CI/CD)

Untuk menjaga kesegaran data tanpa memerlukan server VPS berbayar, sistem ini menggunakan GitHub Actions untuk menjalankan pipa pembaruan secara otomatis. Eksekusi dibagi menjadi 6 workflow terpisah yang masing-masing dapat dipicu manual via workflow_dispatch:

A. Workflow 1: Sinkronisasi Teknikal (sync_technical.yml)

  • Jadwal Cron: Tidak adaworkflow_dispatch ONLY, dipicu oleh Apple Shortcut di iPhone owner (~17:15 WIB). Tidak ada cron GitHub Actions sama sekali untuk workflow ini.
  • Mode: Teknikal (Yahoo Finance 2Y Chart + Indikator), tanpa refresh Kabar/Keterbukaan
  • Perintah: python scraper/fetch_metadata.py → publish data/ownership_ihsg_tags.*python scripts/scrape_yahoofinance.py
  • Fungsi: Dipicu sesaat setelah bursa BEI ditutup, memperbarui katalog metadata resmi IDX terlebih dahulu, lalu menghitung seluruh indikator teknikal (RSI, MACD, 27 MA booleans, ATR%, ADR%, Vol Pengali, avgValue20) dari data chart 2 tahun Yahoo Finance. Pada hari libur bursa/volume BBCA 0, indikator lama dipreservasi. Jika iPhone owner berhenti memicu shortcut ini, teknikal berhenti diperbarui tanpa peringatan di status workflow.

B. Workflow 2: Berita & Keterbukaan Informasi (sync_news.yml)

  • Jadwal Cron: Tidak adaworkflow_dispatch ONLY, dipicu oleh Apple Shortcut di iPhone owner setiap jam (24/7 termasuk weekend/libur). Tidak ada cron GitHub Actions.
  • Mode: Ringan (Hanya Berita & Kabar, tanpa Yahoo Finance)
  • Perintah: python scripts/scrape_kabar_keterbukaan.py
  • Fungsi: Memperbarui pengumuman Keterbukaan Informasi IDX dan artikel portal berita utama. Seluruh indikator teknikal dari sinkronisasi terakhir dipreservasi utuh.

C. Workflow 3: Free Float (sync_freefloat.yml)

  • Jadwal Cron: 21 18 * * 0 (Mingguan, Minggu 18:21 UTC / Senin 01:21 WIB), plus manual via workflow_dispatch dengan input ticker, limit, dan refresh_technical.
  • Mode: Quota-safe. Cron mingguan otomatis hanya menjalankan scripts/parse_idx_freefloat_status_pdf.py (bulk IDX status PDF) lalu republish metadata; scrape Lapbul per-emiten (scripts/scrape_free_float.py --ticker/--limit) hanya berjalan saat dispatch manual mengisi input tersebut — tidak ada all-emiten scrape otomatis.
  • Perintah murah: python scripts/parse_idx_freefloat_status_pdf.py → (dispatch only) python scripts/scrape_free_float.py --ticker BOLTpython scraper/fetch_metadata.py → publish data/ownership_ihsg_tags.*. refresh_technical=true hanya dipakai jika ingin lanjut menjalankan Yahoo technical sync.
  • Fungsi: Memperbarui free-float resmi dari bulk status IDX setiap minggu tanpa menjalankan crawl ratusan PDF Lapbul secara otomatis. Refresh Lapbul per-ticker hanya dilakukan manual saat benar-benar dibutuhkan.

D. Workflow 4: Kepemilikan Resmi IDX/KSEI (sync_ownership.yml)

  • Jadwal Cron: 0 6 5 * * (Bulanan, tanggal 5 pukul 06:00 UTC / 13:00 WIB), plus manual via workflow_dispatch — dispatch ini tidak memiliki input apa pun (tidak ada opsi untuk memilih ticker atau membatasi scope governance).
  • Mode: Full ownership + governance refresh setiap bulan — tidak bergantung pada repo lain. Setiap run (cron maupun manual) menjalankan fetch_1pct.py (±25 menit) lalu fetch_lapbul_full.py all-emiten penuh (±120 menit) tanpa opsi skip.
  • Perintah: python scraper/fetch_1pct.pypython scraper/fetch_lapbul_full.py (full, semua emiten) → copy_if_exists ke data/ownership_*.
  • Fungsi: Mengambil dokumen resmi Pemegang Saham di atas 1% sebagai tabel kepemilikan utama dan menambahkan governance dari Lapbul (PG, UBO, direksi/komisaris) untuk seluruh emiten setiap bulan. Metadata/ISSI sengaja dikelola oleh workflow metadata/technical/freefloat agar update ISSI tidak tertimpa oleh refresh ownership bulanan.
  • Output scraper native: docs/data/latest.json, docs/data/latest.csv, docs/data/latest_pengendali.csv, docs/data/latest_ubo.csv, docs/data/summary.json, docs/data/summary_1pct.json, docs/data/summary_lapbul.json.
  • Output dashboard: workflow memublikasikan file tersebut ke data/ownership_*, yang kemudian dimuat langsung oleh Next.js client di browser.
  • Resiliensi CI: karena IP GitHub Actions kadang diblokir IDX/Cloudflare, snapshot docs/data/ dan data/ownership_* disimpan di repo. Jika scrape gagal tetapi snapshot lama tersedia, workflow dapat mempertahankan data terakhir alih-alih membuat dashboard kosong. Job timeout 150 menit.

E. Workflow 5: Metadata Resmi IDX (sync_metadata.yml)

  • Jadwal Cron: 11 18 * * 0 (Mingguan, Minggu 18:11 UTC / Senin 01:11 WIB), plus manual via workflow_dispatch dan trigger push pada path terkait (fetch_metadata.py, ihsg_tags/**, requirements.txt, file workflow itu sendiri).
  • Mode: Metadata-only refresh untuk katalog emiten resmi.
  • Perintah: python scraper/fetch_metadata.py → publish docs/data/ihsg_tags.* dan data/ownership_ihsg_tags.*.
  • Fungsi: Menjaga name, sector, papan, ipo_date, ISSI, LQ45, dan KOMPAS100 tetap mengikuti sumber resmi IDX/DES/index tanpa mengandalkan CSV/XLSX statis.

F. Workflow 6: Sinkronisasi Laporan Bulanan (Lapbul) & Free Float Harian (sync_daily_lapbul.yml)

  • Jadwal Cron: 30 11 * * * (Harian, pukul 18:30 WIB / 11:30 UTC)
  • Mode: Incremental daily scrape (past 14 hari)
  • Perintah: python scraper/fetch_lapbul_full.py --days 14python scripts/scrape_free_float.py --days 14python scripts/skriner_sync.py --skip-yfinance --skip-disclosures
  • Fungsi: Memindai keterbukaan informasi LBRE dalam 14 hari terakhir untuk mengekstrak data Free Float dan kepemilikan/governance (PG/pengendali, UBO/penerima manfaat akhir). Melakukan penggabungan kumulatif pada database CSV/JSON di repositori dan mempublikasikannya secara otomatis.
  • ⚠️ Isu diketahui (belum selesai, sejak 14 Juni 2026): scraping LBRE/Lapbul workflow ini berhenti menghasilkan commit baru. Hipotesis utama: sync_daily_lapbul.yml tidak memiliki langkah instalasi Playwright Chromium (berbeda dari sync_news.yml), sehingga fallback headless browser saat IDX memblokir discovery gagal senyap dan guardrail snapshot exit 0 tanpa data baru. Detail investigasi dan tindakan pemilik yang diperlukan ada di BUGS_AND_FIXES_2026-07-12.md.

G. Workflow 7: Sinkronisasi Utama Skriner Harian (data_sync.yml)

  • Jadwal Cron: 0 1,5,10 * * * (Harian, pukul 08:00, 12:00, dan 17:00 WIB)
  • Mode: Full Skriner Data Update (Technical Indicators, Disclosures, News, IHSG, and Sector Performance Indices)
  • Perintah: python scripts/skriner_sync.py
  • Fungsi: Alur kerja pembaruan utama bursa harian yang menyinkronkan seluruh database skriner. Ini menghitung indikator teknikal dari Yahoo Finance (jika market open), mengumpulkan keterbukaan informasi IDX serta portal berita, mengambil data chart IHSG beserta nilai transaksi harian resmi (Nilai Transaksi) dari API IDX, memperbarui data sektoral, menyalin data ke folder Next.js, dan melakukan komit/dorong ke repositori secara otomatis (dengan izin contents: write) untuk memicu build Vercel secara mandiri di cloud.

H. Proteksi Git History & Vercel (Smart Commit Guard)

Setiap workflow dilengkapi dengan perlindungan penyerahan berkas otomatis:

  • Perintah eksekusi memeriksa perubahan database lokal menggunakan git diff --cached --quiet sebelum membuat komit baru.
  • Hasil: Komit ke repositori hanya dikirim jika ada perubahan data aktual. Selama periode sepi, alur kerja selesai tanpa komit sampah, menjaga histori repositori bersih dan meminimalkan rebuild Vercel.

8. Sumber Data & Atribusi Resmi

Seluruh modul pengambilan data backend scraper Skriner dirancang menggunakan koneksi aman ke sumber-sumber tepercaya berikut untuk memastikan integritas data bursa efek Indonesia:

A. Data Free Float — Sumber & Hirarki Resolusi

Data persentase free float (saham yang beredar dan dimiliki publik) merupakan metrik kepatuhan penting yang diawasi oleh Bursa Efek Indonesia. Skriner mengambil data ini dari sumber resmi IDX dengan hirarki prioritas:

Prioritas Sumber Data Keterangan
1 (Utama) Laporan Bulanan Registrasi Pemegang Efek (LBRE/Lapbul)data/free_float_tracker.json Data per-emiten yang diekstrak menggunakan parser PDF dari keterbukaan informasi bulanan. Jika tersedia pada tanggal/bulan berapa pun, data ini langsung digunakan sebagai sumber utama.
2 (Fallback) Bulk IDX Status Free Floatdata/idx_free_float_status.json Laporan snapshot bulk resmi dari pengumuman IDX “Status Pemenuhan Kewajiban Jumlah Saham Free Float dan Jumlah Pemegang Saham”. Digunakan sebagai fallback jika data LBRE untuk emiten terkait belum tersedia di tracker (default merujuk ke pengumuman bulk status per 31 Maret 2026).

API Sumber LBRE:

  • Endpoint: https://www.idx.co.id/primary/ListedCompany/GetAnnouncement
  • Metode Discovery: warmup ke halaman keterbukaan informasi IDX, ambil halaman pengumuman tanpa keyword server-side, lalu filter client-side untuk Laporan Bulanan Registrasi Pemegang Efek agar tidak kehilangan laporan akibat filter API yang tidak konsisten.
  • Ekstraksi Free Float: tidak membutuhkan Excel indeks. Nilai diambil dari PDF resmi per-emiten dengan pdfplumber dan disimpan bersama evidence (method, evidence, page, pdf_attachments).

B. Data Teknikal & Harga (Self-Contained Engine)

  • Data Historis Transaksi & Lilin Harga: Disediakan oleh Yahoo Finance API dengan kode akhiran bursa Jakarta (.JK), rentang data 2 tahun (range=2y), timeout 10 detik.
  • Mesin Indikator Mandiri: Seluruh indikator teknikal (RSI, MACD, EMA/SMA/VMA booleans, ATR%, ADR%, Vol Pengali, avgValue20, shortEmaNearestDistPct, pullbackBreakoutSignal) dihitung langsung dari data chart Yahoo Finance tanpa dependensi database eksternal.
    • Database Indikator Pra-Komputasi: Dependensi screenerzero telah dihapus sepenuhnya sejak 31 Mei 2026.

C. Keterbukaan Informasi & Pengumuman Emiten

  • Sumber Resmi: Diperoleh langsung dari Bursa Efek Indonesia (IDX).
  • Arsitektur WAF-Bypass (Anti-Blokir Cloudflare): Untuk memastikan perayapan stabil di lingkungan datacenter seperti GitHub Actions, scraper dilengkapi dengan strategi bypass multi-layer:
    1. Rotasi TLS Fingerprint (curl_cffi): Memutar identitas impersonasi browser (chrome124, safari17_0, chrome120) secara dinamis sekaligus menghapus header statis yang berkonflik agar anomali JA3 tidak terdeteksi oleh Cloudflare.
    2. Playwright Headless Fallback: Jika curl_cffi menerima 3 kali respons 403 Forbidden akibat JavaScript Turnstile Challenge, scraper akan menyalakan peramban Chromium nirkepala lengkap dengan playwright-stealth. Peramban ini akan mengunjungi beranda IDX untuk menyelesikan tantangan Cloudflare secara otomatis, lalu mengekstrak data JSON langsung dari DOM halaman. Integrasi ini berjalan mulus dan sepenuhnya self-contained pada pelari GitHub.

D. Kepemilikan Saham, Pengendali, UBO, dan Metadata Emiten

  • Sumber resmi utama kepemilikan: Dokumen KSEI via IDX "Pemegang Saham di atas 1%", diekstrak oleh scraper/fetch_1pct.py ke docs/data/latest.* lalu dipublikasikan sebagai data/ownership_latest.*.
  • Sumber governance: Laporan Bulanan Registrasi Pemegang Efek per emiten, diekstrak oleh scraper/fetch_lapbul_full.py untuk menandai PG/pengendali dan UBO/pemilik manfaat akhir.
  • Sumber metadata resmi: endpoint/download IDX/DES/index konstituen melalui scraper/fetch_metadata.py, disimpan sebagai docs/data/ihsg_tags.* dan dipublikasikan ke data/ownership_ihsg_tags.*. Snapshot ini menjadi katalog utama scripts/skriner_sync.py; CSV statis hanya fallback/supplement.
  • Catatan kualitas: data kepemilikan >1% tetap dipisahkan dari data/skriner_data.json; dashboard menggabungkan layer ini di browser berdasarkan kode ticker.

Temuan retrain scraper 1% — 02 Juni 2026 11:50:22:

Pada update KSEI terbaru, halaman keterbukaan informasi IDX untuk keyword semua emiten menampilkan dua headline yang sangat mirip pada hari yang sama:

Waktu IDX Headline Attachment data Status
02 Juni 2026 14:51:29 Pemegang Saham di atas 5% (KSEI) [Semua Emiten Saham ] 20260602_Semua Emiten Saham_Pengumuman Bursa_32096123_lamp1.pdf Jangan dipakai untuk dashboard ownership utama
02 Juni 2026 11:50:22 Pemegang Saham di atas 1% (KSEI) [Semua Emiten Saham ] 20260602_Semua Emiten Saham_Pengumuman Bursa_32096035_lamp1.pdf Sumber benar untuk ownership_latest.*

Perbaikan scraper/fetch_1pct.py dibuat agar tidak lagi memilih hasil pertama/terbaru secara buta. Jalur discovery sekarang memakai keyword website-style semua emiten, lalu memvalidasi JudulPengumuman secara client-side: harus cocok Pemegang Saham di atas 1% (KSEI) dan eksplisit menolak Pemegang Saham di atas 5% (KSEI). Fallback no-keyword tetap ada, tetapi tidak boleh menjadi satu-satunya jalur karena pada Juni 2026 response no-keyword bisa menemukan bulk 5% namun melewatkan bulk 1%.

PDF lampiran Juni 2026 juga berubah format: pdfplumber.extract_tables() mengembalikan 0 tabel pada file 33 halaman tersebut. Scraper kini memiliki fallback berbasis extract_words() dan posisi kolom tetap untuk membaca text layer yang token awalnya tergabung, misalnya 29-May-2026ALTO. Verifikasi lokal atas lampiran 32096035_lamp1.pdf menghasilkan 7.160 baris, 956 ticker, 5.167 investor, dengan data_date snapshot 20260602 dan tanggal data isi PDF 29-May-2026.

E. Portal Berita & Kabar Pasar Modal Terkini


9. Cara Menjalankan Secara Lokal

Anda dapat mengkloning proyek ini dan menjalankannya secara lokal di komputer Anda:

  1. Instalasi Dependensi: Pastikan Python $\ge 3.9$ telah terinstal, lalu pasang pustaka pendukung:
    pip install -r requirements.txt
  2. Sinkronisasi Data Free Float (LBRE):
    # Murah/aman: satu ticker
    python scripts/scrape_free_float.py --ticker BOLT
    
    # Full all-emiten hanya jalankan lokal/manual saat benar-benar perlu
    python scripts/scrape_free_float.py
  3. Sinkronisasi Kepemilikan Resmi IDX/KSEI:
    python scraper/fetch_1pct.py
    
    # Murah/aman: governance satu ticker
    python scraper/fetch_lapbul_full.py --ticker BOLT
    
    # Full all-emiten governance hanya jalankan lokal/manual saat benar-benar perlu
    python scraper/fetch_lapbul_full.py
    Hasil native scraper tersimpan di docs/data/; dashboard memakai salinan data/ownership_* yang dipublikasikan oleh workflow sync_ownership.yml. Untuk menjalankan lokal manual setelah scraper, salin file docs/data/latest*, latest_pengendali.csv, latest_ubo.csv, dan summary ownership ke nama data/ownership_* sesuai workflow. Metadata/ISSI dijalankan terpisah melalui python scraper/fetch_metadata.py atau workflow metadata.
  4. Sinkronisasi Database Penuh (Yahoo Finance + Berita — Default):
    python scripts/skriner_sync.py
  5. Sinkronisasi Ringan (Hanya Berita, Tanpa Yahoo Finance):
    python scripts/skriner_sync.py --skip-yfinance
  6. Menjalankan Server Web Lokal:
    python -m http.server 8799 --bind 127.0.0.1
    Buka penjelajah web Anda di alamat http://127.0.0.1:8799/index.html.

10. Panduan Pengembang untuk AI Model Importer

Jika Anda ingin mem-porting kode ini ke kerangka kerja modern lainnya (misalnya React, Svelte, Next.js, atau Nuxt.js) menggunakan model AI lain:

  • Logika Pencarian: Harap pertahankan logika pencarian multi-ticker yang memisahkan spasi agar pengguna dapat mencari beberapa kode emiten sekaligus (contoh: GOTO BBCA BBNI).
  • Relasi Filter: Filter dropdown Indeks bersifat saling eksklusif (exclusive), Sektor dan Papan bersifat kumulatif (cumulative), sedangkan Moving Averages bersifat AND (semua MA yang dicentang harus terpenuhi). Filter Transaksi 1% 1D bersifat OR (mencocokkan rentang apa saja yang dipilih).
  • Desain Glassmorphism: Gunakan kombinasi warna HSL semi-transparan dengan tingkat keburaman latar belakang (backdrop-filter: blur(12px)) untuk mempertahankan estetika premium. Pada layar ponsel $\le 768\text{px}$, pastikan pembungkus filter dropdown diubah menjadi flex-direction: column agar bertumpuk rapi ke bawah.

11. Zona Waktu & Proteksi Kode Sumber

A. Penegakan Zona Waktu Jakarta (WIB)

Seluruh tampilan tanggal dan waktu di situs Skriner selalu mengacu ke zona waktu Asia/Jakarta (WIB, UTC+7), terlepas dari zona waktu peramban pengunjung. Implementasi menggunakan Intl.DateTimeFormat dengan parameter timeZone: 'Asia/Jakarta' yang didukung oleh seluruh peramban modern.

Format tampilan standar: dd MMM yyyy HH.mm WIB (contoh: 01 Jun 2026 17.00 WIB)

  • formatDateTimeWIB(): Menggunakan getJakartaParts() yang memanfaatkan Intl.DateTimeFormat untuk mengekstrak komponen tanggal secara eksplisit dalam zona waktu Jakarta.
  • formatListingDate(): Tanggal pencatatan emiten yang di-parse melalui objek Date juga dikonversi ke zona waktu Jakarta sebelum diformat.
  • Logika Fallback Timestamp: Pengecekan jam teknikal (apakah sudah melewati jam 17.00 WIB) menggunakan komponen jam Jakarta, bukan jam lokal peramban.

B. Proteksi & Optimasi Kode Sumber

Untuk mengamankan dan mengoptimalkan pengiriman kode ke peramban pengguna, Skriner memanfaatkan fitur bawaan Next.js:

  1. Minifikasi & Optimasi Kode Otomatis: Next.js (menggunakan SWC/Turbopack) secara otomatis melakukan minifikasi, pemecahan bundel (code splitting), dan pembersihan kode mati (dead-code elimination) saat proses npm run build dijalankan. Hal ini menghasilkan berkas chunk JS yang sulit direkayasa balik secara kasual.
  2. Penerapan di Vercel: Proses kompilasi dijalankan langsung di server Vercel, memastikan bahwa repositori GitHub tetap aman dan hanya kode teroptimasi yang dipublikasikan ke publik.
  3. Strategi Repositori Privat + Hosting Publik: Repositori GitHub dapat tetap private, sedangkan Vercel hanya menyajikan aset terkompilasi statis yang dihasilkan oleh Next.js.

Catatan: Proteksi pada sisi pengguna bersifat pencegahan (deterrent). Pengguna teknis yang sangat termotivasi tetap berpotensi merekayasa balik kode obfuskasi, namun lapisan perlindungan ini secara efektif mencegah replikasi kasual tanpa mengorbankan pengalaman pengguna dashboard.


12. Repositori GitHub Pendukung & Inspirasi Kode

Skriner dikembangkan dengan memanfaatkan kontribusi kode dan terinspirasi dari proyek sumber terbuka (open source) utama berikut:

  • jiprastyo/screenerzero:
    • Peran: Proyek inspirasi dasar dan referensi formula teknikal awal. Dependensi data teknikal aktif telah dihapus sepenuhnya sejak 31 Mei 2026. Seluruh indikator kini dihitung mandiri oleh mesin kalkulasi self-contained di skriner_sync.py menggunakan data chart 2 tahun Yahoo Finance.
  • jiprastyo/skriner:
    • Peran: Repositori aktif untuk website Skriner Berita & Teknikal 1D. Proyek ini memperkenalkan mesin indikator teknikal mandiri penuh (RSI, MACD, 27 MA booleans), antarmuka visual glassmorphism SPA, filter multi-dimensi, metrik Vol Pengali kebal hari libur, rangkuman korporat bertenaga Gemini AI, dan 4 workflow GitHub Actions terpisah.
  • Scraper ownership resmi IDX/KSEI (scraper/):
    • Peran: Modul kepemilikan yang kini sudah menjadi bagian self-contained dari repo ini. Modul ini membawa tabel pemegang saham >1%, tag pengendali (PG), pemilik manfaat akhir (UBO), dan metadata resmi IDX/DES/index ke dashboard utama melalui layer data/ownership_*.

Dokumentasi Sistem Terverifikasi dan Diperbarui secara Resmi pada: 12 Juli 2026

13. Architecture Fallbacks & Anti-Scraping Guardrails

Mengingat agresivitas proteksi WAF (Web Application Firewall) seperti Cloudflare pada website IDX yang sering memblokir IP Datacenter (seperti GitHub Actions), arsitektur pengambilan data (scraping) repositori ini dirancang dengan beberapa lapis fallback dan guardrail ketat:

A. Scraping Bertingkat (Multi-Layer Bypass)

  1. Layer 1: TLS Impersonation (curl_cffi) Scraper utama menggunakan paket curl_cffi untuk memalsukan TLS fingerprint browser asli (Chrome/Safari) sehingga anomali JA3 tidak terdeteksi oleh Cloudflare.
  2. Layer 2: Playwright Headless Fallback Jika metode curl_cffi tetap menerima 3 kali respons 403 Forbidden (akibat tantangan JavaScript Turnstile), scraper akan secara otomatis menyalakan headless browser Chromium yang diinjeksi dengan modul playwright-stealth. Browser ini akan memuat halaman beranda IDX untuk mengeksekusi tantangan JS Cloudflare, lalu mengekstrak muatan JSON langsung dari DOM (Document Object Model).

B. Guardrail Snapshot (Data Persistence)

Untuk mencegah hancurnya data live di dashboard saat seluruh scraper diblokir (atau API IDX sedang down), kami menerapkan guardrail ketat:

  • Jika scraper mengembalikan data kosong atau gagal total, skrip akan langsung berhenti (exit 0) sebelum menyentuh file JSON output.
  • Skrip tidak akan pernah menimpa data/*.json dengan data kosong. Ini memastikan bahwa situs web (Vercel/GitHub Pages) akan terus menyajikan snapshot data terakhir yang ditarik, bukannya layar kosong.

C. Decoupled Data CDN & Next.js Edge Proxy API (Zero iPhone Touch & 0 Vercel Deploy)

Sebagai solusi optimalisasi mutlak kuota Vercel Free Tier (100 deploy/hari) sekaligus mengatasi kendala akses HTTP 404 pada repositori Private GitHub, repositori ini mengimplementasikan arsitektur Decoupled Data CDN via Next.js Edge Proxy API (Opsi C):

  • 1. Optimalisasi Kuota Vercel (Hemat 100% - Zero Automated News Rebuilds)
    • Seluruh komit otomatis dari bot GitHub Actions (sync_news.yml, data_sync.yml, sync_daily_lapbul.yml, dll.) maupun Apple Shortcuts iPhone disuntik tag senyap [skip ci].
    • Konfigurasi vercel.json dilengkapi regex matching: "ignoreCommand": "git log -1 --pretty=%B | grep -E -i '\\[skip ci|auto-sync|automated data sync|upload raw idx data'". Begitu terdeteksi komit sinkronisasi data otomatis, Vercel membatalkan proses re-build (Exit Code 0), menghemat kuota build frontend agar hanya berjalan saat ada perubahan kode sumber aplikasi.
  • 2. Real-Time 5-Minute Delivery via Next.js Edge Proxy (/api/cdn/[filename])
    • Karena repositori GitHub bersifat Private (tautan raw.githubusercontent.com publik menghasilkan 404), aplikasi frontend memuat seluruh aset JSON (skriner_data.json, market_news.json, dll.) melalui serverless proxy endpoint /api/cdn/[filename].
    • Endpoint proxy ini secara aman mengambil data langsung dari GitHub main branch menggunakan Personal Access Token (GITHUB_CDN_TOKEN) yang disimpan di Environment Variables Vercel.
    • Vercel Edge Caching: Proxy menyematkan header Cache-Control: public, s-maxage=300, stale-while-revalidate=60 sehingga data di-cache di jaringan Edge Vercel selama 5 menit. Pembaca menerima keterbukaan informasi instan tanpa menunggu siklus build CI/CD 1 jam ataupun menguras batas rate limit API GitHub.
    • Hybrid Fallback Protection: Jika API eksternal mengalami gangguan, hook (useStocksData.ts) otomatis mundur mengambil aset cadangan lokal di /data/....
  • 3. Enterprise Handshake Relay (Apple Shortcuts 100% Untouched)
    • Pengguna tidak perlu merubah alur kerja Apple Shortcuts di iPhone sama sekali (Mutlak Zero iPhone Touch):
      • Shortcut 1 (Pukul xx.55 WIB): Scrape keterbukaan informasi lokal dari iPhone lalu push raw_idx.json dengan [skip ci].
      • Shortcut 2 (Pukul xx.02 WIB): Memicu sync_news.yml di GitHub untuk merayapi 9 portal berita finansial dan mem-push komit ber-tag [skip ci]. Data langsung dapat diakses lewat /api/cdn.
      • Shortcut 3 (Pukul 17:15 WIB): Memicu sync_technical.yml pasca bursa tutup untuk memperbarui data gabungan Yahoo Finance + IDX: chart YFinance (^JKSE), teknikal ticker, histori sektoral, serta komponen IHSG resmi IDX (Nilai Transaksi dan perubahan IHSG bila ringkasan IDX untuk tanggal terbaru sudah tersedia). Komit akhir bot ini memicu tepat 1x build resmi harian Vercel sebagai jaring pengaman cadangan.
      • Shortcut 4 (Pukul ~17:25 WIB): Relay IDX-only IHSG rescue. Shortcut membaca update_metadata.json; bila ihsg_transaction_sync_ok=false, iPhone mengambil GetIndexSummary IDX untuk tanggal gap, mengunggah data/raw_idx_ihsg_summary.json, lalu memicu workflow sync_idx_ihsg_rescue.yml. Rescue ini tidak menjalankan Yahoo lagi — ia hanya menutup gap Nilai Transaksi dari iPhone (IP Indonesia → Cloudflare IDX lolos).
    • 📖 Panduan setup lengkap: docs/apple-shortcuts-setup.md — step-by-step untuk membuat semua 4 Shortcuts di iPhone.
    • ⚠️ Windows Task Scheduler (skriner_scheduler.py) sudah deprecated. Semua trigger sekarang via Apple Shortcuts → GitHub Actions. File run_yfinance.bat dan run_news_hourly.bat hanya tersisa sebagai referensi.

D. Cumulative History Sync (Sector Indexes Fallback)

Yahoo Finance tidak menyimpan grafik riwayat harian untuk indeks sektoral BEI (IDXBASIC.JK, IDXCYCLIC.JK, dll.) melainkan hanya data 1 hari/5 hari terbaru. Agar visualisasi diagram performa sektor di frontend tetap dapat menampilkan histori pergerakan jangka panjang, skrip sinkronisasi backend menerapkan Cumulative History Sync:

  • Skrip memuat file data/sectors_history.json yang sudah ada di repositori sebelum melakukan fetch data baru.
  • Setelah data harga sektor hari ini ditarik, skrip membandingkan tanggal terakhir. Jika terdeteksi hari perdagangan baru, harga hari ini akan di-append ke dalam array grafik histori (maksimal 40 hari).
  • Jika dijalankan beberapa kali pada hari yang sama, skrip hanya memperbarui harga penutupan hari ini di elemen terakhir array untuk menghindari duplikasi data.

E. Hybrid IHSG Chart & Volume Derivation (Frontend Hook Sync)

Untuk menjamin akurasi dan kesegaran data pada kartu IHSG komposit serta persentase perubahan IHSG (ihsgChange) di setiap kartu emiten, frontend (useStocksData.ts) menerapkan arsitektur penggabungan hibrida (hybrid derivation):

  • Komposit & Perubahan Harian (ihsg_chart.json): Harga penutupan harian dan persentase perubahan komposit ditarik dari Yahoo Finance (^JKSE) saat alur kerja Apple Shortcuts --only-yfinance dijalankan (17:15 WIB). Ini memastikan header kartu IHSG dan tag perubahan bursa di kartu saham selalu sinkron dengan tab Kinerja Sektor.
  • Bar Volume Nilai Transaksi Aktual (ihsg_transaction_history.json): Karena Yahoo Finance hanya menyediakan volume lembar saham (tidak mencerminkan nilai transaksi Triliun Rupiah), batang volume ditarik langsung dari API resmi BEI (Ringkasan Perdagangan / GetIndexSummary) dan digabungkan secara dinamis berdasarkan pencocokan tanggal.

Note on Continuous Documentation: README ini dan repositori dokumentasi akan selalu diperbarui secara otomatis setiap kali ada penemuan metode scraping baru, guardrail yang berhasil/gagal, maupun perubahan flow arsitektur (seperti arsitektur Cumulative History Sync atau iterasi Apple Shortcut). Dokumentasi bersifat living document.

About

Resources

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors