Stock market analysis requires more than simply monitoring price movements. Investors can also examine insider transactions and relationships between stocks to obtain additional market intelligence.
This project develops a Stock Market Intelligence Dashboard Using Python that combines three analytical components:
Insider screening.
Insider net position analysis.
Stock correlation matrix.
The system uses the Indonesia Stock Exchange IDX API through RapidAPI to retrieve insider transaction data and stock correlation information. The collected data is then processed using Python, Pandas, and NumPy before being presented in structured DataFrames.
The project provides a practical workflow for transforming API responses into a readable market analysis dashboard.
Project Overview
The project integrates three IDX API analysis endpoints:
1. getInsiderScreening()
The first endpoint retrieves insider transaction activity for selected stocks.
The example configuration analyses:
BBCA.
BUMI.
ADRO.
The function can filter information based on:
Stock symbols.
Action type.
Page.
Limit.
Source type.
Analysis period.
The default period used in the project is 2025-12.
The returned data can contain summary statistics, top symbols, top insiders, and alerts.
2. getInsiderNetSummary()
The second endpoint calculates the net insider position for selected stocks.
The example uses:
BBCA.
BUMI.
ADRO.
The analysis period is configured from:
2025-11-01
to:
2025-12-31
The resulting data is used to identify:
Total net value.
Total net shares.
Dominant action.
Net position for individual symbols.
3. getCorrelationMatrix()
The third endpoint calculates the correlation between selected stocks.
The example configuration uses:
BBCA.
BBRI.
BMRI.
TLKM.
The correlation period is set to 30 days.
The response can contain:
Analysis date.
Analysis period.
Stock symbols.
Correlation matrix.
Pair correlation.
Correlation insights.
This provides an additional perspective for understanding how stocks move relative to one another.
Cell 1 — Setup & API Configuration
import requests
import pandas as pd
import numpy as np
# ============================================================
# CONFIGURATION
# ============================================================
RAPIDAPI_KEY = "YOUR_API_KEY"
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": RAPIDAPI_KEY,
}
The first cell prepares the Python environment.
The project uses:
Requests for API communication.
Pandas for DataFrame processing.
NumPy for numerical operations.
The API configuration defines the RapidAPI key, base URL, and HTTP headers required to communicate with the IDX API.
For security, the API key should ideally be stored using an environment variable or secret manager rather than directly inside the notebook.
Generic API Client
# ============================================================
# GENERIC API CLIENT
# ============================================================
def api_get(endpoint, params=None):
response = requests.get(
f"{BASE_URL}{endpoint}",
headers=HEADERS,
params=params,
timeout=30
)
# Tampilkan error API dengan jelas
if not response.ok:
print("Status:", response.status_code)
print("Response:", response.text)
response.raise_for_status()
return response.json()
Instead of creating a separate HTTP request implementation for every endpoint, the project introduces a generic api_get() function.
This function receives:
endpointparams
It then constructs the API URL, sends the GET request, checks the HTTP response, and returns the JSON result.
The function also includes error handling through response.raise_for_status().
This approach makes the subsequent API functions simpler and more consistent.
Cell 2 — Insider Screening
def getInsiderScreening(
symbols="BBCA,BUMI,ADRO",
action_type="ACTION_TYPE_UNSPECIFIED",
page=1,
limit=100,
source_type="SOURCE_TYPE_UNSPECIFIED",
period="2025-12"
):
return api_get(
"/api/analysis/insider-screening",
params={
"symbols": symbols,
"action_type": action_type,
"page": page,
"limit": limit,
"source_type": source_type,
"period": period,
}
)
# Example
insider_screening = getInsiderScreening()
insider_screening
The getInsiderScreening() function connects to the insider screening endpoint.
The default symbols are:
BBCA,BUMI,ADRO
The function also supports several parameters that control the screening request.
The returned response is stored in:
insider_screening
This response later becomes the primary data source for the insider screening dashboard.
Cell 3 — Insider Net Summary
def getInsiderNetSummary(
symbols="BBCA,BUMI,ADRO",
date_start="2025-11-01",
date_end="2025-12-31"
):
return api_get(
f"/api/analysis/insider-net/{symbols}",
params={
"date_start": date_start,
"date_end": date_end,
}
)
# Example
insider_net = getInsiderNetSummary()
insider_net
The getInsiderNetSummary() function retrieves net insider activity for selected stocks.
Unlike the insider screening function, this endpoint uses a specific start and end date.
The example analyses insider activity between:
1 November 2025.
31 December 2025.
The response is stored in insider_net.
This data is later transformed into a summary containing total net value, total net shares, dominant action, and symbol-level positions.
Cell 4 — Correlation Matrix
def getCorrelationMatrix(
symbols="BBCA,BBRI,BMRI,TLKM",
period_days=30
):
return api_get(
"/api/analysis/correlation",
params={
"symbols": symbols,
"period_days": period_days,
}
)
# Example
correlation = getCorrelationMatrix()
correlation
The getCorrelationMatrix() function retrieves stock correlation data.
The example compares four stocks:
BBCA.
BBRI.
BMRI.
TLKM.
The analysis uses a 30-day period.
Correlation analysis can help identify stocks that tend to move together or stocks whose movements are relatively different within the selected period.
Cell 5 — Dashboard & DataFrame Output
The fifth cell transforms the API responses into a structured dashboard.
The dashboard is divided into three major sections:
Insider Screening.
Insider Net Summary.
Correlation Matrix.
Helper Functions
def get_data(response):
"""Ambil object data dari response API."""
if not isinstance(response, dict):
return response
return response.get("data", response)
The get_data() function extracts the main data object from an API response.
This makes the following processing more flexible when the API wraps its primary response inside a data field.
Number Formatting
def format_number(value):
if value is None:
return "-"
try:
return f"{float(value):,.0f}".replace(",", ".")
except (ValueError, TypeError):
return str(value)
The format_number() function converts numerical values into a more readable format.
For example, large numbers can be displayed using thousands separators instead of raw numerical representations.
Money Formatting
def format_money(value):
if value is None:
return "-"
try:
return f"Rp {float(value):,.0f}".replace(",", ".")
except (ValueError, TypeError):
return str(value)
The format_money() helper formats monetary values into Indonesian Rupiah notation.
This is particularly useful for displaying:
Buy Value.
Sell Value.
Net Value.
Total Net Value.
Extracting Stock Symbols
def extract_symbol_names(symbols):
"""
Mengambil nama/symbol dari berbagai bentuk response API.
"""
if not symbols:
return []
if isinstance(symbols, str):
return [symbols]
result = []
for item in symbols:
if isinstance(item, str):
result.append(item)
elif isinstance(item, dict):
symbol = (
item.get("symbol")
or item.get("code")
or item.get("ticker")
or item.get("name")
)
if symbol:
result.append(str(symbol))
return result
The API may return stock symbols in different structures.
The extract_symbol_names() function is designed to handle:
A simple string.
A list of strings.
A list of dictionaries.
This makes the dashboard more robust when processing different API response formats.
Cleaning DataFrames
def clean_dataframe(data, preferred_columns=None):
"""Merapikan DataFrame berdasarkan kolom yang tersedia."""
if not isinstance(data, list) or not data:
return pd.DataFrame()
df = pd.json_normalize(data)
if preferred_columns:
columns = [
col for col in preferred_columns
if col in df.columns
]
if columns:
df = df[columns]
return df
The clean_dataframe() function converts lists of API objects into Pandas DataFrames.
It uses pd.json_normalize() to process potentially nested JSON structures.
The function can also select preferred columns when those columns exist in the API response.
1. Insider Screening Dashboard
screen = get_data(insider_screening)
summary = screen.get("summary", {})
top_symbols = screen.get("topSymbols", [])
top_insiders = screen.get("topInsiders", [])
alerts = screen.get("alerts", [])
The first dashboard section extracts four important components:
summarytopSymbolstopInsidersalerts
These components are then displayed separately to make the insider analysis easier to interpret.
Insider Screening Summary
summary_df = pd.DataFrame([{
"Periode":
f"{summary.get('periodStart', '-')} → "
f"{summary.get('periodEnd', '-')}",
"Movements":
summary.get("totalMovements", 0),
"Buy":
summary.get("totalBuyMovements", 0),
"Sell":
summary.get("totalSellMovements", 0),
"Saham":
summary.get("uniqueSymbols", 0),
"Insider":
summary.get("uniqueInsiders", 0),
"Buy Value":
format_money(summary.get("totalBuyValue")),
"Sell Value":
format_money(summary.get("totalSellValue")),
"Net Value":
format_money(summary.get("netValue")),
}])
The summary table provides a high-level overview of insider activity.
The dashboard can show:
Analysis period.
Total movements.
Buy movements.
Sell movements.
Number of unique stocks.
Number of unique insiders.
Total buy value.
Total sell value.
Net value.
This gives the user a quick snapshot before examining individual symbols or insiders.
Top Symbols
The dashboard also extracts the stocks with the highest insider activity.
df_symbols = clean_dataframe(
top_symbols,
[
"symbol",
"totalBuyShares",
"totalSellShares",
"totalBuyValue",
"totalSellValue",
"netValue",
"movementCount",
]
)
The selected fields include:
Symbol.
Total buy shares.
Total sell shares.
Total buy value.
Total sell value.
Net value.
Movement count.
This allows the dashboard to compare insider activity between different stocks.
Top Insiders
The next section focuses on individual insiders.
df_insiders = clean_dataframe(
top_insiders,
[
"id",
"name",
"symbol",
"totalBuyShares",
"totalSellShares",
"totalBuyValue",
"totalSellValue",
"netValue",
]
)
The dashboard can display each insider together with their related stock and transaction totals.
This creates a more detailed view than simply looking at aggregate insider movements.
Insider Alerts
The system also displays alerts when they are provided by the API.
if alerts:
df_alerts = clean_dataframe(alerts)
display(df_alerts)
The alert section is useful for highlighting potentially important insider activity detected by the API.
Because the actual alert content depends on the API response, the notebook does not hard-code a particular alert interpretation.
2. Insider Net Summary
The second major dashboard component retrieves the net insider position.
net_data = get_data(insider_net)
display(Markdown("# 💰 Insider Net Summary"))
The dashboard extracts the symbols associated with the response and creates a summary table.
symbols_raw = net_data.get("symbols", [])
symbol_names = extract_symbol_names(symbols_raw)
symbol_text = ", ".join(symbol_names)
The symbol extraction function allows the dashboard to handle different API response structures.
Main Net Summary
net_summary_df = pd.DataFrame([{
"Symbols":
symbol_text or "-",
"Total Net Value":
format_money(
net_data.get("totalNetValue")
),
"Total Net Shares":
format_number(
net_data.get("totalNetShares")
),
"Dominant Action":
net_data.get(
"dominantAction",
"-"
),
}])
The main summary contains four important fields:
Symbols.
Total Net Value.
Total Net Shares.
Dominant Action.
This provides a compact view of the overall insider net position for the selected stocks and period.
Net Position per Symbol
If the API returns detailed symbol objects, the dashboard also creates a symbol-level table.
df_net = clean_dataframe(
symbols_raw,
[
"symbol",
"totalBuyShares",
"totalSellShares",
"totalNetShares",
"totalBuyValue",
"totalSellValue",
"totalNetValue",
"dominantAction",
]
)
The resulting table provides a more granular analysis of insider positioning.
It separates:
Buy shares.
Sell shares.
Net shares.
Buy value.
Sell value.
Net value.
Dominant action.
This makes it easier to compare insider activity across the selected stocks.
3. Correlation Matrix
The final dashboard component analyses stock correlation.
corr_data = get_data(correlation)
display(Markdown("# 📈 Correlation Matrix"))
The code extracts the analysis date, analysis period, stock symbols, and correlation matrix from the API response.
analysis_date = (
corr_data.get("analysis_date")
or corr_data.get("analysisDate")
)
period_days = corr_data.get("period_days")
symbols = corr_data.get("symbols", [])
corr_symbols = extract_symbol_names(symbols)
matrix = corr_data.get("matrix", [])
This approach also accounts for variations in API field naming, such as analysis_date and analysisDate.
Correlation Information
corr_info = pd.DataFrame([{
"Analysis Date":
analysis_date or "-",
"Period":
f"{period_days} hari"
if period_days
else "-",
"Jumlah Saham":
len(corr_symbols),
"Symbols":
", ".join(corr_symbols) or "-",
}])
The correlation information table summarizes:
Analysis date.
Analysis period.
Number of stocks.
Stocks included in the analysis.
Correlation Matrix Table
When the API provides both a matrix and valid stock symbols, the matrix is converted into a Pandas DataFrame.
corr_df = pd.DataFrame(
matrix,
index=corr_symbols,
columns=corr_symbols
)
display(
corr_df.round(3)
)
The stock symbols are used as both the index and columns.
This creates a conventional correlation matrix that can be inspected directly inside the notebook.
The values are rounded to three decimal places to improve readability.
Pair Correlation
The dashboard also supports pair-level correlation information.
pairs = corr_data.get("pairs", [])
if pairs:
df_pairs = clean_dataframe(pairs)
display(df_pairs)
The pair correlation section provides another way of analysing the relationship between individual stocks.
Instead of viewing the entire matrix, users can focus on specific stock pairs returned by the API.
Correlation Insights
The API may also return structured insights.
insights = corr_data.get("insights", {})
if insights:
for key, value in insights.items():
title = key.replace(
"_", " "
).title()
display(
Markdown(
f"**{title}**"
)
)
The dashboard dynamically displays each insight returned by the API.
If the value is a list, the code converts it into a DataFrame where possible. Otherwise, the value is printed directly.
This approach prevents the dashboard from being tied to a fixed set of insight fields.
Results and Discussion
The project demonstrates how Python can be used to combine different market intelligence datasets into a single analysis workflow.
The dashboard provides three complementary perspectives.
Insider Screening
Insider screening provides an overview of insider movements, including buy and sell activity, top symbols, top insiders, and alerts.
Insider Net Summary
Insider net analysis focuses on the overall balance between insider buying and selling.
It can be used to examine total net shares, total net value, dominant action, and individual symbol positions.
Correlation Matrix
Correlation analysis provides a market relationship perspective by comparing the movements of selected stocks.
Together, these three components create a broader stock analysis framework than using a single dataset.
The project also demonstrates several useful Python data-processing techniques:
API abstraction using a generic client.
JSON response extraction.
JSON normalization.
Dynamic DataFrame generation.
Number and currency formatting.
Flexible symbol extraction.
Dynamic dashboard rendering.
Data Handling and Error Management
One important aspect of the project is its API error handling.
The generic api_get() function checks whether the HTTP response is successful.
if not response.ok:
print("Status:", response.status_code)
print("Response:", response.text)
response.raise_for_status()
This allows API errors to be displayed clearly instead of silently producing invalid data.
The dashboard also includes defensive handling for missing values.
For example:
value if value is not None else "-"
and empty DataFrame handling prevent missing API fields from immediately breaking the dashboard.
Conclusion
The Insider Screening, Insider Net Summary & Stock Correlation Matrix Using Python project demonstrates how IDX API data can be transformed into a structured stock market intelligence dashboard.
The system integrates:
Insider screening.
Insider net position analysis.
Stock correlation analysis.
Pandas DataFrame processing.
Dynamic API response handling.
Structured dashboard output.
By combining insider activity with stock correlation information, the workflow provides multiple analytical perspectives within a single Python environment.
The project can be further developed into a more comprehensive stock intelligence platform by adding historical tracking, automated reporting, visualization, scheduled data collection, portfolio correlation analysis, and additional market indicators.
However, the resulting dashboard should be considered an analytical support tool rather than a standalone investment decision system. The data should be evaluated together with company fundamentals, valuation, financial performance, market conditions, and other relevant investment factors.
Project Structure Summary
Component | Function | Purpose |
|---|---|---|
API Client |
| Generic IDX API request |
Insider Screening |
| Analyse insider transactions |
Insider Net |
| Analyse net insider position |
Correlation |
| Analyse stock relationships |
Data Processing |
| Convert API data into DataFrames |
Symbol Parser |
| Extract stock symbols |
Dashboard | Cell 5 | Present structured analysis |
The final output provides a foundation for building an automated IDX Stock Intelligence Dashboard using Python.
