OHLC.dev editorialIDX

IDX Corporate Action Monitor Hari Ini and Warrant Calendar Dashboard

This project builds an IDX Corporate Action Monitor Hari Ini using Python and the Indonesia Stock Exchange API. The notebook retrieves Today Corporate Actions data and Warrant Calendar data, summarizes corporate action categories, displays dividend, public expose, RUPS, and warrant calendar tables, and generates simple insights for beginner investors.

June 24, 20269 min readRafatar
IDX Corporate Action Monitor Hari Ini and Warrant Calendar Dashboard

Building an IDX Corporate Action Monitor and Warrant Calendar Dashboard Using Python

Monitoring corporate action activity is useful for investors who want to understand what is happening in the stock market beyond daily price movement. Corporate actions such as dividends, public expose schedules, RUPS, stock splits, right issues, tender offers, and warrants can provide important context about listed companies.

In this project, we build an IDX Corporate Action Monitor Hari Ini using Python and the Indonesia Stock Exchange API. The dashboard retrieves today’s corporate action data and Warrant Calendar data, then presents them in a simpler format for beginner investors.

The notebook is divided into five main sections. It starts with library imports, continues with API configuration, helper functions, data retrieval, and ends with a dashboard that summarizes corporate actions and warrant calendar information.

What This Project Builds

This project creates a dashboard that combines:

Today Corporate Actions data

Warrant Calendar data

Corporate action summary table

Dividend list

Public Expose schedule

RUPS schedule

Warrant Calendar table

Beginner investor insights

The goal is to make IDX corporate action data easier to read and understand.

CELL 1 — Install and Import Library

import requests
import pandas as pd
import time
from IPython.display import display, Markdown

pd.set_option("display.max_columns", None)
pd.set_option("display.max_colwidth", 120)
pd.set_option("display.width", 1000)

Explanation

Cell 1 imports the libraries required for this project.

The requests library is used to retrieve data from the IDX API. The pandas library is used to process data into tables. The time library is used to create a delay between API requests, while display and Markdown are used to show dashboard text and tables neatly in Google Colab.

The pandas display settings are also configured so the dashboard can show more columns and longer text values clearly.

CELL 2 — API Configuration

BASE_URL = "https://indonesia-stock-exchange-idx.p.rapidapi.com"

HEADERS = {
    "Content-Type": "application/json",
    "x-rapidapi-host": "indonesia-stock-exchange-idx.p.rapidapi.com",
    "x-rapidapi-key": "YOUR_API_KEY"
}

Explanation

Cell 2 contains the API configuration.

BASE_URL stores the main API URL from RapidAPI. The HEADERS variable contains the request headers needed to access the Indonesia Stock Exchange API.

This configuration is used later when the notebook requests Today Corporate Actions data and Warrant Calendar data.

CELL 3 — Helper Function

def fetch_api(endpoint, retries=3, delay=5):
    url = BASE_URL + endpoint

    for attempt in range(retries):
        try:
            response = requests.get(url, headers=HEADERS, timeout=30)

            if response.status_code == 200:
                return response.json()

            elif response.status_code == 429:
                print(f"Rate limit terkena. Menunggu {delay} detik...")
                time.sleep(delay)
                delay *= 2

            else:
                print(f"Error {response.status_code}: {response.text}")
                return None

        except Exception as e:
            print(f"Gagal mengambil data: {e}")
            return None

    return None


def safe_get_list(data, key):
    try:
        value = data.get("data", {}).get(key, [])
        return value if isinstance(value, list) else []
    except:
        return []


def make_simple_table(data_list, selected_columns=None, rename_columns=None):
    if not data_list:
        return pd.DataFrame()

    df = pd.json_normalize(data_list)

    if selected_columns:
        available_cols = [col for col in selected_columns if col in df.columns]
        df = df[available_cols]

    if rename_columns:
        df = df.rename(columns=rename_columns)

    return df

Explanation

Cell 3 creates helper functions used throughout the notebook.

The fetch_api() function is used to request data from the IDX API. It includes retry handling and rate limit handling. If the API returns status code 429, the notebook waits before trying again.

The safe_get_list() function helps retrieve list data safely from nested API responses.

The make_simple_table() function converts list data into a pandas dataframe, selects available columns, and renames columns when needed. This makes the dashboard output easier to read.

CELL 4 — Fetch Data from IDX API

display(Markdown("## 📥 Fetching Data from IDX API"))

today_corporate_actions_raw = fetch_api("/api/calendar/today")

time.sleep(5)

warrant_calendar_raw = fetch_api("/api/calendar/warrant")

display(Markdown("✅ Data retrieval completed"))

Explanation

Cell 4 retrieves the required data from the IDX API.

The first request retrieves Today Corporate Actions data from the /api/calendar/today endpoint. After that, the notebook waits for five seconds using time.sleep(5) to reduce the risk of hitting the API rate limit.

The second request retrieves Warrant Calendar data from the /api/calendar/warrant endpoint.

After both requests are completed, the notebook displays a message confirming that data retrieval has finished.

CELL 5 — IDX Corporate Actions and Warrant Dashboard

display(Markdown("# 📊 IDX Corporate Action Monitor Hari Ini"))
display(Markdown("Dashboard ini dibuat untuk membaca aktivitas korporasi dari Bursa Efek Indonesia dengan tampilan yang lebih mudah dipahami investor pemula."))

# =========================
# Ambil Tanggal Data
# =========================
tanggal_data = "-"

if isinstance(today_corporate_actions_raw, dict):
    tanggal_data = today_corporate_actions_raw.get("data", {}).get("today", "-")

display(Markdown(f"📅 **Tanggal Data:** {tanggal_data}"))


# =========================
# Ambil Data Corporate Action
# =========================
bonus = safe_get_list(today_corporate_actions_raw, "bonus")
dividend = safe_get_list(today_corporate_actions_raw, "dividend")
economic = safe_get_list(today_corporate_actions_raw, "economic")
ipo = safe_get_list(today_corporate_actions_raw, "ipo")
pubex = safe_get_list(today_corporate_actions_raw, "pubex")
rightissue = safe_get_list(today_corporate_actions_raw, "rightissue")
rups = safe_get_list(today_corporate_actions_raw, "rups")
stock_reverse = safe_get_list(today_corporate_actions_raw, "stock_reverse")
stocksplit = safe_get_list(today_corporate_actions_raw, "stocksplit")
tender = safe_get_list(today_corporate_actions_raw, "tender")
warrant_today = safe_get_list(today_corporate_actions_raw, "warrant")
stock_dividend = safe_get_list(today_corporate_actions_raw, "stock_dividend")


# =========================
# Ringkasan Corporate Action
# =========================
display(Markdown("## 🔔 Ringkasan Corporate Action Hari Ini"))

summary_data = [
    ["💰 Dividen Tunai", len(dividend), "Pembagian keuntungan perusahaan kepada pemegang saham."],
    ["🎁 Dividen Saham", len(stock_dividend), "Dividen yang diberikan dalam bentuk saham."],
    ["🎉 Bonus Share", len(bonus), "Saham bonus yang diberikan kepada pemegang saham."],
    ["📈 IPO", len(ipo), "Perusahaan baru yang masuk ke Bursa Efek Indonesia."],
    ["🏢 Public Expose", len(pubex), "Penyampaian informasi perusahaan kepada publik."],
    ["👥 RUPS", len(rups), "Rapat umum pemegang saham untuk keputusan penting perusahaan."],
    ["🔀 Stock Split", len(stocksplit), "Pemecahan nilai saham agar harga lebih terjangkau."],
    ["🔁 Stock Reverse", len(stock_reverse), "Penggabungan nilai saham."],
    ["💳 Right Issue", len(rightissue), "Penerbitan saham baru kepada pemegang saham lama."],
    ["🤝 Tender Offer", len(tender), "Penawaran pembelian saham oleh pihak tertentu."],
    ["🎫 Waran Hari Ini", len(warrant_today), "Hak untuk membeli saham pada harga tertentu."],
    ["🗓️ Agenda Ekonomi", len(economic), "Agenda ekonomi yang dapat memengaruhi pasar."]
]

df_summary = pd.DataFrame(summary_data, columns=["Jenis Aktivitas", "Jumlah", "Penjelasan Singkat"])
display(df_summary)

total_activity = sum([row[1] for row in summary_data])

if total_activity > 0:
    display(Markdown(f"✅ Hari ini terdapat **{total_activity} aktivitas** yang perlu diperhatikan investor."))
else:
    display(Markdown("Tidak ada aktivitas corporate action yang tersedia hari ini."))


# =========================
# Dividen
# =========================
display(Markdown("## 💰 Daftar Emiten Dividen"))

df_dividend = make_simple_table(
    dividend,
    selected_columns=[
        "company_symbol", "dividend_cash_value", "dividend_cum_date",
        "dividend_ex_date", "dividend_recording_date", "dividend_payment_date"
    ],
    rename_columns={
        "company_symbol": "Kode Saham",
        "dividend_cash_value": "Nilai Dividen",
        "dividend_cum_date": "Cum Date",
        "dividend_ex_date": "Ex Date",
        "dividend_recording_date": "Recording Date",
        "dividend_payment_date": "Payment Date"
    }
)

if not df_dividend.empty:
    display(df_dividend)
else:
    display(Markdown("Tidak ada data dividen hari ini."))


# =========================
# Public Expose
# =========================
display(Markdown("## 🏢 Jadwal Public Expose"))

df_pubex = make_simple_table(
    pubex,
    selected_columns=["company_symbol", "puexp_date", "puexp_time", "puexp_place"],
    rename_columns={
        "company_symbol": "Kode Saham",
        "puexp_date": "Tanggal",
        "puexp_time": "Waktu",
        "puexp_place": "Tempat"
    }
)

if not df_pubex.empty:
    display(df_pubex)
else:
    display(Markdown("Tidak ada jadwal Public Expose hari ini."))


# =========================
# RUPS
# =========================
display(Markdown("## 👥 Jadwal RUPS"))

df_rups = make_simple_table(
    rups,
    selected_columns=["company_symbol", "rups_date", "rups_time", "rups_place"],
    rename_columns={
        "company_symbol": "Kode Saham",
        "rups_date": "Tanggal",
        "rups_time": "Waktu",
        "rups_place": "Tempat"
    }
)

if not df_rups.empty:
    display(df_rups)
else:
    display(Markdown("Tidak ada jadwal RUPS hari ini."))


# =========================
# Warrant Calendar
# =========================
display(Markdown("## 🎫 Warrant Calendar"))

warrant_calendar = []

if isinstance(warrant_calendar_raw, dict):
    warrant_calendar = warrant_calendar_raw.get("data", {}).get("warrant", [])

df_warrant = make_simple_table(
    warrant_calendar,
    selected_columns=[
        "company_symbol", "wrant_code", "wrant_exc_start",
        "wrant_exc_end", "wrant_last_trading_date",
        "wrant_price"
    ],
    rename_columns={
        "company_symbol": "Kode Saham",
        "wrant_code": "Kode Waran",
        "wrant_exc_start": "Mulai Exercise",
        "wrant_exc_end": "Akhir Exercise",
        "wrant_last_trading_date": "Tanggal Terakhir Perdagangan",
        "wrant_price": "Harga Exercise"
    }
)

if not df_warrant.empty:
    display(Markdown(f"Jumlah data Warrant Calendar yang berhasil ditampilkan: **{len(df_warrant)} data**"))
    display(df_warrant.head(20))
else:
    display(Markdown("Tidak ada data Warrant Calendar."))


# =========================
# Insight Investor
# =========================
display(Markdown("## 📌 Insight Investor Pemula"))

insight = []

if len(dividend) > 0:
    insight.append("💰 Ada emiten yang membagikan dividen. Investor bisa memperhatikan cum date dan ex date.")
if len(pubex) > 0:
    insight.append("🏢 Ada Public Expose. Ini penting untuk melihat penjelasan perusahaan kepada publik.")
if len(rups) > 0:
    insight.append("👥 Ada RUPS. Biasanya berkaitan dengan keputusan penting perusahaan.")
if len(warrant_calendar) > 0:
    insight.append("🎫 Ada data waran. Waran memiliki risiko lebih tinggi dibanding saham biasa.")
if len(ipo) == 0:
    insight.append("📈 Tidak ada IPO pada data hari ini.")
if len(stocksplit) == 0:
    insight.append("🔀 Tidak ada Stock Split pada data hari ini.")

if insight:
    for item in insight:
        display(Markdown(f"- {item}"))
else:
    display(Markdown("Belum ada insight khusus dari data hari ini."))

display(Markdown("✅ Dashboard berhasil dibuat dengan tampilan yang lebih mudah dipahami."))

Explanation

Cell 5 builds the final IDX Corporate Action Monitor Hari Ini dashboard.

The dashboard begins by displaying the main title and a short description explaining that the dashboard is designed to read corporate action activity from the Indonesia Stock Exchange in a format that is easier for beginner investors to understand.

The dashboard first retrieves the data date from the Today Corporate Actions response. After that, it extracts several types of corporate action data, including bonus, dividend, economic agenda, IPO, public expose, right issue, RUPS, stock reverse, stock split, tender offer, warrant, and stock dividend.

The first main output is Ringkasan Corporate Action Hari Ini. This section creates a summary table that shows the type of activity, the number of records, and a short explanation for each corporate action category.

Next, the dashboard displays dividend data if available. It selects important dividend-related columns such as stock code, dividend value, cum date, ex date, recording date, and payment date.

The dashboard then displays Public Expose schedules and RUPS schedules if available. Each section converts the data into a simple table with renamed columns so the output becomes easier to read.

After that, the dashboard processes the Warrant Calendar data. It selects important warrant-related columns such as stock code, warrant code, exercise start date, exercise end date, last trading date, and exercise price.

The final section is Insight Investor Pemula. This section creates simple investor-friendly insights based on the available data. For example, if dividend data exists, the dashboard reminds users to pay attention to cum date and ex date. If warrant data exists, it reminds users that warrants carry higher risk than ordinary shares.

At the end, the notebook displays a confirmation message indicating that the dashboard has been successfully created in a more understandable format.
Result:

result

Dashboard Output

The dashboard output is divided into several sections.

The first section displays the data date, which helps users know the date of the corporate action information being reviewed.

The second section displays a corporate action summary table. This table summarizes different activities such as cash dividends, stock dividends, bonus shares, IPO, public expose, RUPS, stock split, stock reverse, right issue, tender offer, warrants, and economic agenda.

The dashboard then displays detailed sections for dividends, public expose, RUPS, and warrant calendar data. Each table is created using selected columns and renamed labels so the output becomes easier to understand.

The final output is an investor insight section designed for beginner investors. This section provides simple notes based on the available data.

Overall Workflow

  1. Import the required libraries.

  2. Configure API access.

  3. Create helper functions for API retrieval and table formatting.

  4. Retrieve Today Corporate Actions data.

  5. Retrieve Warrant Calendar data.

  6. Extract different corporate action categories.

  7. Build a corporate action summary table.

  8. Display dividend data.

  9. Display Public Expose data.

  10. Display RUPS data.

  11. Display Warrant Calendar data.

  12. Generate beginner investor insights.

  13. Display the final dashboard confirmation.

Why This Project Matters

Corporate action data is important because it can provide useful information about company events that may affect investors.

Dividends show company profit distribution. Public Expose gives investors access to company information. RUPS may involve important shareholder decisions. Warrant Calendar data helps investors understand warrant-related schedules and risks.

By combining Today Corporate Actions data and Warrant Calendar data into one dashboard, users can monitor multiple types of market activity through a single workflow.

Conclusion

This project demonstrates how Python can be used to build an IDX Corporate Action Monitor Hari Ini dashboard.

The notebook retrieves Today Corporate Actions data and Warrant Calendar data from the Indonesia Stock Exchange API, processes the responses into structured tables, and displays investor-friendly insights in Google Colab.

The final dashboard helps beginner investors understand corporate action activity more easily.